C# 将两个DateTime对象添加到一起

C# 将两个DateTime对象添加到一起,c#,datetime,add,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); ... 等等 在这个例子中,我想得到Dat

有没有比以下更好的方法将一个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的回答一样,将两个
日期时间
值一起添加是没有意义的。如果你想代表“11年,2个月,5天,10小时,10分11秒”,那么你应该代表它。这和0011-02-05T10:10:11不一样。特别是,你永远无法添加“2个月30天”的例子。同样,您永远无法仅添加一年,因为在一个日期内,月份和日期的值不能为0

现在没有BCL类型来代表“11年[…]”的概念,但是你可以很容易地创建自己的一个。作为替代方案,您可以使用我的项目,该项目具有
期间
,正好用于此目的:

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
,但举个例子,我假设您需要数月和数年。)

如果你不想用野田佳彦的时间,我建议你像上课一样,假装一段时间。这很容易做到,例如:

// 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日,这取决于它是否是闰年

我在这里列出的简单方法,通过中间值,有其缺点,因为这种截断可能会在不需要的时候发生两次(加上年份,然后再加上月份)——例如,“2月29日+1年+1个月”逻辑上可能是“3月29日”,但实际上会以“3月28日”结束因为截止到2月28日的时间将在添加月份之前发生


试图找出一种“正确”的方法来做日历算术是非常困难的,特别是在某些情况下,人们可能不同意什么是“正确”的答案。在上面的代码中,我选择了简单性和可预测性-根据您的实际需求,您可能需要更复杂的东西。

您有一个表示时间点的
DateTime
。您希望在其中添加若干年/月/日/小时/分/秒

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

避免它并不能解决你的痛苦,但它能让你的痛苦变得容易控制

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

现在,把洛杉矶到纽约到伦敦的“向量”加起来是有意义的——因为旅行向量是一个向量,而不是一个点。点+向量就是一个点

这意味着您需要创建一个时间向量类型。简单的时间跨度是一种选择,但可能并不合适:因为您关心的是月、年和天,而不是纳秒或绝对时间长度

我将把向量的名称命名为CalendarVector,因为它表示日历上的运动,而不是时间本身

简单的第一步是创建每个时间子类型(年、月、日等)的元组,然后使用重载的
运算符+
将它们以任意顺序添加到原始
DateTime

你应该支持:

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

然而,这只会让你半途而废

剩下的一个大问题是CalendarVector加法不能通勤。在DateTime中添加1个月,然后添加1天,与添加1天然后添加1个月不同

这是最基本的

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

因此,您的计划构造器(在其中输入年、月、日、小时、分、秒的数量)的含义是不明确的

所以一个健壮的解决方案不应该有那个构造函数

解决方案是创建明确添加在一起的
小时
分钟
类型。它们添加到一起的顺序是它们应用于您添加到的
DateTime
的顺序。在
日期时间
上的最终应用程序之前,避免通勤和“简化”——因此
+1年、+2天、-1个月、-1年、-2天、+1个月
不是零转换

DateTime-DateTime
有一个相关问题——它应该返回一个
CalendarVector
v,这样
lhs=rhs+v
,但是有多个这样的向量。同样的问题也可能发生在球坐标系中——你是说绕地球的短途,还是长途跋涉?在某些情况下,这并不重要,但随后将结果减半,以找到中间点。此外,当你接近“世界的另一边”时,你会遇到不连续性

因此,我的建议是在
DateTime
对象上维护一个转换列表<代码>1年是一种转换,包括将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);