2016-02-04 10 views
1

У меня есть дата в далеком прошлом.
Я выяснил, что такое продолжительность между этой датой и сейчас.
Теперь я хотел бы знать - сколько это за годы?Преобразование продолжительности в годы в Java8 Date API?

Я придумал это решение с использованием Java8 API.
Это чудовищное решение, так как я должен сначала преобразовать продолжительность в дни вручную, потому что будет UnsupportedTemporalTypeException иначе - LocalDate.plus(SECONDS) не поддерживается по какой-либо причине.
Даже если компилятор разрешает этот вызов.

Есть еще несколько слов о возможности преобразования Duration в лет?

LocalDate dateOne = LocalDate.of(1415, Month.JULY, 6); 
Duration durationSinceGuss1 = Duration.between(LocalDateTime.of(dateOne, LocalTime.MIDNIGHT),LocalDateTime.now()); 

long yearsSinceGuss = ChronoUnit.YEARS.between(LocalDate.now(), 
     LocalDate.now().plus(
       TimeUnit.SECONDS.toDays(
         durationSinceGuss1.getSeconds()), 
       ChronoUnit.DAYS)); 

/* 
* ERROR - 
* LocalDate.now().plus(durationSinceGuss1) causes an Exception. 
* Seconds are not Supported for LocalDate.plus()!!! 
* WHY OR WHY CAN'T JAVA DO WHAT COMPILER ALLOWS ME TO DO? 
*/ 
//long yearsSinceGuss = ChronoUnit.YEARS.between(LocalDate.now(), LocalDate.now().plus(durationSinceGuss)); 

/* 
* ERROR - 
* Still an exception! 
* Even on explicitly converting duration to seconds. 
* Everything like above. Seconds are just not allowed. Have to convert them manually first e.g. to Days?! 
* WHY OR WHY CAN'T YOU CONVERT SECONDS TO DAYS OR SOMETHING AUTOMATICALLY, JAVA? 
*/ 
//long yearsSinceGuss = ChronoUnit.YEARS.between(LocalDate.now(), LocalDate.now().plus(durationSinceGuss.getSeconds(), ChronoUnit.SECONDS)); 
+3

Вы рассчитываете Длительность между датой в * прошлых * и 'now()', а затем попытайтесь рассчитать годы между 'now()' и * другой датой *, которая является Duration в * future *. ЗАЧЕМ?!?!? Пример: В этом году (2016 год) високосный год, но високосный день еще не произошел. Продолжительность с 3 февраля 2015 года по сегодняшний день ('3, 2016') в прошлом году составляет 365 дней. 365 дней с сегодняшнего дня * вчера * даты следующего года ('2 февраля 2017 года). Так ровно один год с оригинальной даты, но ваши расчеты говорят, что будущая дата будет меньше, чем через год. Результат неверен !! – Andreas

ответ

5

Вы пробовали использовать LocalDateTime или DateTime вместо LocalDate? По дизайну последний не поддерживает часы/минуты/секунды/и т. Д., Поэтому UnsupportedTemporalTypeException, когда вы пытаетесь добавить к нему секунды.

Например, это работает:

LocalDateTime dateOne = LocalDateTime.of(1415, Month.JULY, 6, 0, 0); 
Duration durationSinceGuss1 = Duration.between(dateOne, LocalDateTime.now()); 
long yearsSinceGuss = ChronoUnit.YEARS.between(LocalDateTime.now(), LocalDateTime.now().plus(durationSinceGuss1)); 
System.out.println(yearsSinceGuss); // prints 600 
+0

Действительно, 'plus'' LocalDateTime' работает с секундами! Или даже с 'Duration' себя! – Skip

3

Используйте Period, чтобы получить число лет между двумя объектами: LocalDate

LocalDate before = LocalDate.of(1415, Month.JULY, 6); 
    LocalDate now  = LocalDate.now(); 
    Period period = Period.between(before, now); 

    int yearsPassed  = period.getYears(); 

    System.out.println(yearsPassed); 
+0

Привет! Я знаю периоды. Все это касалось преобразования DURATION в годы, например. если кто-то передает его вам извне. – Skip

+0

Лично я нахожу точность дня (с использованием 'Period') гораздо более привлекательной в историческом контексте, чем вторая точность (используя' Duration'). Однако, построение 'LocalDate.of (1415, Month.JULY, 6)', вероятно, неверно, потому что 'java.time' использует только gregorian правила календаря на все времена. –

3

Хотя принятый ответ @ Matt Болл пытается быть умным в использование Java-8-API, я бы сделал следующее возражение:

Ваше требование не является точным becaus e нет способа точно преобразовать секунды в годы.

Причины:

  • Самое главное: Месяцы имеют разные длины в дни (с 28 до 31).
  • Годы иногда високосные (29 февраля), которые также влияют на расчетные дельты года.
  • Грегорианский срез: вы начинаете с года в 1415 году, что задолго до первой грегорианской реформы календаря, которая отменила полные десять дней, в Англии даже 11 дней и в России больше. И годы в старом юлианском календаре имеют разные правила високосного года.
  • Исторические даты не определены со второй точностью. Можете ли вы, например, описать момент/момент битвы при Гастингсе? Мы даже не знаем точно час, как раз в тот день. Предполагая, что полночь в начале дня уже является грубым и, вероятно, неправильным предположением.
  • Временные эффекты, влияющие на длину дня (23 часа, 24 часа, 25 часов или даже другие длины).
  • високосные секунды (экзотические)

И, может быть, самое главное возражение код:

Я не могу себе представить, что поставщик на дату с 1415 года имеет намерение интерпретировать такую ​​дату как gregorian дата.

Я понимаю желание для перехода от секунд до нескольких лет но может быть только приблизительным бы вы ни выбрали в качестве решения. Так что если у вас есть годы, как 1415 я бы просто предложить следующее очень простое приближение:

Duration d = ...; 
int approximateYears = (int) (d.toDays()/365.2425); 

Для меня это является достаточным в историческом контексте тех пор, пока мы действительно хотим использовать второй на основе длительности для такого использования которых дело. Похоже, вы не можете изменить ввод, который вы получаете из внешних источников (в противном случае было бы неплохо связаться с поставщиком продолжительности и спросить, может ли быть подсчитано количество дней). В любом случае, вы должны спросить себя, какое определение года вы хотите применить.

Боковые ноты:

Ваша жалоба "? ПОЧЕМУ ИЛИ ПОЧЕМУ НЕ МОЖЕТ JAVA DO ЧТО COMPILER ПОЗВОЛЯЕТ МНЕ СДЕЛАТЬ" не соответствует характеру нового java.time-API.

Вы ожидать API быть типобезопасным, но java.time (JSR-310) не разработан как Типобезопасные и во многом зависит от времени выполнения-исключений. Компилятор не поможет вам с этим API. Вместо этого вам необходимо проконсультироваться с документацией в случае сомнений, если какая-либо единица времени применима к любому временному типу. Вы можете найти такой ответ в документации о конкретной реализации Temporal.isSupported(TemporalUnit). Во всяком случае, желание для безопасности компиляции понятно (и я сделал все возможное, чтобы реализовать свою собственную библиотеку времени Time4J как безопасную для типа), но дизайн JSR-310 уже установлен в камне.

Существует также искусная ловушка, если вы применяете java.time.Duration на любом LocalDateTime или Instant, потому что результаты не совсем сопоставимы (в секунды первого типа определяется на местных сроках, а секунды Instant определяются на глобальной шкале). Таким образом, даже если исключение во время выполнения, как в принятом ответе @Matt Ball, мы должны тщательно рассмотреть, является ли результат такого расчета разумным и заслуживающим доверия.

+0

Эй, Мено! Я понимаю вашу точку зрения и как-то понимаю стратегию, которой придерживается новый API Date. Выбросьте исключение, если исключающее решение невозможно. НО. Java как-то DID реализует преобразование дней, месяцев и т. Д. В годы. Так почему же конверсия секунд (и, следовательно, длительность) должна отличаться? Нынешний API для меня похож на минное поле. Я бы использовал аппроксимацию вместо исключений времени выполнения. – Skip

+0

@Skip Ну, простая дата календаря (например, «LocalDate») не имеет отношения к секундам, поэтому гранулярность дат календаря не определена с такой точностью.Поэтому неплохо не поддерживать применение длительностей по календарным датам на второй основе. Таким образом, пользователи могут быть предупреждены, когда они делают ошибки точности. Однако не так хорошо, что компилятор не жалуется на такой код, поэтому новый API действительно может быть иногда минным полем во время выполнения. Это поведение относится ко всем видам статических 'from()' -методов или низкоуровневых интерфейсов 'Temporal',' TemporalUnit' и т. Д. –

+0

@Skip Кстати, я не вижу автоматического преобразования из нескольких дней в несколько лет (из-за разной длины месяца), если вы не определяете контрольную дату. И я думаю, что «Период» не имеет механизма для такого преобразования. Вы знаете это лучше? –