C# 时间跨度年和月(十进制c)

C# 时间跨度年和月(十进制c),c#,datetime,timestamp,C#,Datetime,Timestamp,我有两个十进制值 我试图将这些值相加,结果是5.9,这是不正确的 预期的结果应该是 6.6m = 6 years 6 months 任何人都可以建议我们如何使用TimeSpan或C中的任何其他方法来实现这一点。首先,我要避免使用那样的小数来表示年/月值。如评论中所述,您将无法轻松区分1个月和10个月。。。虽然十进制可以表示3.1和3.10之间的差异,但这将是一个非常奇怪的用法。只需将这两个值保持在单独的整数中 接下来,你不能用TimeSpan做这样的算术。TimeSpan只存储一定数量的滴答声

我有两个十进制值

我试图将这些值相加,结果是5.9,这是不正确的

预期的结果应该是

6.6m = 6 years 6 months

任何人都可以建议我们如何使用TimeSpan或C中的任何其他方法来实现这一点。首先,我要避免使用那样的小数来表示年/月值。如评论中所述,您将无法轻松区分1个月和10个月。。。虽然十进制可以表示3.1和3.10之间的差异,但这将是一个非常奇怪的用法。只需将这两个值保持在单独的整数中

接下来,你不能用TimeSpan做这样的算术。TimeSpan只存储一定数量的滴答声——它不会处理像1个月或1年这样的想法,因为这些并不代表固定数量的滴答声

我建议改用我的图书馆。您可以将这些值表示为周期对象。您仍然无法直接将年和月相加-周期不采用公历系统,这样的算法对某些非公历日历不起作用,尤其是那些根据年份改变月数的日历。但是,您可以轻松编写自己的周期规范化方法:

using System;
using NodaTime;

class Test
{
    static void Main()
    {
        Period p1 = new PeriodBuilder { Years = 3, Months = 10 }.Build();
        Period p2 = new PeriodBuilder { Years = 5, Months = -12 }.Build();
        Period sum = p1 + p2;
        Period normalized = NormalizeYearsAndMonths(sum);
        Console.WriteLine($"{normalized.Years} years; {normalized.Months} months");
    }

    static Period NormalizeYearsAndMonths(Period period)
    {
        // TODO: Handle negative years and months however you want.
        int years = period.Years;
        int months = period.Months;
        years += months / 12;
        months = months % 12;
        var builder = period.ToBuilder();
        builder.Years = years;
        builder.Months = months;
        return builder.Build();
    }
}

当然,你可以把所有的东西都保留在两个整数中——使用句点的好处是,你可以很容易地将它添加到LocalDate或LocalDateTime等中。如果你愿意的话,你甚至可以一开始就不进行规范化。

首先,我要避免使用像那样的小数来表示年/月值。如评论中所述,您将无法轻松区分1个月和10个月。。。虽然十进制可以表示3.1和3.10之间的差异,但这将是一个非常奇怪的用法。只需将这两个值保持在单独的整数中

接下来,你不能用TimeSpan做这样的算术。TimeSpan只存储一定数量的滴答声——它不会处理像1个月或1年这样的想法,因为这些并不代表固定数量的滴答声

我建议改用我的图书馆。您可以将这些值表示为周期对象。您仍然无法直接将年和月相加-周期不采用公历系统,这样的算法对某些非公历日历不起作用,尤其是那些根据年份改变月数的日历。但是,您可以轻松编写自己的周期规范化方法:

using System;
using NodaTime;

class Test
{
    static void Main()
    {
        Period p1 = new PeriodBuilder { Years = 3, Months = 10 }.Build();
        Period p2 = new PeriodBuilder { Years = 5, Months = -12 }.Build();
        Period sum = p1 + p2;
        Period normalized = NormalizeYearsAndMonths(sum);
        Console.WriteLine($"{normalized.Years} years; {normalized.Months} months");
    }

    static Period NormalizeYearsAndMonths(Period period)
    {
        // TODO: Handle negative years and months however you want.
        int years = period.Years;
        int months = period.Months;
        years += months / 12;
        months = months % 12;
        var builder = period.ToBuilder();
        builder.Years = years;
        builder.Months = months;
        return builder.Build();
    }
}
现在,您当然可以将所有内容保留为两个整数-使用句点的好处是,您可以轻松地将其添加到LocalDate或LocalDateTime等中。如果您愿意,您甚至可以在不进行规范化的情况下开始操作。

