Este es más un comentario largo sobre las respuestas de @Sergey y @ Steffen. Habiendo escrito un código similar en el pasado, decidí verificar lo que era más eficiente mientras recordaba que la claridad también es importante.
Resultado
Aquí hay un ejemplo de un resultado de ejecución de prueba para 10 millones de iteraciones:
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()
Código
Solía LINQPad 4 (en C # modo de programa) para ejecutar las pruebas con la optimización del compilador de encendido. Aquí está el código probado factorizado como métodos de extensión para mayor claridad y conveniencia:
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();
}
Análisis
Me sorprendieron algunos de estos resultados.
Aunque no hay mucho, FirstDayOfMonth_AddMethod
fue un poco más rápido que FirstDayOfMonth_NewMethod
en la mayoría de las pruebas. Sin embargo, creo que este último tiene una intención un poco más clara y por eso tengo preferencia por eso.
LastDayOfMonth_AddMethod
fue un claro perdedor contra LastDayOfMonth_AddMethodWithDaysInMonth
, LastDayOfMonth_NewMethod
y LastDayOfMonth_NewMethodWithReuseOfExtMethod
. Entre los tres más rápidos no hay mucho, por lo que se reduce a su preferencia personal. Elijo la claridad LastDayOfMonth_NewMethodWithReuseOfExtMethod
con la reutilización de otro método de extensión útil. En mi humilde opinión, su intención es más clara y estoy dispuesto a aceptar el pequeño costo de rendimiento.
LastDayOfMonth_SpecialCase
supone que está proporcionando el primer día del mes en el caso especial en el que ya haya calculado esa fecha y utiliza el método add DateTime.DaysInMonth
para obtener el resultado. Esto es más rápido que las otras versiones, como era de esperar, pero a menos que tenga una necesidad desesperada de velocidad, no veo el punto de tener este caso especial en su arsenal.
Conclusión
Aquí hay una clase de método de extensión con mis elecciones y, en general, de acuerdo con @Steffen, creo:
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 has llegado hasta aquí, ¡gracias por tu tiempo! Ha sido divertido: ¬). Comente si tiene alguna otra sugerencia para estos algoritmos.
_Date
variable. ¿Qué "mínimo y máximo" estás tratando de obtener de ese valor?