[英]first occurrence of day of week in month
我想用DateTime date
配置一個 Event 。
我想在每個月的同一周和同一天重復該活動。
例如,此事件發生在 2015 年 4 月 2 日(四月第一周的星期四)。
我想在每個月的第一個星期的每個星期四再次重復。
我如何每次計算下一個日期?
只需從每月的第一天開始,遞增,直到獲得所需的星期幾,然后以n-1的7倍遞增,其中n是您從該月開始的第n天。
public static DateTime(int year, int month, DayOfWeek weekDay, int nth)
{
DateTime result = new DateTime(year, month, 1);
while(result.DatOfWeek != weekDay)
result = result.AddDays(1);
return result.AddDays(7 * (nth-1));
}
請注意,您將需要對參數進行檢查,並確保最終結果不會超過下個月。
如果還需要從DateTime
確定DayOfWeek
和nth
的值,則可以執行以下操作。
DateTime now = DateTime.Now;
DayOfWeek dayOfWeek = now.DayOfWeek;
int nth = 0;
int month = now.Month;
int year = now.Year;
while(now.Year == year && now.Month == month)
{
now = now.AddDays(-7);
nth++;
}
請注意,一個月可能有第5個星期三,但下個月只有第4個星期三,因此您必須確定在這種情況下該怎么做。
我開發了一個小功能,可以找到一個月的第n天。
private static DateTime Next(int year, int month, DayOfWeek dayOfWeek, int occurrence)
{
return Enumerable.Range(1, 7).
Select(day => new DateTime(year, month, day)).
First(dateTime => (dateTime.DayOfWeek == dayOfWeek))
.AddDays(7 * (occurrence - 1));
}
我為我的項目開發的方法。 它正在添加所有邊緣案例並在生產中工作。
/// <summary>
/// Calculates and returns the date from specifed month based on weekday and week number passed in.
/// </summary>
/// <param name="month">any date of the month as base referece</param>
/// <param name="dayOfWeek">day of week Mon/Tues/Wed/Thu/Fri etc..</param>
/// <param name="requiredWeek">!st wqeek = 1,2nd week =2,3,4,5,last etc</param>
/// <returns></returns>
public static DateTime GetFirstOccuringWeekDayFromMonth(DateTime month, DayOfWeek dayOfWeek, ReccurrenceEnum requiredWeek)
{
if (requiredWeek == ReccurrenceEnum.First || requiredWeek == ReccurrenceEnum.Second
|| requiredWeek == ReccurrenceEnum.Third || requiredWeek == ReccurrenceEnum.Forth || requiredWeek == ReccurrenceEnum.Last)
{
DateTime current;
int requiredweekno = (int)requiredWeek;
int foundDayInstanceCount = 0;
if (requiredWeek == ReccurrenceEnum.Last)
{
DateTime lastDayofMonth = new DateTime(month.AddMonths(1).Year, month.AddMonths(1).Month, 1).AddDays(-1);
DateTime firstDayofMonth = new DateTime(month.Year, month.Month, 1);
current = lastDayofMonth;
//skip until required day is reached.
while (current.DayOfWeek != dayOfWeek && current >= firstDayofMonth)
current = current.AddDays(-1);
return current;
}
else
{
DateTime firstDayofMonth = new DateTime(month.Year, month.Month, 1);
DateTime lastDayofMonth = new DateTime(month.AddMonths(1).Year, month.AddMonths(1).Month, 1).AddDays(-1);
current = firstDayofMonth;
if (current.DayOfWeek == dayOfWeek)
foundDayInstanceCount++;
//skip until required week is reached.
while (foundDayInstanceCount < requiredweekno && current <= lastDayofMonth)
{
current = current.AddDays(1);
if (current.DayOfWeek == dayOfWeek)
foundDayInstanceCount++;
}
//skip until required day is reached.
while (current.DayOfWeek != dayOfWeek && current <= lastDayofMonth)
current = current.AddDays(1);
return current;
}
}
else
throw new Exception("Exception, wrong week recurrence specified!");
}
public enum ReccurrenceEnum
{
First = 1,
Second = 2,
Third = 3,
Forth = 4,
Last = 5,
}
這是我所做的,代碼中沒有循環,它基於問題Find The date last sunday...計算一個月的最后一個(你想要的任何一天)工作日。
public static DateTime getFirstDayWeekOfMonth(DateTime fromDT, DayOfWeek wantedDay)
{
int wantedDayIndex = (int)wantedDay;
int firstDayIndex = (int)fromDT.DayOfWeek;
DateTime newTime = fromDT.AddDays(
firstDayIndex > wantedDayIndex
? (7 - firstDayIndex) + (wantedDayIndex)
: wantedDayIndex - firstDayIndex
);
return newTime;
}
其原理是天的索引(C# 中從 0 到 6 的值)以及這些索引之間的距離。
如果使用 0 到 6 之間的值設置循環列表,則需要計算兩個DayIndex
之間的距離(始終向前)。
解決方案不是列表,只是了解概念。
您計算從起始索引到 6 的距離,加上從 0 到起始索引的距離。 如果該月第一天的DayIndex
大於indexWanted ,則為真。 否則,只需要從 0 到該月第一天的 DayIndex 的距離。
另外,我為這兩個功能(一個月的第一天和最后一天)制作了測試用例。 它們是在 NUnit C# 中制作的。
[TestFixture]
public class TESTLastFirst
{
[Test]
public void LastWeekDayOfMonthTest()
{
for (int j = 1; j < 12; j++)
{
DateTime dateTimeExpected = new DateTime();
switch (j)
{
case 1: dateTimeExpected = new DateTime(2022, j, 30); break;
case 2: dateTimeExpected = new DateTime(2022, j, 27); break;
case 3: dateTimeExpected = new DateTime(2022, j, 27); break;
case 4: dateTimeExpected = new DateTime(2022, j, 24); break;
case 5: dateTimeExpected = new DateTime(2022, j, 29); break;
case 6: dateTimeExpected = new DateTime(2022, j, 26); break;
case 7: dateTimeExpected = new DateTime(2022, j, 31); break;
case 8: dateTimeExpected = new DateTime(2022, j, 28); break;
case 9: dateTimeExpected = new DateTime(2022, j, 25); break;
case 10: dateTimeExpected = new DateTime(2022, j, 30); break;
case 11: dateTimeExpected = new DateTime(2022, j, 27); break;
case 12: dateTimeExpected = new DateTime(2022, j, 25); break;
}
for (int i = 1; i < 28; i++)
{
DateTime dateTimeResult = ProgramV.getLastWeekDayOfMonth(new DateTime(2022, j, i), DayOfWeek.Sunday);
Assert.That(dateTimeResult, Is.EqualTo(dateTimeExpected));
}
}
}
[Test]
public void FirstWeekDayOfMonthTest()
{
for (int j = 1; j < 12; j++)
{
DateTime dateTimeExpected = new DateTime();
switch (j)
{
case 1: dateTimeExpected = new DateTime(2022, j, 2 + 1); break;
case 2: dateTimeExpected = new DateTime(2022, j, 6 + 1); break;
case 3: dateTimeExpected = new DateTime(2022, j, 6 + 1); break;
case 4: dateTimeExpected = new DateTime(2022, j, 3 + 1); break;
case 5: dateTimeExpected = new DateTime(2022, j, 1 + 1); break;
case 6: dateTimeExpected = new DateTime(2022, j, 5 + 1); break;
case 7: dateTimeExpected = new DateTime(2022, j, 3 + 1); break;
case 8: dateTimeExpected = new DateTime(2022, j, 7 + 1); break;
case 9: dateTimeExpected = new DateTime(2022, j, 4 + 1); break;
case 10: dateTimeExpected = new DateTime(2022, j, 2 + 1); break;
case 11: dateTimeExpected = new DateTime(2022, j, 6 + 1); break;
case 12: dateTimeExpected = new DateTime(2022, j, 4 + 1); break;
}
DateTime dateTimeResult = ProgramV.getFirstDayWeekOfMonth(new DateTime(2022, j, 1), DayOfWeek.Monday);
Assert.That(dateTimeResult, Is.EqualTo(dateTimeExpected));
}
}
public class ProgramV
{
public static DateTime getLastWeekDayOfMonth(DateTime cuurentDate, DayOfWeek wantedDayObj)
{
DateTime lastDayMonth = new DateTime(cuurentDate.Year, cuurentDate.Month, 1).AddMonths(1).AddDays(-1);
int wantedDay = (int)wantedDayObj;
int lastDay = (int)lastDayMonth.DayOfWeek;
DateTime newDate = lastDayMonth.AddDays(
lastDay >= wantedDay ? wantedDay - lastDay : wantedDay - lastDay - 7
);
return newDate;
}
public static DateTime getFirstDayWeekOfMonth(DateTime fromDT, DayOfWeek wantedDay)
{
int wantedDayIndex = (int)wantedDay;
int firstDayIndex = (int)fromDT.DayOfWeek;
DateTime newTime = fromDT.AddDays(
//
firstDayIndex > wantedDayIndex ? (7 - firstDayIndex) + (wantedDayIndex ) : wantedDayIndex - firstDayIndex
);
return newTime;
}
}
}
這是獲取一個月中第 n 次出現的工作日的擴展方法。
/// <summary>
/// Gets the Nth occurrence of the specified weekday in the month.
/// </summary>
public static DateTime GetNthOfWeekDayInMonth(this DateTime dt, DayOfWeek dayOfWeek, int n)
{
//Get the first day of the month
DateTime fd = dt.AddDays(-dt.Day).AddDays(1);
// Get the first occurrence of the required week day.
fd = dayOfWeek >= fd.DayOfWeek ? fd.AddDays(dayOfWeek - fd.DayOfWeek) : fd.AddDays((7 + ((int)dayOfWeek)) - ((int)fd.DayOfWeek));
// Add the amount of "weeks" to get the correct nth date.
fd = fd.AddDays((n-1) * 7);
// Might want to handle it differently, but if the next nth day is not in the same month, give an exception?
if (fd.Month != dt.Month) throw new Exception($"There is no {n} week in this month");
return fd;
}
樣本:
new DateTime(2022,05,12).GetNthOfWeekDayInMonth(DayOfWeek.Tuesday, 2)
// out: 2022/05/10
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.