不要这样做!小数不代表年。月。从技术上讲,你可以解决这个问题,并区分3.1m和3.10m十进制;以下代码仅供学术使用:

演示:

我希望,我吓坏了你,使你不再使用十进制。作为一个快速而肮脏的补丁,如果您不能使用标准库以外的任何库,您可以尝试DateTime类:

不要这样做!小数不代表年。月。从技术上讲,你可以解决这个问题,并区分3.1m和3.10m十进制;以下代码仅供学术使用:

演示:

我希望,我吓坏了你,使你不再使用十进制。作为一个快速而肮脏的补丁,如果您不能使用标准库以外的任何库,您可以尝试DateTime类:


为什么要对DateTime使用十进制响应?如何区分3.1 3年1个月和3.10 3年10个月?我认为3.10=3年10个月的标识是错误的。根据这一逻辑,3.12将是3年12个月或4年。我们如何使用TimeSpan或C中的任何其他方法来实现这一点?使用TimeSpan,您只需执行TimeSpan total=span1+span2;其中span1和span2也是TimeSpan类型。@马修·沃森:是的,你说得很对:在2018年1月30日之前加上一个月是个问题,是2018年2月28日吗?如果我们减去1个月的时间呢?;但是,通常情况下,业务请求应在一个月内发出。为什么要对DateTime使用十进制响应?如何区分3.1 3年1个月和3.10 3年10个月?标识3.10=3年10个月在我看来是错误的。根据时间跨度4.3年或12年的逻辑,我们将如何实现?使用TimeSpan,您只需执行TimeSpan total=span1+span2;其中span1和span2也是TimeSpan类型。@马修·沃森:是的,你说得很对:在2018年1月30日之前加上一个月是个问题,是2018年2月28日吗?如果我们减去1个月的时间呢?;然而,通常情况下,业务请求应该在一个月内发出,等等。
private static decimal EerieArithmetics(decimal d1, decimal d2) {
  int y1 = (int)d1;
  int m1 = (int)((d1 % 1m) * ((((decimal.GetBits(d1)[3] >> 16) & 31) == 2) ? 100m : 10m));

  int y2 = (int)d2;
  int m2 = (int)((d2 % 1m) * ((((decimal.GetBits(d2)[3] >> 16) & 31) == 2) ? 100m : 10m));

  int y = y1 + y2 + (m1 + m2) / 12;
  int m = (m1 + m2) % 12;

  return y + (m == 10 ? 0.10m : m > 10 ? m / 100.00m : m / 10.0m);
}
Tuple<decimal, decimal>[] tests = new Tuple<decimal, decimal>[] {
  Tuple.Create(3.10m,  2.8m),
  Tuple.Create( 3.1m,  2.8m),
  Tuple.Create( 3.0m,  2.8m),
  Tuple.Create( 3.0m,  2.0m),
  Tuple.Create(   3m,    2m),
  Tuple.Create( 3.8m,  2.4m),
  Tuple.Create(3.10m, 3.10m),
  Tuple.Create( 2.8m,  2.2m),
  Tuple.Create(2.11m,  2.2m),
};

string report = string.Join(Environment.NewLine, tests
  .Select(test => 
     $"{test.Item1,5} + {test.Item2,5} == {EerieArithmetics(test.Item1, test.Item2),5}"));

Console.Write(report);
 3.10 +   2.8 ==   6.6
  3.1 +   2.8 ==   5.9
  3.0 +   2.8 ==   5.8
  3.0 +   2.0 ==     5
    3 +     2 ==     5
  3.8 +   2.4 ==     6
 3.10 +  3.10 ==   7.8
  2.8 +   2.2 ==  4.10
 2.11 +   2.2 ==   5.1
 DateTime d1 = new DateTime(3, 10, 1); // 1 Oct 3 AD
 DateTime d2 = new DateTime(2, 8, 1);  // 1 Aug 2 AD

 DateTime result = d1
   .AddYears(d2.Year)
   .AddMonths(d2.Month);               // 1 Jun 6 AD

 // 6.6
 Console.Write($"{result.Year}.{result.Month}");