Подтвердить что ты не робот

Как найти третью пятницу в месяц с С#?

С учетом даты (типа DateTime), как найти третью пятницу в месяце этой даты?

4b9b3361

Ответ 1

Я не тестировал это, но поскольку третья пятница не может произойти до 15 числа месяца, создайте новую DateTime, а затем просто увеличивайте ее до пятницы.

DateTime thirdFriday= new DateTime(yourDate.Year, yourDate.Month, 15);

while (thirdFriday.DayOfWeek != DayOfWeek.Friday)
{
   thirdFriday = thirdFriday.AddDays(1);
}

Ответ 2

Я собираюсь повторить свой ответ из здесь с одним небольшим дополнением.

Язык-агностическая версия:

Чтобы получить первый конкретный день месяца, начните с первого дня месяца: yyyy-mm-01. Используйте любую функцию, чтобы дать число, соответствующее дню недели; в С# это будет DateTime.DayOfWeek. Вычтите это число с того дня, которое вы ищете; например, если первый день месяца - среда (3), и вы ищете пятницу (5), вычтите 3 из 5, оставив 2. Если ответ отрицательный, добавьте 7. Наконец добавьте это к первому из месяц; для моего примера, первая пятница будет третьей.

Чтобы попасть в последнюю пятницу месяца, найдите первую пятницу следующего месяца и вычтите 7 дней.

Чтобы получить третью пятницу месяца, добавьте 14 дней до первой пятницы.

Ответ 3

Я следовал за алгоритмом User: Mark Ransom и написал обобщенный дневной поиск. Например, чтобы получить третью пятницу декабря 2013 года,

int thirdFriday = DayFinder.FindDay(2013, 12, DayOfWeek.Friday, 3);

И вот определение функции. Он не имеет итерационных циклов, поэтому его эффективность.

public class DayFinder
        {

            //For example to find the day for 2nd Friday, February, 2016
            //=>call FindDay(2016, 2, DayOfWeek.Friday, 2)
            public static int FindDay(int year, int month, dayOfWeek Day, int occurance)
            {

               if (occurance <= 0 || occurance > 5) 
                throw new Exception("Occurance is invalid");

               DateTime firstDayOfMonth = new DateTime(year, month, 1);
                //Substract first day of the month with the required day of the week 
               var daysneeded = (int)day - (int)firstDayOfMonth.DayOfWeek;
                //if it is less than zero we need to get the next week day (add 7 days)
               if (daysneeded < 0) daysneeded = daysneeded + 7;
                //DayOfWeek is zero index based; multiply by the Occurance to get the day
               var resultedDay =  (daysneeded + 1)+ (7*(occurance-1));

               if(resultedDay > (firstDayOfMonth.AddMonths(1) - firstDayOfMonth).Days) 
                throw new Exception(String.Format("No {0} occurance(s) of {1} in the required month", occurance, day.ToString()));

               return resultedDay; 
            }
        }

Ответ 4

Немного оптимизированная версия:

    DateTime Now = DateTime.Now;

    DateTime TempDate = new DateTime(Now.Year, Now.Month, 1);

    // find first friday
    while (TempDate.DayOfWeek != DayOfWeek.Friday)
        TempDate = TempDate.AddDays(1);

    // add two weeks
    TempDate = TempDate.AddDays(14);

Ответ 5

Наверное, лучше всего отнести это к методу, чтобы сделать комбинацию даты/дня:

(метод расширения)

public static bool TryGetDayOfMonth(this DateTime instance, 
                                 DayOfWeek dayOfWeek, 
                                 int occurance, 
                                 out DateTime dateOfMonth)
{
    if (instance == null)
    {
        throw new ArgumentNullException("instance");
    }

    if (occurance <= 0 || occurance > 5)
    {
        throw new ArgumentOutOfRangeException("occurance", "Occurance must be greater than zero and less than 6.");
    }

    bool result;
    dateOfMonth = new DateTime();

    // Change to first day of the month
    DateTime dayOfMonth = instance.AddDays(1 - instance.Day);

    // Find first dayOfWeek of this month;
    if (dayOfMonth.DayOfWeek > dayOfWeek)
    {
        dayOfMonth = dayOfMonth.AddDays(7 - (int)dayOfMonth.DayOfWeek + (int)dayOfWeek);
    }
    else
    {
        dayOfMonth = dayOfMonth.AddDays((int)dayOfWeek - (int)dayOfMonth.DayOfWeek);
    }

    // add 7 days per occurance
    dayOfMonth = dayOfMonth.AddDays(7 * (occurance - 1));

    // make sure this occurance is within the original month
    result = dayOfMonth.Month == instance.Month;


    if (result)
    {
        dateOfMonth = dayOfMonth;
    }

    return result;
}

Результаты:

DateTime myDate = new DateTime(2013, 1, 1)
DateTime dateOfMonth;

myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 1, out dateOfMonth) 
// returns: true; dateOfMonth = Sunday, 1/6/2013

myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 4, out dateOfMonth) 
// returns: true; dateOfMonth = Sunday, 1/27/2013

myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 5, out dateOfMonth) 
// returns: false; 

myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 1, out dateOfMonth) 
// returns: true; dateOfMonth = Wednesday, 1/2/2013

myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 4, out dateOfMonth) 
// returns: true; dateOfMonth = Wednesday, 1/23/2013

myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 5, out dateOfMonth) 
// returns: true; dateOfMonth = Wednesday, 1/30/2013 

// etc

Ответ 6

Старый пост, но я нашел замечательно мало достойных ответов онлайн для этой, безусловно, довольно распространенной проблемы! Ответ на Mark Ransom должен быть последним словом в этом алгоритме, но вот класс-помощник С# (я ненавижу расширения) для всех, кто хочет быстро ответить на общие проблемы "первого дня недели в месяц", "xth day" недели за месяцем "и" последний день недели в месяц ".

Я изменил его, чтобы вернуть DateTime.MinValue, если X-й день недели выпадает за указанный месяц, а не на следующий месяц, потому что это мне кажется более полезным.

Я также добавил в программу примера LINQPad-runnable.

void Main()
{
    DayOfWeek dow = DayOfWeek.Friday;
    int y = 2014;
    int m = 2;

    String.Format("First {0}: {1}", new object[] { dow, DateHelper.FirstDayOfWeekInMonth(y, m, dow) }).Dump();

    "".Dump();

    String.Format("Last {0}: {1}", new object[] { dow, DateHelper.LastDayOfWeekInMonth(y, m, dow) }).Dump();

    "".Dump();

    for(int i = 1; i <= 6; i++)
        String.Format("{0} #{1}: {2}", new object[] { dow, i, DateHelper.XthDayOfWeekInMonth(y, m, dow, i) }).Dump();
}


public class DateHelper
{
    public static DateTime FirstDayOfWeekInMonth(int year, int month, DayOfWeek day)
    {
        DateTime res = new DateTime(year, month, 1);
        int offset = -(res.DayOfWeek - day);

        if (offset < 0)
            offset += 7;

        res = res.AddDays(offset);

        return res;
    }

    public static DateTime LastDayOfWeekInMonth(int year, int month, DayOfWeek day)
    {
        DateTime res = FirstDayOfWeekInMonth(year, month + 1, day);

        res = res.AddDays(-7);

        return res;
    }

    public static DateTime XthDayOfWeekInMonth(int year, int month, DayOfWeek day, int x)
    {
        DateTime res = DateTime.MinValue;

        if (x > 0)
        {
            res = FirstDayOfWeekInMonth(year, month, day);

            if (x > 1)
                res = res.AddDays((x - 1) * 7);

            res = res.Year == year && res.Month == month ? res : DateTime.MinValue;
        }

        return res;
    }
}

Печать

First Friday: 07/02/2014 00:00:00

Last Friday: 28/02/2014 00:00:00

Friday #1: 07/02/2014 00:00:00
Friday #2: 14/02/2014 00:00:00
Friday #3: 21/02/2014 00:00:00
Friday #4: 28/02/2014 00:00:00
Friday #5: 01/01/0001 00:00:00
Friday #6: 01/01/0001 00:00:00

Ответ 7

Это версия, которая использует LINQ и стиль функционального программирования.

Он работает следующим образом.

Сначала возьмите все дни месяца. Затем выберите только один из правильных дней (пятница). Наконец, возьмите n-й (3-й) элемент и вернитесь.

// dt: The date to start from (usually DateTime.Now)
// n: The nth occurance (3rd)
// weekday: the day of the week to look for
    public DateTime GetNthWeekdayOfMonth(DateTime dt, int n, DayOfWeek weekday)
    {
        var days = Enumerable.Range(1, DateTime.DaysInMonth(dt.Year, dt.Month)).Select(day => new DateTime(dt.Year, dt.Month, day));

        var weekdays = from day in days
                            where day.DayOfWeek == weekday
                            orderby day.Day ascending
                            select day;

        int index = n - 1;

        if (index >= 0 && index < weekdays.Count())
            return weekdays.ElementAt(index);

        else
            throw new InvalidOperationException("The specified day does not exist in this month!");
   }

Ответ 8

Я передаю это DateTime для начала месяца, на который я смотрю.

    private DateTime thirdSunday(DateTime timeFrom)
    {
        List<DateTime> days = new List<DateTime>();
        DateTime testDate = timeFrom;

        while (testDate < timeFrom.AddMonths(1))
        {
            if (testDate.DayOfWeek == DayOfWeek.Friday)
            {
                days.Add(testDate);
            }
            testDate = testDate.AddDays(1);
        }

        return days[2];
    }

Ответ 9

Я не знаю, как это сделать. Но это не слишком сложно для кода:

        DateTime now = DateTime.Now;

        for (int i = 0; i < 7; ++i)
        {
            DateTime d = new DateTime(now.Year, now.Month, i+1);
            if (d.DayOfWeek == DayOfWeek.Friday)
            {
                return d.AddDays(14);
            }
        }

Ответ 10

