Il s'agit plutôt d'un long commentaire sur les réponses de @Sergey et @ Steffen. Ayant écrit moi-même un code similaire dans le passé, j'ai décidé de vérifier ce qui était le plus performant tout en se rappelant que la clarté est également importante.
Résultat
Voici un exemple de résultat de test pour 10 millions d'itérations:
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
J'ai utilisé LINQPad 4 (en mode programme C #) pour exécuter les tests avec l'optimisation du compilateur activée. Voici le code testé pris en compte comme méthodes d'extension pour plus de clarté et de commodité:
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();
}
Une analyse
J'ai été surpris par certains de ces résultats.
Bien qu'il n'y ait pas grand-chose, il FirstDayOfMonth_AddMethod
était légèrement plus rapide que FirstDayOfMonth_NewMethod
dans la plupart des tests. Cependant, je pense que ce dernier a une intention légèrement plus claire et j'ai donc une préférence pour cela.
LastDayOfMonth_AddMethod
était un perdant clair contre LastDayOfMonth_AddMethodWithDaysInMonth
, LastDayOfMonth_NewMethod
et LastDayOfMonth_NewMethodWithReuseOfExtMethod
. Entre les trois plus rapides, il n'y a pas grand-chose et cela dépend donc de vos préférences personnelles. Je choisis la clarté de LastDayOfMonth_NewMethodWithReuseOfExtMethod
sa réutilisation d'une autre méthode d'extension utile. À mon humble avis, son intention est plus claire et je suis prêt à accepter le faible coût de performance.
LastDayOfMonth_SpecialCase
suppose que vous fournissez le premier du mois dans le cas particulier où vous avez peut-être déjà calculé cette date et utilise la méthode add avec DateTime.DaysInMonth
pour obtenir le résultat. C'est plus rapide que les autres versions, comme vous vous en doutez, mais à moins que vous n'ayez désespérément besoin de vitesse, je ne vois pas l'intérêt d'avoir ce cas spécial dans votre arsenal.
Conclusion
Voici une classe de méthode d'extension avec mes choix et en accord général avec @Steffen je crois:
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());
}
}
Si vous êtes arrivé jusqu'ici, merci pour le temps! C'est amusant: ¬). Veuillez commenter si vous avez d'autres suggestions pour ces algorithmes.
_Date
variable. Quel "minimum et maximum" essayez-vous d'obtenir de cette valeur?