Функция определения первого дня месяца, последнего дня месяца и т. Д. - PullRequest
4 голосов
/ 02 октября 2009

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

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

Результаты должны возвращаться как DateTime или List<DateTime>.

Ответы [ 6 ]

4 голосов
/ 02 октября 2009

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

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);
}
2 голосов
/ 03 октября 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 (), если вы ничего не указали.

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

1 голос
/ 31 июля 2013

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

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

1 голос
/ 02 октября 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);

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

0 голосов
/ 02 октября 2009

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

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

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

0 голосов
/ 02 октября 2009

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

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

...