書接上回,我們繼續來分享一些關於特殊時間獲取的常用擴充套件方法。
01、獲取當前日期所在月的第一個指定星期幾
該方法和前面介紹的獲取當前日期所在周的第一天(週一)核心思想是一樣的,只是把求週一改成求周幾而已,當然其中有些小細節需要注意,比如求所在周的第一天則兩天都在同一周,而求所在月第一個指定周則可能兩天在不同周,具體程式碼如下:
//獲取當前日期所在月的第一個指定星期幾
public static DateTime GetFirstDayOfWeekDateTimeInMonth(this DateTime dateTime, DayOfWeek dayOfWeek)
{
//獲取當前日期所在月的第一天
var firstDayOfMonth = dateTime.GetFirstDayDateTimeOfMonth();
//計算目標日期與當月第一天相差天數
var diff = ((int)dayOfWeek - (int)firstDayOfMonth.DayOfWeek + 7) % 7;
return firstDayOfMonth.AddDays(diff);
}
下面我們還需要做詳細的單元測試,我們分別測試指定週一和週日兩個特殊日期,然後再分別測試三種特殊情況:
指定週一測試:
(1) 驗證當前日期是週五,而週一在下一週的情況;
(2) 驗證當前日期是本月第一個週一的情況;
(3) 驗證當前日期是週日,並且在本月第一個週一之後的情況;
指定週日測試:
(1) 驗證當前日期是週五,並且在本月第一個週日之前的情況;
(2) 驗證當前日期是本月第一個週日的情況;
(3) 驗證當前日期是週一,並且在本月第一個週日之後的情況;
具體程式碼如下:
[Fact]
public void GetFirstDayOfWeekDateTimeInMonth()
{
//驗證當前日期是週五,而週一在下一週的情況
var friday_monday = new DateTime(2024, 11, 1, 14, 10, 10);
var day_friday_monday = friday_monday.GetFirstDayOfWeekDateTimeInMonth(DayOfWeek.Monday);
Assert.Equal(new DateTime(2024, 11, 4), day_friday_monday);
//驗證當前日期是本月第一個週一的情況
var monday_monday = new DateTime(2024, 11, 4, 4, 10, 10);
var day_monday_monday = monday_monday.GetFirstDayOfWeekDateTimeInMonth(DayOfWeek.Monday);
Assert.Equal(new DateTime(2024, 11, 4), day_monday_monday);
//驗證當前日期是週日,並且在本月第一個週一之後的情況
var sunday_monday = new DateTime(2024, 11, 30, 4, 10, 10);
var day_sunday_monday = sunday_monday.GetFirstDayOfWeekDateTimeInMonth(DayOfWeek.Monday);
Assert.Equal(new DateTime(2024, 11, 4), day_sunday_monday);
//驗證當前日期是週五,並且在本月第一個週日之前的情況
var friday_sunday = new DateTime(2024, 11, 1, 14, 10, 10);
var day_friday_sunday = friday_sunday.GetFirstDayOfWeekDateTimeInMonth(DayOfWeek.Sunday);
Assert.Equal(new DateTime(2024, 11, 3), day_friday_sunday);
//驗證當前日期是本月第一個週日的情況
var sunday_sunday = new DateTime(2024, 11, 30, 4, 10, 10);
var day_sunday_sunday = sunday_sunday.GetFirstDayOfWeekDateTimeInMonth(DayOfWeek.Sunday);
Assert.Equal(new DateTime(2024, 11, 3), day_sunday_sunday);
//驗證當前日期是週一,並且在本月第一個週日之後的情況
var monday_sunday = new DateTime(2024, 11, 4, 4, 10, 10);
var day_monday_sunday = monday_sunday.GetFirstDayOfWeekDateTimeInMonth(DayOfWeek.Sunday);
Assert.Equal(new DateTime(2024, 11, 3), day_monday_sunday);
}
02、獲取當前日期所在月的最後一個指定星期幾
該方法和上一個求第一個指定星期幾核心思想是一樣的,具體程式碼如下:
//獲取當前日期所在月的最後一個指定星期幾
public static DateTime GetLastDayOfWeekDateTimeInMonth(this DateTime dateTime, DayOfWeek dayOfWeek)
{
//獲取當前日期所在月的最後一天
var lastDayOfMonth = dateTime.GetLastDayDateTimeOfMonth();
//計算目標日期與當月最後一天相差天數
var diff = ((int)lastDayOfMonth.DayOfWeek - (int)dayOfWeek + 7) % 7;
return lastDayOfMonth.AddDays(-diff);
}
單元測試可以參考求第一個指定星期幾,這裡就不贅述了。
03、獲取當前日期上一個指定星期幾
求上一個指定周幾,其實也不復雜,首先計算出當前日期與目標星期幾相差的天數,其中有個小細節需要注意,就是如果兩個日期相同,則需要把相差天數改為7,具體程式碼如下:
//獲取當前日期上一個指定星期幾
public static DateTime GetPreviousDayDateTimeOfWeek(this DateTime dateTime, DayOfWeek dayOfWeek)
{
//計算當前日期與目標星期幾相差天數
var diff = ((int)dateTime.DayOfWeek - (int)dayOfWeek + 7) % 7;
//如果相差0天表示當前日期和目標星期幾相同,需要改為7
diff = diff == 0 ? 7 : diff;
return dateTime.AddDays(-diff).Date;
}
我們分別對以下四種情況做單元測試:
(1) 驗證當前日期是週一,而上一個週一在上一月的情況;
(2) 驗證當前日期是週一,而上一個週一在當月的情況;
(3) 驗證當前日期是週日,而上一個週一在當月的情況;
(4) 驗證當前日期是週六,並且是當月最後一天的情況;
具體程式碼如下:
[Fact]
public void GetPreviousDayDateTimeOfWeek()
{
//驗證當前日期是週一,而上一個週一在上一月的情況
var monday = new DateTime(2024, 11, 1, 14, 10, 10);
var day_monday = monday.GetPreviousDayDateTimeOfWeek(DayOfWeek.Monday);
Assert.Equal(new DateTime(2024, 10, 28), day_monday);
//驗證當前日期是週一,而上一個週一在當月的情況
var monday1 = new DateTime(2024, 11, 25, 14, 10, 10);
var day_monday1 = monday1.GetPreviousDayDateTimeOfWeek(DayOfWeek.Monday);
Assert.Equal(new DateTime(2024, 11, 18), day_monday1);
//驗證當前日期是週日,而上一個週一在當月的情況
var sunday = new DateTime(2024, 11, 24, 4, 10, 10);
var day_sunday = sunday.GetPreviousDayDateTimeOfWeek(DayOfWeek.Monday);
Assert.Equal(new DateTime(2024, 11, 18), day_sunday);
//驗證當前日期是週六,並且是當月最後一天的情況
var saturday = new DateTime(2024, 11, 30, 4, 10, 10);
var day_saturday = saturday.GetPreviousDayDateTimeOfWeek(DayOfWeek.Monday);
Assert.Equal(new DateTime(2024, 11, 25), day_saturday);
}
04、獲取當前日期下一個指定星期幾
該方法和上面獲取上一個指定星期幾核心思想相同,具體程式碼如下:
//獲取當前日期下一個最近指定星期幾
public static DateTime GetNextDayDateTimeOfWeek(this DateTime dateTime, DayOfWeek dayOfWeek)
{
//計算目標日期與當月最後一天相差天數
var diff = ((int)dayOfWeek - (int)dateTime.DayOfWeek + 7) % 7;
//如果相差0天表示當前日期和目標星期幾相同,需要改為7
diff = diff == 0 ? 7 : diff;
return dateTime.AddDays(diff).Date;
}
單元測試也可以參考求上一個指定星期幾,這裡就不再贅述了。
05、獲取當前日期是其所在月的第幾周
該方法的核心思想是,獲取當前日期和當月第一天相差多少天,然後用相差的天數除以7即可獲得當前是第幾周。
但是這裡有個比較麻煩的事情是如果第一週不滿一週呢,比如當月的第一週第一天是2024-11-01週五,而今天是2024-11-07週四,應該是當月的第二週,但是如果直接計算兩天的差再除以7結果顯然是不對的。
因此我們首先需要把第一週不滿一週的天數補上,即前面還有4天。
如此就是(7+4)/7=1…4,即所在第二週,其中商表示完整的周,餘數則表示不完整的周。如果轉為公式則為:days/7 + (days%7 > 0 ? 1 : 0),我們對這個公式簡化後得到:(days + 6)/7,具體實現程式碼如下:
//獲取當前日期是其所在月的第幾周
public static int GetWeekOfMonth(this DateTime dateTime)
{
//獲取當前日期所在月的第一天
var firstDayOfMonth = dateTime.GetFirstDayDateTimeOfMonth();
//首先設定週一為一週的開始
//計算當前月第一天與週一相差天數
//即第一週如果不滿一週還差多少天
var diff = ((int)firstDayOfMonth.DayOfWeek - (int)DayOfWeek.Monday + 7) % 7;
//用第一週不滿的差值加上當前日期的天數之和計算當前為當月第幾周
//然後計算 總天數/7的商,如果有餘數則再加1
//公式為:n/7 + (n%7 > 0 ? 1 : 0)
//上面公式可以簡化為 (n+6)/7
return (diff + dateTime.Day + 6) / 7;
}
下面我們對其進行以下幾種情況詳細的單元測試:
(1) 驗證當前日期是週五,且是當月第一天的情況;
(2) 驗證當前日期是週日,且在當月第一週的情況;
(3) 驗證當前日期是週一,且在當月第三週的情況;
(4) 驗證當前日期是週日,且在當月第三週的情況;
(5) 驗證當前日期是週六,且是當月最後一天的情況;
具體程式碼如下:
[Fact]
public void GetWeekOfMonth()
{
//驗證當前日期是週五,且是當月第一天的情況
var friday = new DateTime(2024, 11, 1, 14, 10, 10);
var day_friday = friday.GetWeekOfMonth();
Assert.Equal(1, day_friday);
//驗證當前日期是週日,且在當月第一週的情況
var sunday = new DateTime(2024, 11, 3, 14, 10, 10);
var day_sunday = sunday.GetWeekOfMonth();
Assert.Equal(1, day_sunday);
//驗證當前日期是週一,且在當月第三週的情況
var monday = new DateTime(2024, 11, 11, 4, 10, 10);
var day_monday = monday.GetWeekOfMonth();
Assert.Equal(3, day_monday);
//驗證當前日期是週日,且在當月第三週的情況
var date17 = new DateTime(2024, 11, 17, 4, 10, 10);
var day17 = date17.GetWeekOfMonth();
Assert.Equal(3, day17);
//驗證當前日期是週六,且是當月最後一天的情況
var sunday1 = new DateTime(2024, 11, 30, 4, 10, 10);
var day_sunday1 = sunday1.GetWeekOfMonth();
Assert.Equal(5, day_sunday1);
}
06、獲取當前日期是其所在年的第幾周(ISO 8601 標準)
在ISO 8601 標準規定中,每週從星期一開始,且每年最少有 52 周,每年的第一週是包含該年第一天的那一週,且該周必須至少有四天。
獲取當然日期所在年的第幾周可以透過呼叫C#中文化資訊中日曆元件中GetWeekOfYear方法,具體程式碼如下:
//獲取當前日期是其所在年的第幾周(ISO 8601 標準)
public static int GetWeekOfYear(this DateTime dateTime)
{
var currentCulture = CultureInfo.CurrentCulture;
return currentCulture.Calendar.GetWeekOfYear(dateTime, currentCulture.DateTimeFormat.CalendarWeekRule, currentCulture.DateTimeFormat.FirstDayOfWeek);
}
07、獲取當前日期所在月份的週數
該方法實現的核心思想是首先獲取當前日期所在月份的第一天和最後一天,然後分別計算其所在當年第幾周,最後相減即可得到,具體程式碼如下:
//獲取當前日期所在月份的週數
public static int GetWeeksInMonth(this DateTime dateTime)
{
//獲取當前日期所在月的第一天
var firstDayOfMonth = dateTime.GetFirstDayDateTimeOfMonth();
//獲取當前日期所在月的最後一天
var lastDayOfMonth = dateTime.GetLastDayDateTimeOfMonth();
//獲取當月第一天在全年中的週數
var firstWeek = firstDayOfMonth.GetWeekOfYear();
//獲取當月最後一天在全年中的週數
var lastWeek = lastDayOfMonth.GetWeekOfYear();
return lastWeek - firstWeek + 1;
}
08、判斷當前日期是否是週末
該方法比較簡單,只是判斷當前是否是否為週六或週日,具體程式碼如下:
//判斷當前日期是否是週末
public static bool IsWeekend(this DateTime dateTime)
{
return dateTime.DayOfWeek == DayOfWeek.Saturday || dateTime.DayOfWeek == DayOfWeek.Sunday;
}
09、判斷當前日期所在年是否是閏年
該方法呼叫了C#內建方法IsLeapYear,具體程式碼如下:
//判斷當前日期所在年是否是閏年
public static bool IsLeapYear(this DateTime dateTime)
{
return DateTime.IsLeapYear(dateTime.Year);
}
10、獲取當前日期所在季度
該方法也比較簡單,只需要應用一個小公式即可求的,具體程式碼如下:
//獲取當前日期所在季度
public static int GetQuarter(this DateTime dateTime)
{
return (dateTime.Month - 1) / 3 + 1;
}
稍晚些時候我會把庫上傳至Nuget,大家可以直接使用Ideal.Core.Common。
注:測試方法程式碼以及示例原始碼都已經上傳至程式碼庫,有興趣的可以看看。https://gitee.com/hugogoos/Ideal