Вот что я пытаюсь сделать:
Учитывая дату, день недели и целое число 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));
}
Ответ 1
Вы можете изменить проверку недели, чтобы функция читала:
private bool NthDayOfMonth(DateTime date, DayOfWeek dow, int n){
int d = date.Day;
return date.DayOfWeek == dow && (d-1)/7 == (n-1);
}
Кроме этого, он выглядит довольно хорошо и эффективно.
Ответ 2
Ответ от этого веб-сайта. Скопируйте/вставьте здесь, если этот сайт будет потерян.
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;
}
Ответ 3
Здесь - это то, что должен сказать MSDN. Его VB, но он легко переводится.
Ответ 4
Похоже, что язык даёт дату/день для заданной даты. Если кому-то было интересно, вы можете прочитать о Конгруэнтность Целлера.
Я не думаю, что они хотели, чтобы вы это сделали, но вы могли найти день недели первого дня месяца. Теперь, когда я подумал об этом, вы можете найти день недели для данного дня как N
и получить этот модуль 7.
Ой, подождите, это N-й случай дня недели (например, воскресенье) или как Nth weekday месяца! Хорошо, я вижу примеры.
Может быть, будет иметь значение, если вы могли бы построить дату, например, 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 *)
Надеюсь, что в этом LOL нет ошибки!
[править: суббота была бы седьмой, а верхняя граница выше (N-1)*7 + 7
.]
Ваше решение похоже, что оно будет соответствовать двум разным неделям? Похоже, он всегда будет возвращать ноль по воскресеньям? Должно было сделать псевдокод в С#.. короткое замыкание && это как мой, если..
эй не должен в воскресенье первый матч за N = 1 в месяцах, которые начинаются в воскресенье?
d/ 7 == n
Это приведет к (either 0 or 1)/7 == 1
, что не может быть прав! Ваш ||
ловит (n-1)
, и у Роберта это есть. Пойдите с ответом Роберта Вагнера! Это всего 2 линии, короткие - это хорошо! Имея (Day-1) mod 7
[edit: (Day-1) div 7
]
исключает мои ненужные переменные и 2 строки настройки.
Для записи это должно быть проверено на граничные случаи и так далее, как то, что если 31 августа было воскресенье или суббота.
[edit: Должен был также проверить конец недели. Извините!]
Ответ 5
Вы можете найти функцию, которая возвращает дату для n-го вхождения определенного дня недели в любой месяц.
См. http://chiragrdarji.wordpress.com/2010/08/23/find-second-saturday-and-fourth-saturday-of-month/
Ответ 6
В этом ответе следующий код нужно перевернуть:
// 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");
}
Ответ 7
Большинство приведенных выше ответов частично точны или излишне сложны.
Вы можете попробовать эту более простую функцию, которая также проверяет, является ли данная дата последней, кроме 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;
}
Ответ 8
Если вам нужен список дат для промежутка времени (а не только одного) для Nth 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);
... и т.д..