2010-06-17 12 views
12

Digamos, tengo 28a de de febrero de 2010 y añadir un mes para esta fecha usando AddMonths(1) ...
la fecha resultante es 28a de marzo de, pero no 31 de Marzo, que yo quiero.
¿Hay alguna manera de modificar eso un poco para que esto funcione sin agregar código personalizado?DateTime.AddMonths añadiendo solamente no meses días

Editar: No necesito el último día de un mes, en realidad necesito agregar un mes, pero cuando es el último día de un mes, necesito encontrar el último día del mes siguiente.

+2

Si ninguna respuesta satisface sus necesidades por favor, pulse la "señal" al lado de él para aceptarlo. –

+1

Para sintonizar el algoritmo: ¿Y qué espera cuando la fecha sea el 27 de febrero o el 1 de febrero? – GvS

Respuesta

30

no sé lo que desea lograr, pero puede agregar un día, agregar un mes y restar un día.

DateTime nextMonth = date.AddDays(1).AddMonths(1).AddDays(-1); 

EDITAR:

Como uno de los comentaristas señala, esto a veces da un resultado erróneo. Después de leer su pregunta actualizada, creo que la forma más fácil de calcular la fecha en que desea es:

public static DateTime NextMonth(this DateTime date) 
{ 
    if (date.Day != DateTime.DaysInMonth(date.Year, date.Month)) 
     return date.AddMonths(1); 
    else 
     return date.AddDays(1).AddMonths(1).AddDays(-1); 
} 

Esta extensión método devuelve la fecha del próximo mes. Cuando la fecha actual sea el último día del mes, regresará el último día del mes siguiente.

+0

Inteligente: eso funcionaría si ya tiene garantizado el último día del mes. –

+4

Si no lo hace, el resultado es el mismo que AddMonths (1) –

+4

Para el 30 de enero, no lo es. –

0

No, no tiene eso en cuenta. ¡Es un código personalizado hasta el final!

¿Su código solo estará interesado en el último día de meses, o desea que el código agregue un mes a cualquier fecha, pero tenga en cuenta cuándo la fecha suministrada es el último día del mes?

+0

Sí, el último día de los meses también sería suficiente, creo ... Voy a marcar la respuesta tan pronto como funcione :) – grady

+1

Ver mi edición de la publicación original – grady

-1

Try sobrecargar la propiedad día y se establece a 32. Whgen esto se hace en JavaScript, yo creo que por defecto se remontan al último día de cualquier mes en el que se encuentre.

+0

