Dies ist eher ein langer Kommentar zu den Antworten von @Sergey und @ Steffen. Nachdem ich in der Vergangenheit selbst ähnlichen Code geschrieben hatte, entschied ich mich zu überprüfen, was am performantesten war, während ich mich daran erinnerte, dass Klarheit ebenfalls wichtig ist.
Ergebnis
Hier ist ein Beispiel für ein Testergebnis für 10 Millionen Iterationen:
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()
Code
Ich habe LINQPad 4 (im C # -Programmmodus) verwendet, um die Tests mit aktivierter Compileroptimierung auszuführen. Hier ist der getestete Code, der aus Gründen der Klarheit und Bequemlichkeit als Erweiterungsmethode berücksichtigt wird:
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();
}
Analyse
Einige dieser Ergebnisse haben mich überrascht.
Obwohl nicht viel drin ist, FirstDayOfMonth_AddMethod
war das etwas schneller als FirstDayOfMonth_NewMethod
in den meisten Testläufen. Ich denke jedoch, dass Letzteres eine etwas klarere Absicht hat, und deshalb bevorzuge ich das.
LastDayOfMonth_AddMethod
war ein klarer Verlierer gegen LastDayOfMonth_AddMethodWithDaysInMonth
, LastDayOfMonth_NewMethod
und LastDayOfMonth_NewMethodWithReuseOfExtMethod
. Zwischen den schnellsten drei ist nicht viel drin und es kommt auf Ihre persönlichen Vorlieben an. Ich wähle die Klarheit LastDayOfMonth_NewMethodWithReuseOfExtMethod
mit der Wiederverwendung einer anderen nützlichen Erweiterungsmethode. IMHO ist seine Absicht klarer und ich bin bereit, die geringen Leistungskosten zu akzeptieren.
LastDayOfMonth_SpecialCase
Angenommen, Sie geben den ersten des Monats in dem speziellen Fall an, in dem Sie dieses Datum möglicherweise bereits berechnet haben, und es verwendet die Add-Methode mit DateTime.DaysInMonth
, um das Ergebnis zu erhalten. Dies ist schneller als die anderen Versionen, wie Sie es erwarten würden, aber wenn Sie nicht dringend Geschwindigkeit brauchen, sehe ich keinen Sinn darin, diesen Sonderfall in Ihrem Arsenal zu haben.
Fazit
Hier ist eine Erweiterungsmethodenklasse mit meinen Auswahlmöglichkeiten und in allgemeiner Übereinstimmung mit @Steffen glaube ich:
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());
}
}
Wenn Sie so weit gekommen sind, danke für die Zeit! Es hat Spaß gemacht: ¬). Bitte kommentieren Sie, wenn Sie weitere Vorschläge für diese Algorithmen haben.
_Date
Variablen ist ein einzelner Wert gespeichert . Welche "Min und Max" versuchen Sie von diesem Wert zu bekommen?