DateTime.AddMonths仅添加月而不是天

时间:2010-06-17 09:26:52

标签: c# datetime

假设我已经 2010年2月28日,并使用AddMonths(1)在此日期添加一个月... ... 结果日期 3月28日,但不是 3月31日,这是我想要的。
有没有办法调整一点,所以这可以工作而不添加自定义代码?

编辑:我不需要一个月的最后一天,实际上我需要添加一个月,但是当它是一个月的最后一天时,我需要找到下个月的最后一天。

18 个答案:

答案 0 :(得分:36)

我不知道你想要达到什么目标,但你可以添加一天,增加一个月并减去一天。

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

修改

正如其中一位评论者指出的那样,这有时会产生错误的结果。在阅读更新后的问题后,我认为计算所需日期的最简单方法是:

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);
}

此扩展方法返回下个月的日期。当前日期是该月的最后一天,它将返回下个月的最后一天。

答案 1 :(得分:7)

如果你的意思是结果日期与该月的结束的距离相同,那么你就会进入自定义代码 - 类似于(未经过全面测试,特别是28/30 / 31个月):

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;
    }

}

答案 2 :(得分:4)

这样怎么样?它解决了当前最佳答案会出现的1月30日问题。

        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);
        }

答案 3 :(得分:3)

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));
    }
}

并推广了几个月:

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);
    }
}

该代码针对2月问题,闰年和新年过渡进行测试。所有测试都通过了。

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));
    }
}

答案 4 :(得分:2)

此代码将添加月数,如果当前日期是当月的最后一天,则会跳转到目标月份的最后一天。请注意,在没有完全自定义日期的情况下,1月30日的问题基本上没有解决方案

如果日期是唯一的状态,那么无论您如何处理1月30日前一个月的跳跃,您必须选择是否将结果解释为 2月的最后一天或简单当月的第28天。你不能同时拥有这两个,因为日期是你唯一的状态。没有标志&#39;它告诉你,2月28日最初是1月份的单一到最后一天

实际上这意味着Jan30.AddMonthsCustom(1).AddMonthsCustom(1)!= Jan30.AddMonthsCustom(2),如果你继续传播,那么最终任何第30,29和28日结束于该月的最后一天。

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);
}

如果我错了,请告诉我。我真的很想解决这个问题。

答案 5 :(得分:1)

rashleighp建议几乎是正确的,但对于例如加入1个月到2016-02-29(结果应该是2016-03-31)或者2017-02-28(结果应该是2017-03-31)

此修改版本应该包括所有特殊情况。

Package: Amelia
Version: 1.7.4
Depends: R (>= 3.0.2), Rcpp (>= 0.11)
Imports: foreign, utils, grDevices, graphics, methods, stats
LinkingTo: Rcpp (>= 0.11), RcppArmadillo
Suggests: tcltk, Zelig
License: GPL (>= 2)
Archs: i386, x64

Package: BH
Version: 1.60.0-1
License: BSL-1.0

以下所有NUnit测试都通过了:

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);
}

答案 6 :(得分:0)

这个怎么样?它可以添加任意数月作为扩展方法 - 即dateDue.AddSmarthMonths(6); - 并考虑在“月的最后一天”28之后的1月的任何一天。

    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);
    }

答案 7 :(得分:0)

如果您想总是在下个月的同一天,使用它会不会更简单:

DateTime nextMonth = new DateTime(thisMonth.Year, thisMonth.Month + 1, thisMonth.Day);

答案 8 :(得分:0)

您也可以尝试

src="../js/main.js"

答案 9 :(得分:0)

以下提到的扩展方法将产生月份的最后一天,如果给定的日期是该月的最后一天,则使用datetime API。

public static DateTime AddMonthsE(this DateTime value,int numberOfMonths)
{           
    bool isEndDate = DateTime.DaysInMonth(value.Year, value.Month) == value.Day;
    if(isEndDate)
    {
        var newDateTime = value.AddMonths(numberOfMonths);
        return new DateTime(newDateTime.Year, newDateTime.Month, DateTime.DaysInMonth(newDateTime.Year, newDateTime.Month));
    }
    return value.AddMonths(numberOfMonths);
}

输入:2010年2月28日上午12:00:00 输出加上1个月的时间2010年3月31日上午12:00:00

答案 10 :(得分:0)

将下个月的最后一天放在一行:

var t1 = new DateTime(2010,2,28); 
var t2 = t1.AddDays((t1.Day * -1) + 1).AddMonths(2).AddMilliseconds(-1).Date;
// t2: {31.03.2010 00:00:00}

(操作是:获取当月的第一天(= 1.Feb 10),添加2个月(= 1. 4月10日),减去1 ms(= 31。3月10日),可选截止时间

答案 11 :(得分:0)

This will add numMonths to someDate and, if someDate is end-of-month, return value will be end-of-month, otherwise it just does AddMonths(numMonths)

private DateTime AddMonthsRetainingEOM(DateTime someDate, int numMonths)
    {
        if (someDate.AddDays(1).Day == 1)
        {
            // someDate is EOM
            someDate = someDate.AddMonths(numMonths);
            // keep adding days if new someDate is not EOM
            while (someDate.AddDays(1).Day != 1)
            {
                someDate = someDate.AddDays(1);
            }
            return someDate;
        }
        else
        {
            // not EOM - Just add months
            return someDate.AddMonths(numMonths);
        }
    }

答案 12 :(得分:0)

你可以试试这个

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);
    }
}

答案 13 :(得分:0)

不 - 它没有考虑到这一点。这是自定义代码!

您的代码是否只对几个月的最后一天感兴趣,或者您是否希望代码在任何日期添加一个月,但是在提供的日期是该月的最后一天时会考虑?

答案 14 :(得分: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);
    }
}

答案 15 :(得分:0)

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

答案 16 :(得分:0)

我现在通过使用 GetLastDayInCurrentMonth 检查它是否是一个月的最后一天来解决它。如果是这样,我使用

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

如果不是最后一天,我只使用AddMonths(1)

谢谢你们!

答案 17 :(得分:-1)

尝试重载day属性并将其设置为32.如果在JavaScript中完成此操作,我相信它会默认返回到您所在月份的最后一天。