นี่เป็นความคิดเห็นที่ยาวกว่าในคำตอบของ @Sergey และ @ Steffen เมื่อก่อนฉันเคยเขียนโค้ดที่คล้ายกันในตัวเองฉันตัดสินใจที่จะตรวจสอบสิ่งที่มีประสิทธิภาพมากที่สุดในขณะที่การจดจำความชัดเจนนั้นก็มีความสำคัญเช่นกัน
ผลลัพธ์
นี่คือตัวอย่างผลการทดสอบการทำงานสำหรับการทำซ้ำ 10 ล้านครั้ง:
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()
รหัส
ฉันใช้LINQPad 4 (ในโหมดโปรแกรม C #) เพื่อเรียกใช้การทดสอบโดยเปิดการปรับแต่งคอมไพเลอร์ นี่คือการทดสอบรหัสว่าเป็นวิธีการขยายเพื่อความชัดเจนและความสะดวกสบาย:
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();
}
การวิเคราะห์
ฉันรู้สึกประหลาดใจกับผลลัพธ์เหล่านี้
แม้ว่าจะมีไม่มากนัก แต่FirstDayOfMonth_AddMethod
ก็เร็วกว่าเล็กน้อยFirstDayOfMonth_NewMethod
ในการทดสอบส่วนใหญ่ อย่างไรก็ตามฉันคิดว่าอันหลังมีเจตนาที่ชัดเจนกว่าเล็กน้อยดังนั้นฉันจึงชอบสิ่งนั้น
LastDayOfMonth_AddMethod
เป็นผู้แพ้ที่ชัดเจนกับLastDayOfMonth_AddMethodWithDaysInMonth
, และLastDayOfMonth_NewMethod
LastDayOfMonth_NewMethodWithReuseOfExtMethod
ระหว่างสามคนที่เร็วที่สุดนั้นไม่มีอะไรมากมายดังนั้นมันจึงเหมาะกับความชอบส่วนตัวของคุณ ฉันเลือกความชัดเจนLastDayOfMonth_NewMethodWithReuseOfExtMethod
ด้วยการใช้ส่วนขยายที่เป็นประโยชน์อีกวิธีหนึ่ง IMHO ความตั้งใจของมันชัดเจนขึ้นและฉันยินดีที่จะยอมรับค่าใช้จ่ายเล็กน้อย
LastDayOfMonth_SpecialCase
สมมติว่าคุณให้วันแรกของเดือนในกรณีพิเศษที่คุณอาจคำนวณวันที่แล้วและใช้วิธีการเพิ่มด้วยDateTime.DaysInMonth
เพื่อให้ได้ผลลัพธ์ นี้เร็วกว่ารุ่นอื่น ๆ อย่างที่คุณคาดหวัง แต่ถ้าคุณไม่ต้องการความรวดเร็วฉันไม่เห็นประเด็นที่มีกรณีพิเศษนี้ในคลังแสงของคุณ
ข้อสรุป
นี่คือคลาสวิธีส่วนขยายพร้อมตัวเลือกของฉันและโดยทั่วไปฉันเห็นด้วยกับ @Steffen:
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());
}
}
หากคุณได้มาไกลขนาดนี้ขอบคุณสำหรับเวลา! สนุกแล้ว: ¬) โปรดแสดงความคิดเห็นหากคุณมีข้อเสนอแนะอื่น ๆ สำหรับอัลกอริทึมเหล่านี้
_Date
ตัวแปร คุณพยายาม "ได้รับจำนวนสูงสุด" จากมูลค่านั้นคืออะไร