Функция для определения первого дня месяца, последнего дня месяца и т. Д.

Я создаю планировщик, и мне нужно уметь делать на C # следующее:

  1. Найдите 1-й вторник июня 2012 г.
  2. Найдите последнюю пятницу марта 2008 г.
  3. Найти каждую субботу в январе 2013 г.
  4. Найдите третью пятницу июля 2009 г.
  5. Найти каждую субботу в течение следующих 3 месяцев
  6. Найти каждый день марта 2018 года

Результат должен быть DateTime или List<DateTime>.


person Keith Adler    schedule 01.10.2009    source источник
comment
Как выглядят входы? эти струны?   -  person Joel Coehoorn    schedule 02.10.2009
comment
Зачем заново внедрять колесо? Выбирайте хороший планировщик. Если только вы не пытаетесь сделать это ради себя.   -  person Aaron M    schedule 02.10.2009
comment
Для этого мне удалось написать около 7 функций в LINQ. Конечный результат отличный и очень гибкий. Однако я надеялся повторно использовать другой код, но несколько модульных тестов и мощность LINQ, и я готов к гонкам. Всем спасибо.   -  person Keith Adler    schedule 02.10.2009


Ответы (6)


Вот методы, чтобы найти первый / последний указанный день недели в заданном месяце:

public DateTime GetFirstDayOfWeekInMonth(int year, int month, DayOfWeek dayOfWeek)
{
    DateTime dt = new DateTime(year, month, 1);
    int first = (int)dt.DayOfWeek;
    int wanted = (int)dayOfWeek;
    if (wanted < first)
        wanted += 7;
    return dt.AddDays(wanted - first);
}

public DateTime GetLastDayOfWeekInMonth(int year, int month, DayOfWeek dayOfWeek)
{
    int daysInMonth = CultureInfo.CurrentCulture.Calendar.GetDaysInMonth(year, month);
    DateTime dt = new DateTime(year, month, daysInMonth);
    int last = (int)dt.DayOfWeek;
    int wanted = (int)dayOfWeek;
    if (wanted > last)
        last += 7;
    return dt.AddDays(wanted - last);
}

Из них вы можете легко найти ответы на другие вопросы ... просто добавьте 7 дней, чтобы найти следующее совпадение дня, который вы ищете.


РЕДАКТИРОВАТЬ: подумав об этом подробнее, было бы очень удобно иметь это в виде методов расширения, таких как:

Console.WriteLine("Next monday : {0}", DateTime.Today.Next(DayOfWeek.Monday));
Console.WriteLine("Last saturday : {0}", DateTime.Today.Previous(DayOfWeek.Saturday));

Вот реализация:

public static class DateExtensions
{
    public static DateTime Next(this DateTime from, DayOfWeek dayOfWeek)
    {
        int start = (int)from.DayOfWeek;
        int wanted = (int)dayOfWeek;
        if (wanted < start)
            wanted += 7;
        return from.AddDays(wanted - start);
    }

    public static DateTime Previous(this DateTime from, DayOfWeek dayOfWeek)
    {
        int end = (int)from.DayOfWeek;
        int wanted = (int)dayOfWeek;
        if (wanted > end)
            end += 7;
        return from.AddDays(wanted - end);
    }
}

Вероятно, он более гибкий, чем первые методы, которые я предложил ... Благодаря этому вы можете легко делать такие вещи:

// Print all Sundays between 2009/01/01 and 2009/03/31
DateTime from = new DateTime(2009, 1, 1);
DateTime to = new DateTime(2009, 3, 31);
DateTime sunday = from.Next(DayOfWeek.Sunday);
while(sunday <= to)
{
   Console.WriteLine(sunday);
   sunday = sunday.AddDays(7);
}
person Thomas Levesque    schedule 01.10.2009

Вдохновленный этим вопросом, казалось забавным создать что-то, что позволяет обрабатывать даты как последовательности и запрашивать их с помощью LINQ. Я сделал простой проект, который можно загрузить здесь с GitHub. Не знаю, нужно ли было добавить его в систему контроля версий, так как я сомневаюсь, что буду работать над этим, но мне пришлось загрузить его куда-то, и загрузка в RapidShare казалась немного хитрой :)

