Вот что я пытаюсь сделать:
Учитывая дату, день недели и целое число 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));
}





Вы можете изменить чек недели, чтобы функция читала:
private bool NthDayOfMonth(DateTime date, DayOfWeek dow, int n){
int d = date.Day;
return date.DayOfWeek == dow && (d-1)/7 == (n-1);
}
В остальном он выглядит довольно хорошо и эффективно.
Здесь - это то, что сообщает MSDN. Его VB, но он легко переводится.
Ответ от этот сайт. Скопируйте / вставьте сюда на случай, если этот сайт когда-нибудь будет утерян.
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;
}
это также делает противоположное тому, что я хочу
Было ли это именно то, что нужно Кевину, это как раз то, что мне нужно. Спасибо, что разместили это.
проверка действительного месяца должна выполняться после добавления дней. if (dt.Month! = month) всегда истинно после нахождения первого дня недели месяца
Похоже, что язык предоставляет методы даты / дня для заданной даты. Если кому-то было интересно, можете почитать про Конгруэнтность Целлера.
Не думаю, что они хотели, чтобы вы делали это, но отсюда вы можете найти день недели первого дня месяца. Теперь, когда я подумал об этом, вы можете найти день недели для данного дня как 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);
...так далее.
это как бы делает противоположное тому, что я хочу