Si se refiere a * establecer * la propiedad del día - es inmutable (esto es C# - vea las etiquetas en la pregunta). –

+0

Woah! Lo siento. No me di cuenta de que no podías hacer eso en C#. – Sam

6

Si quiere decir que la fecha resultante debe ser la misma distancia desde el final del mes, entonces está en el código personalizado, algo así como (no completamente probado, especialmente re 28/30/31 meses):

class Program 
{ 
    static void Main() 
    { 
     var when = DateTime.Today; 
     DateTime fromEndOfNextMonth = when.AddMonthsRelativeToEndOfMonth(1); 
    } 

} 
public static class DateTimeExtensions 
{ 
    public static DateTime AddMonthsRelativeToEndOfMonth(
       this DateTime when, int months) 
    { 
     if (months == 0) return when; 
     DateTime startOfNextMonth = when; 
     int month = when.Month; 
     while (startOfNextMonth.Month == month) 
     { 
      startOfNextMonth = startOfNextMonth.AddDays(1); 
     } 
     TimeSpan delta = startOfNextMonth - when; 
     return startOfNextMonth.AddMonths(1) - delta; 
    } 

} 
0

lo resuelto ahora, comprobando si es el último día de un mes usando GetLastDayInCurrentMonth. Si ése es el caso, yo uso

DateTime nextMonth = date.AddDays(1).AddMonths(1).AddDays(-1); 

Si este no es el último día, sólo tiene que utilizar AddMonths (1)

Gracias chicos!

0
if(yourDate.Day == DaysInMonth(yourDate.Year,yourDate.Month)) //check for last day 
    yourDate.AddDays(DateTime.DaysInMonth(yourDate.Year,(yourDate.Month+1)%12)); 
+0

¿Qué pasa si su fecha es en diciembre? –

+0

@Philippe Leybaert: Gracias por descubrirlo. revisa mi edición – Amsakanna

0
public static class DateTimeExtensions 
{ 
    public static DateTime AddMonthsCustom(this DateTime source, int months) 
    { 
     DateTime result = source.AddMonths(months); 
     if (source.Day != DateTime.DaysInMonth(source.Year, source.Month)) 
      return result; 

     return new DateTime(result.Year, result.Month, 
          DateTime.DaysInMonth(result.Year, result.Month), 
          result.Hour, result.Minute, result.Second, 
          result.Millisecond, result.Kind); 
    } 
} 
2

¿Qué hay de esta manera? Resuelve el problema del 30 de enero que ocurriría con la mejor respuesta actual.

 public static DateTime AddJustMonths(this DateTime @this, int months) 
     { 
      var firstDayOfTargetMonth = new DateTime(@this.Year, @this.Month, 1).AddMonths(months); 
      var lastDayofTargetMonth = DateTime.DaysInMonth(firstDayOfTargetMonth.Year, firstDayOfTargetMonth.Month); 

      var targetDay = @this.Day > lastDayofTargetMonth ? lastDayofTargetMonth : @this.Day; 

      return new DateTime(firstDayOfTargetMonth.Year, firstDayOfTargetMonth.Month, targetDay); 
     } 
2

Este código se sumará el número de meses y saltará al último día del mes de destino si el día actual es el último día del mes en curso.Tenga en cuenta que hay fundamentalmente ninguna solución al problema del 30 de enero sin hacer fechas totalmente personalizadas:

Si la fecha es el único estado, entonces no importa cómo maneje el salto de un mes desde el 30 de enero, tiene para elegir si interpreta el resultado como el último día de febrero o simplemente el el 28 del mes actual. No puede tener ambas, ya que la fecha es su único estado. No existe una "bandera" que indique que este 28 de febrero fue originalmente el día del día 1 al último de enero de.

Efectivamente, esto significa que Jan30.AddMonthsCustom (1) .AddMonthsCustom (1)! = Jan30.AddMonthsCustom (2) y que eventualmente cualquier fecha 30, 29 y 28 termina en el último día del mes si sigue propagándose .

public static DateTime AddMonthsCustom(this DateTime date, int months) 
{ 

    // Check if we are done quickly. 
    if(months == 0) 
     return; 

    // Lookup the target month and its last day. 
    var targetMonth = new DateTime(date.Year, date.Month, 1).AddMonths(months); 
    var lastDay = DateTime.DaysInMonth(targetMonth.Year, targetMonth.Month); 

    // If we are starting out on the last day of the current month, then jump 
    // to the last day of the target month. 
    if (date.Day == DateTime.DaysInMonth(date.Year, date.Month)) 
     return new DateTime(targetMonth.Year, targetMonth.Month, lastDay); 

    // If the target month cannot accomodate the current day, jump to the 
    // last day of the target month. 
    if (date.Day > lastDay) 
     return new DateTime(targetMonth.Year, targetMonth.Month, lastDay); 

    // Simply jump to the current day in the target month. 
    return new DateTime(targetMonth.Year, targetMonth.Month, date.Day); 
} 

Si estoy equivocado, hágamelo saber. Realmente me gustaría tener esto resuelto.

0

¿Qué tal esto? Puede agregar tantos meses como desee como método de extensión, es decir, dateDue.AddSmarthMonths(6);, y considera cualquier día de enero posterior a 28 "el último día del mes".

public static DateTime AddSmartMonths(this DateTime d, int nMonths) 
    { 
     int year = d.Year; 
     int month = d.Month; 
     int day = d.Day; 

     if ((day == 30) && (day < DateTime.DaysInMonth(year, month))) 
      d = d.AddDays(1); 
     else if ((month == 1) && (day > 28)) 
      d = new DateTime(year, month, 31); 

     return d.AddMonths(nMonths); 
    } 
1
public static DateTime NextMonth(DateTime date) 
{ 
    DateTime nextMonth = date.AddMonths(1); 

    if (date.Day != DateTime.DaysInMonth(date.Year, date.Month)) //is last day in month 
    { 
     //any other day then last day 
     return nextMonth; 
    } 
    else 
    { 
     //last day in the month will produce the last day in the next month 
     return date.AddDays(DateTime.DaysInMonth(nextMonth.Year, nextMonth.Month)); 
    } 
} 

y generalizada para varios meses:

public static DateTime AddMonthToEndOfMonth(DateTime date, int numberOfMonths) 
{ 
    DateTime nextMonth = date.AddMonths(numberOfMonths); 

    if (date.Day != DateTime.DaysInMonth(date.Year, date.Month)) //is last day in month 
    { 
     //any other day then last day 
     return nextMonth; 
    } 
    else 
    { 
     //if date was end of month, add remaining days 
     int addDays = DateTime.DaysInMonth(nextMonth.Year, nextMonth.Month) - nextMonth.Day; 
     return nextMonth.AddDays(addDays); 
    } 
} 

El código se prueba contra los problemas de febrero, año bisiesto y la transición de Año Nuevo. Toda la prueba pasó.

enter image description here

[TestMethod] 
public void AddMonthTest_January() 
{ 
    for (int i = 1; i <= 28; i++) 
    { 
     Assert.AreEqual(new DateTime(2015, 2, i), NextMonth(new DateTime(2015, 1, i))); 
    } 
    Assert.AreEqual(new DateTime(2015, 2, 28), NextMonth(new DateTime(2015, 1, 29))); 
    Assert.AreEqual(new DateTime(2015, 2, 28), NextMonth(new DateTime(2015, 1, 30))); 
    Assert.AreEqual(new DateTime(2015, 2, 28), NextMonth(new DateTime(2015, 1, 31))); 
} 

[TestMethod] 
public void AddMonthTest_February() 
{ 
    Assert.AreEqual(new DateTime(2015, 3, 31), NextMonth(new DateTime(2015, 2, 28))); 

    for (int i = 1; i <= 27; i++) 
    { 
     Assert.AreEqual(new DateTime(2015, 3, i), NextMonth(new DateTime(2015, 2, i))); 
    }    
} 

[TestMethod] 
public void AddMonthTest_March() 
{ 
    Assert.AreEqual(new DateTime(2015, 4, 30), NextMonth(new DateTime(2015, 3, 31))); 

    for (int i = 1; i <= 30; i++) 
    { 
     Assert.AreEqual(new DateTime(2015, 4, i), NextMonth(new DateTime(2015, 3, i))); 
    } 
} 

[TestMethod] 
public void AddMonthTest_December() 
{    
    for (int i = 1; i <= 31; i++) 
    { 
     Assert.AreEqual(new DateTime(2016, 1, i), NextMonth(new DateTime(2015, 12, i))); 
    } 
} 

[TestMethod] 
public void AddMonthTest_January_LeapYear() 
{ 
    for (int i = 1; i <= 29; i++) 
    { 
     Assert.AreEqual(new DateTime(2016, 2, i), NextMonth(new DateTime(2016, 1, i))); 
    }    
    Assert.AreEqual(new DateTime(2016, 2, 29), NextMonth(new DateTime(2016, 1, 30))); 
    Assert.AreEqual(new DateTime(2016, 2, 29), NextMonth(new DateTime(2016, 1, 31))); 
} 

[TestMethod] 
public void AddMonthTest_February_LeapYear() 
{ 
    Assert.AreEqual(new DateTime(2016, 3, 31), NextMonth(new DateTime(2016, 2, 29))); 

    for (int i = 1; i <= 28; i++) 
    { 
     Assert.AreEqual(new DateTime(2016, 3, i), NextMonth(new DateTime(2016, 2, i))); 
    } 
} 

[TestMethod] 
public void AddHalfYearTest_January_LeapYear() 
{   
    for (int i = 1; i <= 31; i++) 
    { 
     Assert.AreEqual(new DateTime(2016, 7, i), new DateTime(2016, 1, i).AddMonthToEndOfMonth(6)); 
    } 
} 

[TestMethod] 
public void AddHalfYearTest_February_LeapYear() 
{ 
    Assert.AreEqual(new DateTime(2016, 8, 31), new DateTime(2016, 2, 29).AddMonthToEndOfMonth(6)); 

    for (int i = 1; i <= 28; i++) 
    { 
     Assert.AreEqual(new DateTime(2016, 8, i), new DateTime(2016, 2, i).AddMonthToEndOfMonth(6)); 
    } 
} 

[TestMethod] 
public void AddHalfYearTest_December() 
{ 
    Assert.AreEqual(new DateTime(2016, 6, 30), new DateTime(2015, 12, 31).AddMonthToEndOfMonth(6)); 
    for (int i = 1; i <= 30; i++) 
    { 
     Assert.AreEqual(new DateTime(2016, 6, i), new DateTime(2015, 12, i).AddMonthToEndOfMonth(6)); 
    } 
} 
0

puede probar esta

private void datTimPkerFrom_ValueChanged(object sender, EventArgs e) 
{ 
    int DaysInMonth = DateTime.DaysInMonth(datTimPkerFrom.Value.Year, datTimPkerFrom.Value.Month); 

    if (DaysInMonth == 31) 
    { 
     datTimPkerTo.Value = datTimPkerFrom.Value.AddDays(30); 
    } 
    else if (DaysInMonth == 30) 
    { 
     datTimPkerTo.Value = datTimPkerFrom.Value.AddDays(29); 
    } 
    else if (DaysInMonth == 29) 
    { 
     datTimPkerTo.Value = datTimPkerFrom.Value.AddDays(28); 
    } 
    else 
    { 
     datTimPkerTo.Value = datTimPkerFrom.Value.AddDays(27); 
    } 
} 
1

Lo que sugiere rashleighp es casi correcta, pero no funciona para, por ejemplo, agregando 1 mes a 2016-02-29 (el resultado debe ser 2016-03-31) o 2017-02-28 (el resultado debe ser 2017-03-31)

Esta versión modificada debería funcionar incluyendo todos los casos especiales.

public static DateTime AddMonthsCustom(this DateTime source, int months) 
{ 
    var firstDayOfTargetMonth = new DateTime(source.Year, source.Month, 1).AddMonths(months); 
    var lastDayofSourceMonth = DateTime.DaysInMonth(source.Year, source.Month); 
    var lastDayofTargetMonth = DateTime.DaysInMonth(firstDayOfTargetMonth.Year, firstDayOfTargetMonth.Month); 

    var targetDay = source.Day > lastDayofTargetMonth ? lastDayofTargetMonth : source.Day; 
    if (source.Day == lastDayofSourceMonth) 
     targetDay = lastDayofTargetMonth; 

    return new DateTime(
     firstDayOfTargetMonth.Year, 
     firstDayOfTargetMonth.Month, 
     targetDay, 
     source.Hour, 
     source.Minute, 
     source.Second, 
     source.Millisecond, 
     source.Kind); 
} 

Todas las pruebas NUnit debajo pasado:

[TestCase("2017-01-01T01:01:01.0010000Z", "2016-12-01T01:01:01.0010000Z", 1)] 
[TestCase("2017-02-01T01:01:01.0010000Z", "2016-12-01T01:01:01.0010000Z", 2)] 
[TestCase("2017-03-31T01:01:01.0010000Z", "2016-12-31T01:01:01.0010000Z", 3)] 
[TestCase("2016-03-28T01:01:01.0010000Z", "2016-02-28T01:01:01.0010000Z", 1)] 
[TestCase("2016-03-31T01:01:01.0010000Z", "2016-02-29T01:01:01.0010000Z", 1)] 
[TestCase("2017-03-31T01:01:01.0010000Z", "2017-02-28T01:01:01.0010000Z", 1)] 
[TestCase("2016-02-29T01:01:01.0010000Z", "2016-01-31T01:01:01.0010000Z", 1)] 
[TestCase("2017-02-28T01:01:01.0010000Z", "2017-01-31T01:01:01.0010000Z", 1)] 
[TestCase("2016-12-01T01:01:01.0010000Z", "2017-01-01T01:01:01.0010000Z", -1)] 
[TestCase("2016-12-01T01:01:01.0010000Z", "2017-02-01T01:01:01.0010000Z", -2)] 
[TestCase("2016-12-31T01:01:01.0010000Z", "2017-03-31T01:01:01.0010000Z", -3)] 
[TestCase("2016-02-28T01:01:01.0010000Z", "2016-03-28T01:01:01.0010000Z", -1)] 
public void DateTimeExtensions_AddMonthsCustom(DateTime expected, DateTime dateTime, int months) 
{ 
    // Arrange 
    expected = expected.ToUniversalTime(); 
    dateTime = dateTime.ToUniversalTime(); 

    // Act 
    DateTime result = dateTime.AddMonthsCustom(months); 

    // Assert 
    Assert.AreEqual(expected.Kind, result.Kind); 
    Assert.AreEqual(expected, result); 
} 
Cuestiones relacionadas