Как определить, является ли данная дата N-м днем ​​недели месяца? - PullRequest
17 голосов
/ 14 ноября 2008

Вот что я пытаюсь сделать: Учитывая дату, день недели и целое число n, определите, является ли дата n днем ​​месяца.

Например:

  • ввод 1/1/2009,Monday,2 будет ложным, потому что 1/1/2009 не второй понедельник

  • ввод 11/13/2008,Thursday,2 вернул бы true, потому что это второй четверг

Как я могу улучшить эту реализацию?

private bool NthDayOfMonth(DateTime date, DayOfWeek dow, int n)
{
    int d = date.Day;
    return date.DayOfWeek == dow && (d/ 7 == n || (d/ 7 == (n - 1) && d % 7 > 0));
}

Ответы [ 8 ]

12 голосов
/ 14 ноября 2008

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

private bool NthDayOfMonth(DateTime date, DayOfWeek dow, int n){
  int d = date.Day;
  return date.DayOfWeek == dow && (d-1)/7 == (n-1);
}

Кроме того, это выглядит довольно хорошо и эффективно.

8 голосов
/ 14 ноября 2008

Ответ от этого сайта . Скопируйте / вставьте сюда на случай, если этот сайт потерян.

public static DateTime FindTheNthSpecificWeekday(int year, int month,int nth, System.DayOfWeek day_of_the_week)
{
    // validate month value
    if(month < 1 || month > 12)
    {
        throw new ArgumentOutOfRangeException("Invalid month value.");
    }

    // validate the nth value
    if(nth < 0 || nth > 5)
    {
        throw new ArgumentOutOfRangeException("Invalid nth value.");
    }

    // start from the first day of the month
    DateTime dt = new DateTime(year, month, 1);

    // loop until we find our first match day of the week
    while(dt.DayOfWeek != day_of_the_week)
    {
        dt = dt.AddDays(1);
    }

    if(dt.Month != month)
    {
        // we skip to the next month, we throw an exception
        throw new ArgumentOutOfRangeException(string.Format("The given month has less than {0} {1}s", nth, day_of_the_week));
    }

    // Complete the gap to the nth week
    dt = dt.AddDays((nth - 1) * 7);

    return dt;
}
1 голос
/ 23 августа 2010

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

См. http://chiragrdarji.wordpress.com/2010/08/23/find-second-saturday-and-fourth-saturday-of-month/

1 голос
/ 15 ноября 2008

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

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

Ой, подождите, это N-е вхождение дня недели (например, воскресенья) или как N-е дня недели месяца! Хорошо, я вижу примеры.

Может быть, будет иметь значение, если вы сможете построить дату, например, 1-го числа месяца ...

Учитывая, что это N-е вхождение дня недели , и что вы не можете использовать любой тип данных datetime, и что у вас есть доступ как к получению дня недели, так и к получению дня месячные функции. Воскресенье будет ноль?

1) Во-первых, день недели должен соответствовать указанному дню недели.
2) N должно быть не менее 1 и не более 4.
3) День месяца будет варьироваться между n * 7 * dayOfWeek + 1 и n * 7 * dayOfWeek + 6 для того же n.
- Дай мне подумать об этом. Если бы воскресенье было первым .. 0 * 7 * 0 + 1 = 1, а суббота 6-го была бы 0 * 7 * 0 + 6.

Думаю, 1 и 3 выше достаточно, так как функция получения дня месяца не должна нарушать 2.

(* first try, this code sucks *)

