一起添加两个DateTime对象

时间:2015-01-21 12:27:06

标签: c# datetime add

有没有更好的方法将一个DateTime对象添加到另一个,而不是:

DateTime first = new DateTime(2000, 1, 1);
DateTime second = new DateTime(11, 2, 5, 10, 10, 11);

DateTime result = first.AddYears(second.Year);
DateTime result = first.AddMonths(second.Month);
...

依旧......

在此示例中,我想获得DateTime(2011, 3, 6, 10, 10, 11)

修改

经过密集的头脑风暴之后,似乎没有什么不同的方式,但是为了方便它可以装在额外的班级和操作员里面,就像在JonSkeet的回答中一样

3 个答案:

答案 0 :(得分:36)

将两个DateTime值一起添加是没有意义的。如果你想表示" 11年,2个月,5天,10个小时,10分钟和11秒"那么你应该代表那个。那个与0011-02-05T10:10:11相同。特别是,您永远无法添加" 2个月和30天"例如。同样,您永远无法添加一年,因为您在一个日期内的月值和日期值不能为0。

现在没有BCL类型来表示" 11年[...]"但你可以很容易地创建自己的。作为替代方案,您可以使用具有Period的{​​{3}}项目来实现此目的:

var localDateTime = new LocalDate(2000, 1, 10).AtMidnight();
var period = new PeriodBuilder {
    Years = 11, Months = 2, Days = 5,
    Hours = 10, Minutes = 10, Seconds = 11
}.Build();
var result = localDateTime + period;

与此处提供的其他一些答案相反,无法使用TimeSpan来实现此目的。 TimeSpan没有任何月份和年份的概念,因为它们的长度不同,而TimeSpan表示固定数量的刻度。 (如果您的最大单位是天数,那么您可以使用TimeSpan,但是根据您的示例,我认为您需要数月和数年。)

如果您不想使用Noda Time,我建议您自己假装Period类课程。这很容易做到 - 例如:

// Untested and quickly hacked up. Lots more API you'd probably
// want, string conversions, properties etc.
public sealed class Period
{
    private readonly int years, months, days, hours, minutes, seconds;

    public Period(int years, int months, int days,
                  int hours, int minutes, int seconds)
    {
        this.years = years;
        this.months = months;
        this.days = days;
        this.hours = hours;
        this.minutes = minutes;
        this.seconds = seconds;
    }

    public static DateTime operator+(DateTime lhs, Period rhs)
    {
        // Note: order of operations is important here.
        // Consider January 1st + (1 month and 30 days)...
        // what do you want the result to be?
        return lhs.AddYears(rhs.years)
                  .AddMonths(rhs.months)
                  .AddDays(rhs.days)
                  .AddHours(rhs.hours)
                  .AddMinutes(rhs.minutes)
                  .AddSeconds(rhs.seconds);
    }
}

用法:

DateTime first = new DateTime(2000, 1, 1);
Period second = new Period(11, 2, 5, 10, 10, 11);
DateTime result = first + second;

您需要了解DateTime.Add如何处理不可能发生的情况 - 例如,在1月31日之前添加一个月会给您2月28日/ 29日,具体取决于它是否是闰年。

我在这里列出的简单方法,通过中间值,有其缺点,因为截断可能发生两次(增加年数,然后增加几个月),当它不需要时 - 例如,&# 34; 2月29日+ 1年+ 1个月"可能逻辑上是" 3月29日"但它实际上最终将成为" 3月28日"因为截至2月28日将在月份加入之前发生。

试图找出一个"对"做日历算术的方法是Noda Time,特别是在某些情况下,人们可能不同意"对"答案是。在上面的代码中,我选择了简单性和可预测性 - 根据您的实际需求,您可能需要更复杂的代码。

答案 1 :(得分:1)

您有一个代表某个时间点的DateTime。并且您希望为其添加若干年/月/日/小时/分钟/秒。

DataTime的变化不是一个点,它是一个向量(点之间的差异)。将一个误认为另一个很容易,因为它们通常具有相似的结构。但是,这种类型错误会导致很多痛苦。

避免它不能解决你的痛苦,但它使它易于管理。

将两个DateTime加在一起就是一起添加两个点。有点像将洛杉矶的位置添加到纽约。

现在,将洛杉矶的“矢量”添加到纽约到伦敦是有意义的 - 因为旅行矢量是一个矢量,而不是一个点。点+向量只是一个点。

所以这意味着你需要创建一个时间向量类型。一个简单的时间跨度是一个选项,但可能不合适:因为你关心的是月,年和日,而不是纳秒或绝对持续时间。

我将复制矢量名CalendarVector,因为它代表日历上的移动,而不是时间本身。

一个简单的第一步是创建每个子类型时间的元组 - 年,月,日等 - 然后以任意顺序将它们添加到原始DateTime并重载{{1 }}

你应该支持:

operator+

理想。 DateTime = DateTime + CalendarVector CalendarVector = CalendarVector + CalendarVector CalendarVector = CalendarVector - CalendarVector CalendarVector = int * CalendarVector CalendarVector = - CalendarVector DateTime = DateTime - CalendarVector CalendarVector = DateTime - DateTime 重载是可选的,但可能不需要。

然而,这只会让你走到一半。

剩下的最大问题是CalendarVector添加无法通勤。将1个月添加到DateTime,然后添加1天,与添加1天然后添加1个月不同。

这是根本性的。

存在“1月31日1个月后意味着什么”的问题,可以回答,但对该问题的任何合理答案都不能解决通勤问题。

你计划好的构造函数 - 你在那里喂它的年数,月数,日数,小时数,分钟数 - 因此含糊不清。

因此,强大的解决方案不应该具有该构造函数。

解决方案是创建您明确添加的CalendarVector + DateTimeYearsMonthsDaysHoursMinutes类型。它们一起添加的顺序是它们应用于您添加到它的Seconds的顺序。在DateTime上进行最终申请之前,可以避免通勤和“简化”,因此DateTime 零转换。

+1 year, +2 days, -1 month, -1 year, -2 days, +1 month存在相关问题 - 它应该返回DateTime-DateTime CalendarVectorv,但有多个此类向量。球面坐标可能会出现同样的问题 - 你的意思是围绕地球的短路还是长路?在某些情况下并不重要 - 但是你将结果减半以找到中间点。此外,当您接近“世界的另一端”时,您会遇到不连续性。

所以我的建议是维护lhs = rhs + v对象的转换列表。 DateTime是一个转换,包括向year字段添加1,然后修复其他字段以使它们保持一致。这些转变支持否定。增加是从左到右一次应用它们。否定也可能会颠倒应用程序的顺序,并且“相同类型”的相邻转换可能会合并(因此+1个月-1个月成为身份转换,而不是基于下个月月末的夹紧操作),或者不是(所以1 year,然后下一行的x = x+1 monthx = x-1 month相同。

另一种方法是坚持要求用户提供在这些特殊情况下(在所有时间内发生)应该做什么的策略,因为这个问题非常棘手,以至于“解决”问题的库可以最好突出问题并强迫客户程序员思考它们并做出决定。

答案 2 :(得分:1)

DateTime first = new DateTime(2000, 1, 1);
DateTime second = new DateTime(11, 2, 5, 10, 10, 11);

DateTime result = new DateTime(first.Ticks + second.Ticks);