簡體   English   中英

一個月中星期幾的第一次出現

[英]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確定DayOfWeeknth的值,則可以執行以下操作。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM