2015-01-23 2 views
4

У меня возникли проблемы с NodaTime lib. Моя цель: вычислить Год/Месяц/Дата между двумя датами. Итак, вот мой тестовый пример:Noda Время: Period.Between возвращает неправильное значение

private static void Main() 
    { 
     var list = new List<Tuple<DateTime, DateTime>> 
     { 
      new Tuple<DateTime, DateTime>(new DateTime(1980, 1, 1), new DateTime(1983, 12, 31)), 
      new Tuple<DateTime, DateTime>(new DateTime(2009, 1, 1), new DateTime(2015, 01, 23)) 
     }; 
     var totalPeriod = Period.Zero; 
     foreach (var tuple in list) 
     { 
      var dateFrom = tuple.Item1; 
      var dateTo = tuple.Item2; 
      var ld1 = new LocalDate(dateFrom.Year, dateFrom.Month, dateFrom.Day); 
      var ld2 = new LocalDate(dateTo.Year, dateTo.Month, dateTo.Day); 
      var period = Period.Between(ld1, ld2, PeriodUnits.YearMonthDay); 
      totalPeriod += period; 
     } 
     Console.WriteLine("Years: {0}, Months: {1}, Days: {2}", 
      totalPeriod.Years, 
      totalPeriod.Months, 
      totalPeriod.Days); 
     Console.Read(); 
    } 

Выход: лет: 9, месяцев: 11, дней: 52

Это неправильно для меня. Я хочу получить, например, следующий результат (конечно, результат зависит от количества дней в месяце, при условии, что в нашем месяце 31 день): Годы: 10, Месяцы: 0, Дни: 21

Итак, я хочу, чтобы дни были округлены до лет и месяца. Как я могу это получить?

Ответ: Используя ответ Мэтта я создал следующее решение:

foreach (var tuple in list) 
     { 
      var dateFrom = tuple.Item1; 
      var dateTo = tuple.Item2; 
      var period = Period.Between(LocalDateTime.FromDateTime(dateFrom).Date, LocalDateTime.FromDateTime(dateTo).Date, PeriodUnits.YearMonthDay); 
      totalPeriod += period; 
     } 
     // trying clarify the period 
     while(totalPeriod.Days >= 30) 
     { 
      totalPeriod = totalPeriod - Period.FromDays(30); 
      totalPeriod = totalPeriod + Period.FromMonths(1); 
      while (totalPeriod.Months >= 12) 
      { 
       totalPeriod = totalPeriod - Period.FromMonths(12); 
       totalPeriod = totalPeriod + Period.FromYears(1); 
      } 
     } 
+3

Я уверен, что @jonskeet прыгнет на это. Но как бы «Период» округлялся от 52 дней до 1 месяца и 21 дня? Каждый месяц имеет другое количество дней! –

+2

Я не думаю, что ваше «следующее решение» является особенно хорошим, если честно. Если вы хотите только разницу между * двумя * датами, почему бы просто не использовать «Period.Between» один раз? Нормализация периодов с месяцами и годами для меня не очень хорошая идея. Если вы добавляете каждый период с 1 января по 2 января, то 2 января и 3 января и т. Д. До 31 декабря и 1 января, вы * не будете * заканчивать год. Какая здесь большая картина? Чего вы действительно пытаетесь достичь? Возможно, вам захочется просто собрать количество дней (что вы можете сделать с PeriodUnits). –

+0

Я собираюсь объяснить, что хочу. Я должен получить продолжительность работы гражданина, который должен быть представлен в Годы, Месяцы и Дни. Пример: Майк Смит - программист. Он начал работать с 1 января 1980 года в Microsoft. Он ушел из Microsoft в 31 декабря 1983 года. После этого он не работает нигде до 1 января 2009 года. С 1 января 2009 года он начал работать в Google. Он ушел из Google в 23 января 2015 года. Итак, есть два периода: 1st = 1 Jan 1980 - 31 Dec 1983 2nd = 1 Jan 2009 - 23 Jan 2015 В результате я должен получить: Годы: 10, Месяцы: 0, Дни: 21 Но Я получил: Лет: 9, Месяц: 11, Дней: 52 – Dampir

ответ

4

Ричард был прав в своем комментарии на ОП. Проблема в том, что месяцы и годы не являются отдельными величинами для себя. Нужно иметь систему отсчета для «подсчета» их. У вас есть эта ссылка, когда вы выполняете операцию Period.Between, но она потеряна к тому моменту, когда вы пытаетесь добавить периоды вместе.

Если проверить периоды, которые добавляются, это имеет смысл:

First: Years: 3, Months: 11, Days: 30 
Second: Years: 6, Months: 0, Days: 22 
Total: Years: 9, Months: 11, Days: 52 

Для того, чтобы округлить, как вы хотели бы, что 22 дней добавляется в течение 30 дней, как-то должны знать, какой месяц ссылался. Даже если вы сохранили исходную информацию - какой из них вы бы использовали? У вас вполне может быть 28-дневный месяц на одной стороне и 31-дневный месяц на другом.

Лучшее, что вы могли бы сделать, - это искусственно обвести результаты самостоятельно и выбрать плоское значение (например, 30 дней) для представления всех месяцев.

О, одна незначительная вещь (не связанная с вашим вопросом) - Чтобы перейти от DateTime к LocalDate, попробуйте LocalDateTime.FromDateTime(dt).Date. :)

+0

Спасибо, Мэтт! Я предполагаю этот вариант, когда я писал этот вопрос, но я думаю, что есть точное решение. Я отправлю свой полученный код в вопрос. Постскриптум И большое спасибо за LocalDateTime.FromDateTime (dt) .Date way :) Это действительно полезно! – Dampir