0

I am trying to resolve an issue in regard to an activity status function for a specific condition. The function is trying to check if an signature on the activity falls within a validity period of two dates within a shift.

The activity has a stored start and finish DateTime as follows:

var startDate = activity.Start; // ex. new DateTime(2023, 05, 25, 18, 00, 00, DateTimeKind.Utc)
var finishDate = activity.Finish; // ex. new DateTime(2023, 06, 01, 04, 00, 00, DateTimeKind.Utc)

In this instance, shifts would be between 18:00 - 04:00 each day (i.e. 25/05 18:00 -> 26/05 04:00, 26/05 18:00 -> 27/05 04:00 etc) which are stored against a shift integer based on the working day (this will usually be in the range of 1-7). If the time that the signature is made is within the validity period then it will go to a "Live" status, otherwise it will go to a "Awaiting Start" status.

Currently the logic in place is as follows. This will return Live if now is after midnight within the validity period of a shift but if the signature time is before midnight, then it will return Awaiting Start.

public void SetStatus (T activity)
{
    //....
    if (startTime.Date <= DateTime.UtcNow.Date && finishTime.Date >= DateTime.UtcNow.Date)
    {
        if (finishTime.TimeOfDay < startTime.TimeOfDay)
            activity.Status = SetStatusIfShiftCrossesMidnight(startTime, finishTime);

        // ... other checks
    }
}

private string SetStatusIfShiftCrossesMidnight(DateTime startDate, DateTime finishDate)
{
    var now = DateTime.UtcNow;
    
    var start = new DateTime(now.Year, now.Month, now.Day - 1 , startDate.Hour, startDate.Minute, 
                startDate.Second, DateTimeKind.Utc);

    var finish = new DateTime(now.Year, now.Month, now.Day, finishDate.Hour, finishDate.Minute,
                finishDate.Second, DateTimeKind.Utc);

    if (start <= now && finish > now)
        return "Live"; 

    return "Awaiting Start";
}

Any recommendedations on the best way to tackle this?

jcx200
  • 80
  • 1
  • 10
  • try to take a look on this question. https://stackoverflow.com/questions/46063866/c-sharp-match-shift-that-spans-over-midnight?rq=2 – Aman Tiwari May 26 '23 at 09:24
  • `bool midNightCrossed = startDate.Date < finishDate.Date;`? Since `Date` component increases each midnight – Dmitry Bychenko May 26 '23 at 09:28
  • @DmitryBychenko that isn't quite what I want to check. I know how to check if midnight has been crossed, its more that I basically need to make sure UtcNow is between that start and end of a shift time that crosses midnight. – jcx200 May 26 '23 at 09:45
  • @AmanTiwari Similarly that doesn't really cover my requirements as it doesn't take into account .Now / UtcNow anywhere to check it is within a validity period. – jcx200 May 26 '23 at 09:51

1 Answers1

1

If I understand you right, you have a shift, which is a range

18:00 - 04:00

and you have a time, say

23:00

and you want to check if the time is within the shift. If it's your task then

// Just time, Date part is ignored
private static bool WithinShift((TimeOnly start, TimeOnly end) shift, TimeOnly time) =>
  (shift.end >= shift.start) 
     ? time >= shift.start && time <= shift.end
     : time >= shift.start || time <= shift.end;

// Date component is taken in to account
private static bool WithinShift((DateTime start, DateTime end) shift, DateTime time) =>
  time >= shift.start && time <= shift.end;

E.g.

var shift = (start : new TimeOnly(18, 0, 0), end : new TimeOnly(4, 0, 0));

var tests = new TimeOnly[] {
  new (23, 0, 0),
  new ( 0, 0, 0),
  new ( 3, 0, 0),
  new ( 5, 0, 0),
  new ( 9, 0, 0),
  new (12, 0, 0),
  new (17, 0, 0),
  new (20, 0, 0)
};

var report = string.Join(Environment.NewLine, tests
  .Select(test => $"{test,9} : {(WithinShift(shift, test) ? "Live" : "Awaiting Start")}"));

Console.WriteLine(report);

// Date Component
var now = DateTime.Now;

var currentShift = (
  now.Date + shift.start.ToTimeSpan(),
  now.Date + shift.end.ToTimeSpan());

report =
  $"time: {now:HH:mm} shift {currentShift} is {(WithinShift(currentShift, now) ? "Live" : "Awaiting Start")}";

Console.WriteLine();
Console.WriteLine(report);

Output:

 11:00 PM : Live
 12:00 AM : Live
  3:00 AM : Live
  5:00 AM : Awaiting Start
  9:00 AM : Awaiting Start
 12:00 PM : Awaiting Start
  5:00 PM : Awaiting Start
  8:00 PM : Live

time: 11:03 shift (5/26/2023 6:00:00 PM, 5/26/2023 4:00:00 AM) is Awaiting Start
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • Seems to cover what I need it to. Had to make some minor adaptations due to being on an older version of .NET but managed to sort it. Thanks! – jcx200 May 26 '23 at 10:52