function isNthGivenDayInMonth(date : dateTime;
                              dow : dayOfWeek;
                              N : integer) : boolean;
    var B, A : integer (* on or before and after day of month *)
    var Day : integer (* day of month *)
    begin
    B := (N-1)*7 + 1; A := (N-1)*7 + 6;
    D := getDayOfMonth(date);
    if (dow <> getDayOfWeek(date) 
        then return(false)
        else return( (B <= Day) and (A >= Day) );
    end; (* function *)

Надеюсь, что в этом нет ошибки!
[править: суббота была бы 7-й, а верхняя граница выше (N-1)*7 + 7.]
Ваше решение выглядит так, как будто бы оно совпадало с 2 разными неделями? Похоже, он всегда будет возвращать ноль в воскресенье? Должен был сделать псевдокод в C # .. короткое замыкание &&, как мой, если .. эй, разве не должен воскресенье первый матч для N = 1 в месяцы, которые начинаются в воскресенье?

 d/ 7 == n

Это приведет к (either 0 or 1)/7 == 1, что не может быть правильным! Твой || тоже ловит (n-1), у Роберта это есть. Идите с ответом Роберта Вагнера! Это всего 2 строки, короткая - это хорошо! Имея (Day-1) mod 7
[редактировать: (Day-1) div 7] устраняет мои ненужные переменные и 2 строки настройки.

Для протокола это следует проверить для граничных случаев и т. Д., Например, что если 31 августа было воскресенье или суббота.
[править: надо было проверять регистр конца недели тоже. Извините!]

1 голос
/ 14 ноября 2008

Здесь - это то, что говорит MSDN. Это VB, но он легко переводится.

0 голосов
/ 23 февраля 2016

Если вам нужен список дат за промежуток времени (а не только одну) для N-го дня недели в месяце, вы можете использовать это:

internal static List<DateTime> GetDatesForNthDOWOfMonth(int weekNum, DayOfWeek DOW, DateTime beginDate, DateTime endDate)
{
    List<DateTime> datesForNthDOWOfMonth = new List<DateTime>();
    int earliestDayOfMonth = 1;
    int latestDayOfMonth = 7;
    DateTime currentDate = beginDate;

    switch (weekNum)
    {
        case 1:
            earliestDayOfMonth = 1;
            latestDayOfMonth = 7;
            break;
        case 2:
            earliestDayOfMonth = 8;
            latestDayOfMonth = 14;
            break;
        case 3:
            earliestDayOfMonth = 15;
            latestDayOfMonth = 21;
            break;
        case 4:
            earliestDayOfMonth = 22;
            latestDayOfMonth = 28;
            break;
    }

    while (currentDate < endDate)
    {
        DateTime dateToInc = currentDate;
        DateTime endOfMonth = new DateTime(dateToInc.Year, dateToInc.Month, DateTime.DaysInMonth(dateToInc.Year, dateToInc.Month));
        bool dateFound = false;
        while (!dateFound)
        {
            dateFound = dateToInc.DayOfWeek.Equals(DOW);
            if (dateFound)
            {
                if ((dateToInc.Day >= earliestDayOfMonth) && 
                    (dateToInc.Day <= latestDayOfMonth))
                {
                    datesForNthDOWOfMonth.Add(dateToInc);
                }
            }
            if (dateToInc.Date.Equals(endOfMonth.Date)) continue;
            dateToInc = dateToInc.AddDays(1);
        }
        currentDate = new DateTime(currentDate.Year, currentDate.Month, 1);
        currentDate = currentDate.AddMonths(1);
    }
    return datesForNthDOWOfMonth;
}

... и назовите это так:

// This is to get the 1st Monday in each month from today through one year from today
DateTime beg = DateTime.Now;
DateTime end = DateTime.Now.AddYears(1);
List<DateTime> dates = GetDatesForNthDOWOfMonth(1, DayOfWeek.Monday, beg, end);
// To see the list of dateTimes, for verification
foreach (DateTime d in dates)
{
    MessageBox.Show(string.Format("Found {0}", d.ToString()));
}

Вы можете получить 2-ую пятницу каждого месяца следующим образом:

List<DateTime> dates = GetDatesForNthDOWOfMonth(2, DayOfWeek.Friday, beg, end);

... и т.д.

0 голосов
/ 16 октября 2014

Большинство ответов выше являются частично точными или излишне сложными. Вы можете попробовать эту более простую функцию, которая также проверяет, является ли данная дата последним, но N-м днем ​​месяца.

    public static bool IsNthDayofMonth(this DateTime date, DayOfWeek weekday, int N)
    {
        if (N > 0)
        {
            var first = new DateTime(date.Year, date.Month, 1);
            return (date.Day - first.Day)/ 7 == N - 1 && date.DayOfWeek == weekday;
        }
        else
        {

            var last = new DateTime(date.Year, date.Month, 1).AddMonths(1).AddDays(-1);
            return (last.Day - date.Day) / 7 == (Math.Abs(N) - 1) && date.DayOfWeek == weekday;
        }
0 голосов
/ 06 февраля 2009

В этот ответ , необходимо перевернуть следующий код:

// Complete the gap to the nth week
dt = dt.AddDays((nth - 1) * 7);

if(dt.Month != month)
{
// we skip to the next month, we throw an exception
throw new ArgumentOutOfRangeException(”The given month has less than ” nth.ToString() ” ”
day_of_the_week.ToString() “s”);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...