Це більше довгий коментар до відповідей @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
змінній зберігається одне значення . Які "хв і макс" ви намагаєтеся отримати від цього значення?