Question

I want to set an "As Of" value on a record reflecting the latest business hour available.

For example, let's say we define business hours as M-F, 9AM to 5PM. If I invoke this on a Thursday at 4:00PM, the "As Of" should be Thursday at 4:00PM; however, if I invoke this at 1:30AM Monday morning, the "As Of" should be 5:00PM on the previous Friday.

I can bull through this with a bunch of logic, but it just seems like this would be a "feature" of some class where the work is pretty much already done, or there is a simple way to do it.

Is there? Or am I stuck writing some odious algorithm?

Was it helpful?

Solution

C# does not include anything for this out of the box, but you could try something like this:

public DateTime? GetLatestOpen(DateTime current) 
{
    var openHours = ...collection of pairs of  int (Day) and two date times (TimeRange[])...
    if (!openHours.Any()) { return null; } //prevent inf. loop if no open hours ever

    var currentDay = current.DayOfWeek;
    var hoursToday = openHours.FirstOrDefault(oh => oh.DayOfWeek == currentDay);

    if (hoursToday != null)
    {
        var currentTime = current.TimeOfDay();
        if (currentTime >= hoursToday.TimeRange[0] && 
            currentTime <= hoursToday.TimeRange[1]) 
        {
            return currentTime;
        } 
        else 
        {
            return hoursToday.TimeRange[1];
        } 
    }

    return GetLatestOpen(current.AddDays(-1));
}


...

var latestOpen = GetLatestOpen(DateTime.Now);

...

Your openHours collection would look something like the following (I used an anonymous type for simplicity of the example):

var openHours = new [] { new { Day = 1, TimeRange = new DateTime[] { ...Open..., ...Close...} }, new { Day = 2...... } };


Notes:

A couple things to note about the above:

  1. Day = 0 is Sunday, Day = 1 is Monday .... Day = 6 is Saturday
  2. You can use another type of collection for the TimeRange, if you want
  3. For the ...Open... and ...Close... DateTime objects, you need not worry about the actual Date; you only carry about the Time portion


Let me know if you have any questions on this. I hope this helps! Good luck, and happy coding! :)

OTHER TIPS

You can use the CalendarPeriodCollector of the Time Period Library for .NET:

// ----------------------------------------------------------------------
public DateTime GetLatestBusinessHour( DateTime moment )
{
  // filter the business hours: - Monday to Friday, 9AM to 5PM
  CalendarPeriodCollectorFilter filter = new CalendarPeriodCollectorFilter();
  filter.AddWorkingWeekDays();
  filter.CollectingHours.Add( new HourRange( 9, 17 ) );

  // collect business hours of the past week
  CalendarPeriodCollector collector = new CalendarPeriodCollector( filter,
    new TimeRange( moment.AddDays( -7 ), moment ), SeekDirection.Forward,
    new TimeCalendar( new TimeCalendarConfig { EndOffset = TimeSpan.Zero } ) );
  collector.CollectHours();

  // end of the last period
  return collector.Periods.End;
} // GetLatestBusinessHour
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top