Ваши первые вопросы решены с помощью моего "Linq-to-DateTime":

  /*
   *    1. Find the 1st Tuesday of June 2012
        2. Find the last Friday of March 2008
        3. Find every Saturday in January 2013
        4. Find the 3rd Friday in July 2009
        5. Find every Saturday over the next 3 months
        6. Find every day in March 2018
  */

  var firstTuesday = (from d in DateSequence.FromYear(2012).June()
                    where d.DayOfWeek == DayOfWeek.Tuesday
                    select d).First();

  var lastFriday = (from d in DateSequence.FromYear(2008).March()
                    where d.DayOfWeek == DayOfWeek.Friday
                    select d).Last();

  var saturdays = (from d in DateSequence.FromYear(2013).January()
                   where d.DayOfWeek == DayOfWeek.Saturday
                   select d);

  var thirdFriday = (from d in DateSequence.FromYear(2009).July()
                     where d.DayOfWeek == DayOfWeek.Friday
                     select d).Skip(2).First();

  var nextSaturdays = (from d in DateSequence.FromDates(DateTime.Today, DateTime.Today.AddMonths(3))
                       where d.DayOfWeek == DayOfWeek.Saturday
                       select d);

  var allDays = (from d in DateSequence.FromYear(2018).March()
                 select d);

В этом примере не показано, что вы можете выбирать степень детализации запросов. Это означает, что если вы сделаете это:

  var days = (from d in DateSequence.FromYears(2001, 2090).AsYears()
              where d.Year % 2 == 0
              select d.Year).ToList();

Вы будете перебирать даты с шагом в год. По умолчанию используется AsDays (), если вы ничего не указываете.

Проект довольно простой, без комментариев или модульных тестов, но я надеюсь, что это все еще может вам помочь. Если нет, то писать было весело :)

person JulianR    schedule 03.10.2009

Вот пример того, как сделать первый день месяца.

public enum Month
{
    January = 1,
    Febuary = 2,
    March = 3,
    April = 4,
    May = 5,
    June = 6,
    July = 7,
    August = 8,
    September = 9,
    October = 10,
    November = 11,
    December = 12
}

public static Nullable<DateTime> FindTheFirstDayOfAMonth(DayOfWeek dayOfWeek, Month month, int year)
{
    // Do checking of parameters here, i.e. year being in future not past

    // Create a DateTime object the first day of that month
    DateTime currentDate = new DateTime(year, (int)month, 1);

    while (currentDate.Month == (int)month)
    {
        if (currentDate.DayOfWeek == dayOfWeek)
        {
            return currentDate;
        }

        currentDate = currentDate.AddDays(1);
    }

    return null;
}

Вы называете это как

Nullable<DateTime> date = Program.FindTheFirstDayOfAMonth(DayOfWeek.Monday, Month.September, 2009);

Итак, вы поняли идею. Вам придется выполнять различные функции, чтобы добиться того, чего вы хотите достичь.

person David Basarab    schedule 01.10.2009

YO YO YO - Вы, ребята, слишком усложняете задачу:

int DaysinMonth = DateTime.DaysInMonth (DateTime.Now.Year, DateTime.Now.Month);

person Trevor    schedule 31.07.2013

Когда я писал планировщик, я в значительной степени скопировал таблицу расписаний SQL-серверов.

http://msdn.microsoft.com/en-us/library/ms178644.aspx

Использование таких вещей, как Тип частоты, Интервал частоты и т. Д., Действительно упростило вычисление значений в коде, но я предполагаю, что есть sproc, который сделает это за вас. Я ищу это сейчас.

person Bob    schedule 01.10.2009

Да, .NET Framework будет поддерживать это без проблем;)

А если серьезно - вы должны уметь писать код, который делает это довольно легко. Если нет, задайте вопрос, когда вы застряли, и мы поможем. Но никаких внешних сборок вам не понадобится - просто используйте стандартный класс C # =)

person Tomas Aschan    schedule 01.10.2009
comment
Почему вы голосуете против этих людей? Вопрос - это домашнее задание, не давайте ОП ответ, помогите ему / ей добраться туда. - person Martin; 03.10.2009
comment
Как этот ответ помогает OP попасть туда? - person bzlm; 03.10.2009
comment
bzlm: ОП явно считает (или привык), что создание кода для этого настолько сложно, что существует какая-то внешняя сборка, которая делает это за него / нее. Поскольку это не так (если у вас нет экстремальных требований к производительности, это можно сделать довольно легко), и OP, похоже, даже не пробовал самостоятельно, и, поскольку он помечен как Homework, просто выдавая некоторый код, который делает работа, похоже, тоже не помогает. - person Tomas Aschan; 04.10.2009