Đây là một nhận xét dài hơn về câu trả lời của @Sergey và @ Steffen. Trước đây tôi đã viết mã tương tự, tôi quyết định kiểm tra xem cái gì hiệu quả nhất trong khi nhớ rằng sự rõ ràng cũng quan trọng.
Kết quả
Dưới đây là kết quả chạy thử nghiệm ví dụ cho 10 triệu lần lặp:
2257 ms for FirstDayOfMonth_AddMethod()
2406 ms for FirstDayOfMonth_NewMethod()
6342 ms for LastDayOfMonth_AddMethod()
4037 ms for LastDayOfMonth_AddMethodWithDaysInMonth()
4160 ms for LastDayOfMonth_NewMethod()
4212 ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()
2491 ms for LastDayOfMonth_SpecialCase()
Mã
Tôi đã sử dụng LINQPad 4 (trong chế độ Chương trình C #) để chạy thử nghiệm với bật tối ưu hóa trình biên dịch. Dưới đây là mã được thử nghiệm bao gồm các phương thức Mở rộng để rõ ràng và thuận tiện:
public static class DateTimeDayOfMonthExtensions
{
public static DateTime FirstDayOfMonth_AddMethod(this DateTime value)
{
return value.Date.AddDays(1 - value.Day);
}
public static DateTime FirstDayOfMonth_NewMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, 1);
}
public static DateTime LastDayOfMonth_AddMethod(this DateTime value)
{
return value.FirstDayOfMonth_AddMethod().AddMonths(1).AddDays(-1);
}
public static DateTime LastDayOfMonth_AddMethodWithDaysInMonth(this DateTime value)
{
return value.Date.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - value.Day);
}
public static DateTime LastDayOfMonth_SpecialCase(this DateTime value)
{
return value.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - 1);
}
public static int DaysInMonth(this DateTime value)
{
return DateTime.DaysInMonth(value.Year, value.Month);
}
public static DateTime LastDayOfMonth_NewMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, DateTime.DaysInMonth(value.Year, value.Month));
}
public static DateTime LastDayOfMonth_NewMethodWithReuseOfExtMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, value.DaysInMonth());
}
}
void Main()
{
Random rnd = new Random();
DateTime[] sampleData = new DateTime[10000000];
for(int i = 0; i < sampleData.Length; i++) {
sampleData[i] = new DateTime(1970, 1, 1).AddDays(rnd.Next(0, 365 * 50));
}
GC.Collect();
System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].FirstDayOfMonth_AddMethod();
}
string.Format("{0} ms for FirstDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].FirstDayOfMonth_NewMethod();
}
string.Format("{0} ms for FirstDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_AddMethod();
}
string.Format("{0} ms for LastDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_AddMethodWithDaysInMonth();
}
string.Format("{0} ms for LastDayOfMonth_AddMethodWithDaysInMonth()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_NewMethod();
}
string.Format("{0} ms for LastDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_NewMethodWithReuseOfExtMethod();
}
string.Format("{0} ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()", sw.ElapsedMilliseconds).Dump();
for(int i = 0; i < sampleData.Length; i++) {
sampleData[i] = sampleData[i].FirstDayOfMonth_AddMethod();
}
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_SpecialCase();
}
string.Format("{0} ms for LastDayOfMonth_SpecialCase()", sw.ElapsedMilliseconds).Dump();
}
Phân tích
Tôi đã ngạc nhiên bởi một số trong những kết quả này.
Mặc dù không có nhiều trong đó nhưng nó FirstDayOfMonth_AddMethod
nhanh hơn một chút so với FirstDayOfMonth_NewMethod
hầu hết các lần chạy thử. Tuy nhiên, tôi nghĩ rằng cái sau có một ý định rõ ràng hơn một chút và vì vậy tôi có một sở thích cho điều đó.
LastDayOfMonth_AddMethod
là một kẻ thua cuộc rõ ràng chống lại LastDayOfMonth_AddMethodWithDaysInMonth
, LastDayOfMonth_NewMethod
và LastDayOfMonth_NewMethodWithReuseOfExtMethod
. Giữa ba người nhanh nhất không có gì nhiều trong đó và do đó, nó tùy thuộc vào sở thích cá nhân của bạn. Tôi chọn sự rõ ràng LastDayOfMonth_NewMethodWithReuseOfExtMethod
với việc sử dụng lại một phương pháp mở rộng hữu ích khác. IMHO ý định của nó rõ ràng hơn và tôi sẵn sàng chấp nhận chi phí hiệu suất nhỏ.
LastDayOfMonth_SpecialCase
giả sử bạn đang cung cấp ngày đầu tiên của tháng trong trường hợp đặc biệt mà bạn có thể đã tính ngày đó và nó sử dụng phương thức add với DateTime.DaysInMonth
để có kết quả. Điều này nhanh hơn các phiên bản khác, như bạn mong đợi, nhưng trừ khi bạn đang rất cần tốc độ, tôi không thấy vấn đề có trường hợp đặc biệt này trong kho vũ khí của bạn.
Phần kết luận
Đây là lớp phương thức mở rộng với các lựa chọn của tôi và theo thỏa thuận chung với @Steffen tôi tin rằng:
public static class DateTimeDayOfMonthExtensions
{
public static DateTime FirstDayOfMonth(this DateTime value)
{
return new DateTime(value.Year, value.Month, 1);
}
public static int DaysInMonth(this DateTime value)
{
return DateTime.DaysInMonth(value.Year, value.Month);
}
public static DateTime LastDayOfMonth(this DateTime value)
{
return new DateTime(value.Year, value.Month, value.DaysInMonth());
}
}
Nếu bạn đã đạt được điều này, cảm ơn bạn đã dành thời gian! Thật là vui:). Hãy bình luận nếu bạn có bất kỳ đề xuất nào khác cho các thuật toán này.
_Date
biến. "Tối thiểu và tối đa" bạn đang cố gắng để có được từ giá trị đó là gì?