Как определить, является ли данная дата N-м днем ​​недели месяца?

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

Например:

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

  • ввод 11/13/2008,Thursday,2 вернет истину, потому что это второй четверг

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

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));
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
17
0
13 598
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Ответ принят как подходящий

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

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

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

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

это как бы делает противоположное тому, что я хочу

Kevin 14.11.2008 01:23

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

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

это также делает противоположное тому, что я хочу

Kevin 14.11.2008 02:02

Было ли это именно то, что нужно Кевину, это как раз то, что мне нужно. Спасибо, что разместили это.

Matthew Nichols 03.01.2011 00:18

проверка действительного месяца должна выполняться после добавления дней. if (dt.Month! = month) всегда истинно после нахождения первого дня недели месяца

SQueek 15.12.2014 12:33

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

Не думаю, что они хотели, чтобы вы делали это, но отсюда вы можете найти день недели первого дня месяца. Теперь, когда я подумал об этом, вы можете найти день недели для данного дня как 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.]
Ваше решение похоже на две разные недели? Похоже, по воскресеньям он всегда будет возвращать ноль? Надо было сделать псевдокод на C# .. короткое замыкание && похоже на мой if .. Эй, разве в воскресенье не должно быть первого матча для N = 1 в месяцах, которые начинаются в воскресенье?

 d/ 7 == n

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

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

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

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

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

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

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

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

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

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

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

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

...так далее.

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