Это более длинный комментарий к ответам @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
для получения результата использует метод add with . Это быстрее, чем другие версии, как и следовало ожидать, но если вы не остро нуждаетесь в скорости, я не вижу смысла иметь этот особый случай в вашем арсенале.
Вывод
Вот класс метода расширения с моим выбором и в целом согласен с @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
переменной хранится одно значение . Какие «минимальные и максимальные значения» вы пытаетесь получить из этого значения?