Время и год и месяц в десятичном формате c # - PullRequest
0 голосов
/ 26 сентября 2018

У меня есть два decimal значения

3.10m = 3 years 10 months 
 2.8m = 2 years  8 months.

Я пытаюсь sum эти значения, в результате получается 5.9, что неверно .

Ожидаемый ожидаемый результат должен быть

6.6m = 6 years 6 months

Может ли кто-нибудь из PLS предложить , как мы можем добиться этого, используя TimeSpan или любым другим способом в C #.Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Не делай этого!decimal не для year.month.Технически вы можете решить проблему и различить 3.1m и 3.10m (decimal.GetBits выручает);Вот код для академического использования * только 1009 *:

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

Надеюсь, я напугал вас таким использованием decimal.В качестве быстрого и грязного патча (если вы не можете использовать какую-либо библиотеку, кроме стандартной), вы можете попробовать DateTime class:

 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}"); 
0 голосов
/ 26 сентября 2018

Во-первых, я бы не использовал подобные десятичные дроби для представления значений года / месяца.Как отмечается в комментариях, вы не сможете легко различать от 1 месяца до 10 месяцев ... в то время как decimal может представлять разницу между 3,1 и 3,10, это будетбыть очень странным использованием.Просто держите два значения в отдельных целых числах.

Далее, вы не можете делать арифметику, подобную этой, с TimeSpan.A TimeSpan просто хранит «количество тиков» - он не обрабатывает такие идеи, как «1 месяц» или «1 год», потому что они не представляют фиксированное количество тиков.

Я бы порекомендовалвместо этого использую мою Noda Time библиотеку.Вы бы представляли эти значения как Period объекты.Вы по-прежнему не сможете напрямую добавлять годы и месяцы - Period не предполагает использование григорианской календарной системы, а такая арифметика просто не работает для некоторых негригорианских календарей, особенно тех, которые изменяют количествомесяцев в зависимости от года.Тем не менее, вы можете легко написать свой собственный метод нормализации Period:

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

Теперь, конечно, вы могли бы просто хранить все в двух целых числах - преимущество использования Periodявляется то, что вы можете легко добавить его к LocalDate или LocalDateTime и т. д. Вы можете даже сделать это без нормализации для начала, если хотите.

...