Элегантный способ установить DateTime на последний рабочий час

Я хочу установить значение «По состоянию на» для записи, отражающей последний доступный рабочий час.

Например, предположим, что мы определяем рабочие часы как Пн-Пт, с 9:00 до 17:00. Если я вызову это в четверг в 16:00, "По состоянию на" должно быть в четверг в 16:00; однако, если я вызываю это в 1:30 утра понедельника, «По состоянию на» должно быть 17:00 в предыдущую пятницу.

Я могу пройти через это с кучей логики, но мне кажется, что это будет «особенность» какого-то класса, где работа в значительной степени уже сделана, или есть простой способ сделать это.

Здесь? Или я застрял в написании какого-то одиозного алгоритма?


person Jeremy Holovacs    schedule 26.04.2014    source источник
comment
Я думаю, вы застряли и вам нужно написать свою собственную логику... :)   -  person Leniel Maccaferri    schedule 26.04.2014
comment
О чем ты говоришь? Вам нужен метод, написанный на С# для этого? Если да, то что вы пробовали?   -  person Sriram Sakthivel    schedule 26.04.2014
comment
Я надеюсь, что для этого мне не нужен метод, написанный на C#; Я надеюсь, что для этого уже существует класс или механизм.   -  person Jeremy Holovacs    schedule 26.04.2014
comment
Нет, ничего не существует из коробки.   -  person Sriram Sakthivel    schedule 26.04.2014
comment
В среде .net такого класса нет, поскольку он довольно специфичен. Вам нужно будет создать свой собственный класс с датой и временем.   -  person Fabian Bigler    schedule 26.04.2014
comment
Эх... этого я и боялся. .NET иногда удивлял меня изящными маленькими функциями, так что я надеялся. Ну что ж.   -  person Jeremy Holovacs    schedule 26.04.2014
comment
Ну, гугл тоже может помочь. Есть много бизнес-приложений с вашей конкретной проблемой. Удачи. ;-)   -  person Fabian Bigler    schedule 26.04.2014


Ответы (2)


C# не включает ничего для этого из коробки, но вы можете попробовать что-то вроде этого:

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);

...

Ваша коллекция openHours будет выглядеть примерно так (для простоты примера я использовал анонимный тип):

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


Примечания:

Несколько замечаний по поводу вышеизложенного:

  1. Day = 0 — воскресенье, Day = 1 — понедельник.... Day = 6 — суббота
  2. Вы можете использовать другой тип коллекции для TimeRange, если хотите
  3. Для объектов ...Open... и ...Close... DateTime вам не нужно беспокоиться о фактической дате; вы несете только часть времени


Дайте мне знать, если у вас есть какие-либо вопросы по этому поводу. Надеюсь, это поможет! Удачи и удачного кодирования! :)

person Zachary Kniebel    schedule 26.04.2014
comment
Я закончил тем, что сделал что-то очень похожее на это. - person Jeremy Holovacs; 05.08.2014

Вы можете использовать CalendarPeriodCollector для Time Библиотека периодов для .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
person Community    schedule 26.04.2014