C# DateTime.AddMonths仅添加月份,不添加天数

C# DateTime.AddMonths仅添加月份,不添加天数,c#,datetime,C#,Datetime,比如说,我有2010年2月28日的并使用AddMonths(1)… 结果日期是3月28日,但不是我想要的3月31日。 有没有办法稍微调整一下,这样就可以在不添加自定义代码的情况下工作 编辑:我不需要一个月的最后一天,实际上我需要添加一个月,但是当它是一个月的最后一天时,我需要找到下个月的最后一天。否-它没有考虑到这一点。这是自定义代码的所有方式 您的代码只对月的最后一天感兴趣,还是希望代码在任何日期中添加一个月,但要考虑提供的日期何时是月的最后一天?尝试重载day属性并将其设置为32。这是用Ja

比如说,我有2010年2月28日的并使用
AddMonths(1)

结果日期是3月28日,但不是我想要的3月31日。
有没有办法稍微调整一下,这样就可以在不添加自定义代码的情况下工作


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

否-它没有考虑到这一点。这是自定义代码的所有方式


您的代码只对月的最后一天感兴趣,还是希望代码在任何日期中添加一个月,但要考虑提供的日期何时是月的最后一天?

尝试重载day属性并将其设置为32。这是用JavaScript实现的,我相信它会默认回到你所在月份的最后一天。

我不知道你想要实现什么,但你可以加上一天,加上一个月,减去一天

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

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

如果您的意思是结果日期应该与该月的结束日期保持相同的距离,则您进入了自定义代码-类似(未完全测试,尤其是28/30/31个月):


我现在解决了这个问题,使用GetLastDayInCurrentMonth检查它是否是一个月的最后一天。如果是这样的话,我用

DateTime nextMonth = date.AddDays(1).AddMonths(1).AddDays(-1);
如果不是最后一天,我只使用AddMonths(1)


谢谢大家

像这样怎么样?它解决了1月30日的问题,该问题将与当前的最佳答案一起出现

if(yourDate.Day == DaysInMonth(yourDate.Year,yourDate.Month)) //check for last day
    yourDate.AddDays(DateTime.DaysInMonth(yourDate.Year,(yourDate.Month+1)%12));
        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);
        }

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

如果日期是唯一的状态,那么无论你如何处理从1月30日起提前一个月的跳跃,你都必须选择是将结果解释为2月的最后一天还是仅仅是当月的28日。你不能两者兼得,因为日期是你唯一的状态。没有“旗帜”告诉你二月二十八日原本是一月的最后一天

实际上,这意味着Jan30.AddMonthCustom(1).AddMonthCustom(1)!=1月30日。如果你继续宣传,那么任何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);
}

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

这个怎么样?作为一种扩展方法,它可以添加任意多个月,即
dateDue.AddSmarthMonths(6)--并将1月28日之后的任何一天视为“本月的最后一天”

public static DateTime AddSmartMonths(此日期时间为d,整数为n个月)
{
int year=d.年;
整月=d.月;
int日=d日;
如果((天==30)和&(天<日期时间.DaysInMonth(年,月)))
d=d.add天(1);
如果((月==1)和&(日>28))
d=新日期时间(年、月、31);
返回d.AddMonths(n个月);
}
并概括为多个月:

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);
    }
}
代码针对二月号、闰年和新年过渡进行了测试。所有测试都通过了

[TestMethod]
公共无效AddMonthTest_一月()
{
对于(inti=1;i你可以试试这个

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

rashleighp的建议几乎正确,但不适用于2016-02-29(结果应为2016-03-31)或2017-02-28(结果应为2017-03-31)增加1个月

此修改版本应适用于所有特殊情况

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);
}
以下所有NUnit测试均通过:

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

这会将numMonths添加到someDate,如果someDate是月末,返回值将是月末,否则它只会添加months(numMonths)


在一行中给出下个月的最后一天:

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.Apr 10),减去1毫秒(=31.Mar 10),如果给定的日期是当月的最后一天,则下面提到的可选截止时间扩展方法将生成当月的最后一天,否则它将在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

您也可以试试这个

int numberofmonths = Convert.ToInt32(textBox2.Text); //number of target months as integer
dateTimePicker1.Text = DateTime.Parse(strDate).Date.AddMonths(numberofmonths).ToString("d"); //new date displayed

如果你想在下个月的同一天保持一致,那么使用以下方法会不会更简单:


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

聪明-如果他保证已经有了月的最后一天,那就行了。如果他没有,结果与1月30日的AddMonths(1)相同,那不是。1月30日有什么解决方案吗?为什么不只是新的日期(date.Year,date.Month,1)AddMonths(1)AddDays(-1)in else?如果有任何答案满足您的需要,请点击旁边的“勾号”接受它。要微调算法:当日期是2月27日或2月1日时,您期望得到什么?是的,月份的最后一天也足够了,我想…我会在答案生效后立即标记:)如果您的意思是设置day属性-它是不可变的(这是C#-请参阅问题上的标记).Woah!抱歉。我不知道你不能在C#中这样做。如果你的约会是在12月呢?@Philippe Leybaert:谢谢你发现了这一点。检查我的编辑。效果很好!扩展方法的最后一行应该是
return startOfNextMonth.AddMonths(months)-delta;
我认为,如果下个月的天数少于当前天数,则会出现问题
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);
}
[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);
}
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);
        }
    }
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}
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);
}
int numberofmonths = Convert.ToInt32(textBox2.Text); //number of target months as integer
dateTimePicker1.Text = DateTime.Parse(strDate).Date.AddMonths(numberofmonths).ToString("d"); //new date displayed