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

StackOverflow https://stackoverflow.com/questions/1506378

  •  19-09-2019
  •  | 
  •  

Вопрос

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

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

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

Это было полезно?

Решение

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

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

Другие советы

Вдохновленный этим вопросом, мне показалось забавным создать что-то, что позволит вам обрабатывать даты как последовательности и запрашивать их с помощью LINQ.Я сделал простой проект, который можно скачать здесь с ГитХаба.Не знаю, нужно ли было добавлять его в систему контроля версий, так как сомневаюсь, что буду над этим работать, но нужно было куда-то загрузить его, а загрузка в 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(), если вы ничего не укажете.

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

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

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

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

ЙО ЙО ЙО - Ребята, вы все усложняете:

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top