Мое рассуждение похоже на это

  • 15-я - первая возможная "третья пятница" (1,8,15)
  • поэтому мы ищем первую пятницу или после 15-го
  • DayOfWeek - это перечисление, начинающееся с 0 для воскресенья.
  • Поэтому вам нужно добавить элемент 5-(int)baseDay.DayOfWeek в 15-й
  • За исключением того, что вышеуказанное смещение может быть отрицательным, которое мы исправляем добавлением 7, а затем выполняем по модулю 7.

В коде:

public static DateTime GetThirdFriday(int year, int month)
{
   DateTime baseDay = new DateTime(year, month, 15);
   int thirdfriday = 15 + ((12 - (int)baseDay.DayOfWeek) % 7);
   return new DateTime(year, month, thirdfriday);
}

Поскольку возможны только 7 возможных результатов, вы также можете сделать это:

  private readonly static int[] thirdfridays =
      new int[] { 20, 19, 18, 17, 16, 15, 21 };

  public static int GetThirdFriday(int year, int month)
  {
     DateTime baseDay = new DateTime(year, month, 15);
     return thirdfridays[(int)baseDay.DayOfWeek];
  }

Ответ 11

    public DateTime GetThirdThursday(DateTime now)
    {
        DateTime ThirdThursday;
        now = DateTime.Now;
        string wkday;
        DateTime firstday = new DateTime(now.Year, now.Month, 1);
        ThirdThursday = firstday.AddDays(15);

        // ThirdThursday = now.AddDays((now.Day - 1) * -1).AddDays(14);
        wkday = ThirdThursday.DayOfWeek.ToString();

        while (wkday.CompareTo("Thursday") < 0)

        {
            ThirdThursday.AddDays(1);
        }
        return ThirdThursday;
    }

Ответ 12

    int numday = 0;
    int dayofweek = 5; //friday
    DateTime thirdfriday;
    for (int i = 0; i < (date.AddMonths(1) - date).Days && numday <3; i++)
    {
        if ((int)date.AddDays(i).DayOfWeek == dayofweek)
        {
            numday++;
        }
        if (numday == 3)
        {
            thirdfriday = date.AddDays(i);
        }

    }

Ответ 13

Извините, что вскочил в последнее время... Может помочь кому-то еще.

Начните говорить: петли, yuck. Слишком много кода, yuck. Не общий Достаточно, да.

Здесь простая функция со свободной перегрузкой.

public DateTime DateOfWeekOfMonth(int year, int month, DayOfWeek dayOfWeek, byte weekNumber)
{
    DateTime tempDate = new DateTime(year, month, 1);
    tempDate = tempDate.AddDays(-(tempDate.DayOfWeek - dayOfWeek));

    return
        tempDate.Day > (byte)DayOfWeek.Saturday
            ? tempDate.AddDays(7 * weekNumber)
            : tempDate.AddDays(7 * (weekNumber - 1));
}

public DateTime DateOfWeekOfMonth(DateTime sender, DayOfWeek dayOfWeek, byte weekNumber)
{
    return DateOfWeekOfMonth(sender.Year, sender.Month, dayOfWeek, weekNumber);
}

Ваше использование:

DateTime thirdFridayOfMonth = DateOfWeekOfMonth(DateTime.Now, DayOfWeek.Friday, 3);

Ответ 14

Вот мой алгоритм:

  • Найдите количество дней до предстоящей пятницы.
  • Инициализировать счетчик и установить его в 1. Вычтите семь дней с даты, возвращенной из [1], а затем сравните месяц с даты, возвращенной с датой, возвращенной из (1).
    1. Если месяцы не равны, верните счетчик из [2].
    2. Если месяцы равны, запишите в [2] и добавьте 1 к счетчику, созданному в [2].

Счетчик даст вам пятнадцатую пятницу месяца на эту дату (или на предстоящую пятницу).

Ответ 15

После великолепных работ нет подтверждения для появления. Вы можете найти любой n-й день для данного месяца даты либо от начала, либо до последнего. Укажите минус значение вхождения, если вы ищете от последнего.

 public static DateTime GetDayOfMonth(DateTime dateValue, DayOfWeek dayOfWeek, int occurance)
    {
        List<DateTime> dayOfWeekRanges = new List<DateTime>();

        //move to the first of th month
        DateTime startOfMonth = new DateTime(dateValue.Year, dateValue.Month, 1);

        //move startOfMonth to the dayOfWeek requested
        while (startOfMonth.DayOfWeek != dayOfWeek)
            startOfMonth = startOfMonth.AddDays(1);

        do
        {
            dayOfWeekRanges.Add(startOfMonth);
            startOfMonth = startOfMonth.AddDays(7);
        } while (startOfMonth.Month == dateValue.Month);

        bool fromLast = occurance < 0;
        if (fromLast)
            occurance = occurance * -1;

        if (fromLast)
            return dayOfWeekRanges[dayOfWeekRanges.Count - occurance];
        else
            return dayOfWeekRanges[occurance - 1];
    }

Ответ 16

Вот мои два цента... Оптимизированное решение без ненужных циклов или тестов:

public static DateTime ThirdFridayOfMonth(DateTime dateTime)
{
    int day = dateTime.Day;
    return dateTime.AddDays(21 - day - ((int)dateTime.DayOfWeek + 37 - day) % 7);
}