Ini lebih merupakan komentar panjang tentang jawaban @Sergey dan @ Steffen. Setelah menulis kode yang sama sendiri di masa lalu, saya memutuskan untuk memeriksa apa yang paling performan sambil mengingat bahwa kejelasan juga penting.
Hasil
Berikut ini adalah contoh hasil uji coba untuk 10 juta iterasi:
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()
Kode
Saya menggunakan LINQPad 4 (dalam mode Program C #) untuk menjalankan tes dengan optimasi kompiler dihidupkan. Berikut adalah kode yang diuji yang diperhitungkan sebagai metode Ekstensi untuk kejelasan dan kenyamanan:
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();
}
Analisis
Saya terkejut dengan beberapa hasil ini.
Meskipun tidak banyak di dalamnya, FirstDayOfMonth_AddMethod
itu sedikit lebih cepat daripada FirstDayOfMonth_NewMethod
di sebagian besar menjalankan tes. Namun, saya pikir yang terakhir memiliki niat yang sedikit lebih jelas sehingga saya memiliki preferensi untuk itu.
LastDayOfMonth_AddMethod
jelas kalah melawan LastDayOfMonth_AddMethodWithDaysInMonth
, LastDayOfMonth_NewMethod
dan LastDayOfMonth_NewMethodWithReuseOfExtMethod
. Antara tiga tercepat tidak ada banyak di dalamnya sehingga turun ke preferensi pribadi Anda. Saya memilih kejelasan LastDayOfMonth_NewMethodWithReuseOfExtMethod
dengan menggunakan kembali metode ekstensi lain yang bermanfaat. IMHO maksudnya lebih jelas dan saya bersedia menerima biaya kinerja yang kecil.
LastDayOfMonth_SpecialCase
mengasumsikan Anda memberikan yang pertama bulan dalam kasus khusus di mana Anda mungkin sudah menghitung tanggal itu dan menggunakan metode add dengan DateTime.DaysInMonth
untuk mendapatkan hasilnya. Ini lebih cepat daripada versi lain, seperti yang Anda harapkan, tetapi kecuali Anda sangat membutuhkan kecepatan, saya tidak melihat gunanya memiliki case khusus ini di gudang senjata Anda.
Kesimpulan
Berikut ini adalah kelas metode ekstensi dengan pilihan saya dan dalam perjanjian umum dengan @Steffen saya percaya:
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());
}
}
Jika Anda sudah sejauh ini, terima kasih atas waktunya! Sudah menyenangkan: ¬). Berikan komentar jika Anda memiliki saran lain untuk algoritme ini.
_Date
variabel. Apa "min dan maks" yang Anda coba dapatkan dari nilai itu?