Я пытаюсь вычислить разницу между двумя LocalDateTime
.
Вывод должен быть в формате y years m months d days h hours m minutes s seconds
. Вот что я написал:
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;
public class Main {
static final int MINUTES_PER_HOUR = 60;
static final int SECONDS_PER_MINUTE = 60;
static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
public static void main(String[] args) {
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 9, 19, 46, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
Period period = getPeriod(fromDateTime, toDateTime);
long time[] = getTime(fromDateTime, toDateTime);
System.out.println(period.getYears() + " years " +
period.getMonths() + " months " +
period.getDays() + " days " +
time[0] + " hours " +
time[1] + " minutes " +
time[2] + " seconds.");
}
private static Period getPeriod(LocalDateTime dob, LocalDateTime now) {
return Period.between(dob.toLocalDate(), now.toLocalDate());
}
private static long[] getTime(LocalDateTime dob, LocalDateTime now) {
LocalDateTime today = LocalDateTime.of(now.getYear(),
now.getMonthValue(), now.getDayOfMonth(), dob.getHour(), dob.getMinute(), dob.getSecond());
Duration duration = Duration.between(today, now);
long seconds = duration.getSeconds();
long hours = seconds / SECONDS_PER_HOUR;
long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
long secs = (seconds % SECONDS_PER_MINUTE);
return new long[]{hours, minutes, secs};
}
}
Вывод, который я получаю 29 years 8 months 24 days 12 hours 0 minutes 50 seconds
. Я проверил свой результат с этого сайта (со значениями 12/16/1984 07:45:55
и 09/09/2014 19:46:45
). Следующий скриншот показывает результат:
Я вполне уверен, что поля после значения месяца неправильно в моем коде. Любое предложение будет очень полезным.
Обновить
Я проверил свой результат с другого сайта, и полученный результат отличается. Вот оно: Рассчитайте продолжительность между двумя датами (результат: 29 лет, 8 месяцев, 24 дня, 12 часов, 0 минут и 50 секунд).
Обновить
Поскольку я получил два разных результата с двух разных сайтов, мне интересно, является ли алгоритм моих расчетов законным или нет. Если я использую следующие два LocalDateTime
объекта:
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
Тогда выходной: 29 years 8 months 25 days -1 hours -5 minutes -10 seconds.
По этой ссылке так и должно быть 29 years 8 months 24 days 22 hours, 54 minutes and 50 seconds
. Поэтому алгоритм должен обрабатывать и отрицательные числа.
Обратите внимание, что вопрос не в том, какой сайт дал мне какой результат, мне нужно знать правильный алгоритм и иметь правильные результаты.
Period.between()
применить округление?7:45:55
и время окончания19:46:45
(или7:46:45
PM). Таким образом, разница между этими двумя значениями составляет 12 часов, 0 минут и 50 секунд, а не 23 часа, 34 минуты и 12 секунд. Таким образом, ваш фактический расчет кажется верным, по крайней мере, в части времени.LocalDateTime
нет часового пояса, не может быть уникального ответа. Даже если вы предполагаете, что начальный и конечный часовые пояса совпадают, в некоторых зонах даты, такие как 2014-09-09, будут в летнее или летнее время, а в других - нет. Это может скинуть вещи на час. Таким образом, вычисление разницы со вторым не имеет смысла, если это не разрешено.LocalDateTime
дает нереальные результаты, поскольку в этом классе намеренно отсутствует какое-либо понятие о часовом поясе или смещении от UTC? Для реальных значений, назначить временную зону с помощьюZoneId
для использованияZonedDateTime
.Ответы:
К сожалению, похоже, что класс периодов также не занимает много времени, поэтому вам, возможно, придется выполнять вычисления самостоятельно.
К счастью, у классов даты и времени есть много вспомогательных методов, которые до некоторой степени упрощают это. Вот способ вычислить разницу, хотя и не обязательно самый быстрый:
Основная идея заключается в следующем: создать временную дату начала и завершить полные годы. Затем скорректируйте эту дату по количеству лет, чтобы начальная дата была меньше года после окончания. Повторите это для каждой единицы времени в порядке убывания.
Наконец, отказ от ответственности : я не учел разные часовые пояса (обе даты должны быть в одном часовом поясе), а также не проверял / не проверял, как переход на летнее время или другие изменения в календаре (например, изменения часового пояса в Самоа) повлиять на этот расчет. Так что используйте с осторожностью.
источник
ChronoUnit
:), но делает работу "вручную".long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);
, вернет число больше 59 для любого интервала не менее 1 часа - и это не то, что хочет ОП. Принимая это во внимание, вы не сможете просто сделать 6 звонковChronoUnit#between()
и сделать это.Я нашел лучший способ сделать это с ChronoUnit.
Дополнительная документация здесь: https://docs.oracle.com/javase/tutorial/datetime/iso/period.html
источник
tempDateTime.until( toDateTime, ChronoUnit.YEARS)
наChronoUnit.YEARS.between(fromDate, toDate)
. Но важные дополнительные строки, такие какtempDateTime.plusYears( years )
и т. Д., Полностью отсутствуют в вашем ответе, поэтому это не помогает ОП. Полный алгоритм имеет значение!Вот один пример использования Duration и TimeUnit для получения формата «чч: мм: сс».
источник
String.format("%02d:%02d:%02d",dur.toHoursPart(), dur.toMinutesPart(), dur.toSecondsPart());
. Методы part дают правильные числа для построения строки. Я думаю, что это более читабельно.Это должно быть проще!
источник
TL; DR
а затем использовать методы
period.getYears()
,period.getMonths()
,period.getDays()
,duration.toHoursPart()
,duration.toMinutesPart()
,duration.toSecondsPart()
.Расширенный ответ
Я отвечу на исходный вопрос, то есть как получить разницу во времени между двумя значениями
LocalDateTimes
в годах, месяцах, днях, часах и минутах, чтобы «сумма» (см. Примечание ниже) всех значений для разных единиц была равна сумме временная разница, и таким образом, что значение в каждом блоке меньше , чем следующий больше единицы, то естьminutes < 60
,hours < 24
и так далее.Учитывая два
LocalDateTimes
start
иend
, например,мы можем представить абсолютный промежуток времени между двумя с
Duration
помощью «возможно»Duration.between(start, end)
. Но самая большая единица, которую мы можем извлечь из -Duration
это дни (как временная единица, эквивалентная 24 часам) - см. Примечание ниже для объяснения. Чтобы использовать более крупные единицы (месяцы, годы), мы можем представить этоDuration
с помощью пары (Period
,Duration
), гдеPeriod
измеряет разницу с точностью до дней, а символDuration
представляет остаток:Теперь мы можем просто использовать методы, определенные для
Period
иDuration
извлекать отдельные единицы:или, используя формат по умолчанию:
Обратите внимание на годы, месяцы и дни
Обратите внимание, что в
java.time
концепции «единицы», такие как «месяц» или «год», не представляют фиксированное абсолютное временное значение - они зависят от даты и календаря, как показано в следующем примере:источник
Существует некоторая проблема для кода Tapas Bose и кода Thomas. Если разница во времени отрицательна, массив получает отрицательные значения. Например, если
возвращает 0 лет 0 месяцев 1 дней -1 часов 0 минут 0 секунд.
Я думаю, что правильный вывод: 0 лет 0 месяцев 0 дней 23 часа 0 минут 0 секунд.
Я предлагаю разделить экземпляры LocalDateTime на экземпляры LocalDate и LocalTime. После этого мы можем получить экземпляры Java 8 Period и Duration. Экземпляр Duration разделяется на количество дней и значение времени в течение дня (<24 ч) с последующей коррекцией значения периода. Когда второе значение LocalTime находится перед значением firstLocalTime, необходимо сократить период на один день.
Вот мой способ вычисления разницы LocalDateTime:
Вышеуказанный метод может быть использован для вычисления разницы любых локальных значений даты и времени, например:
Для описанного выше метода удобно написать модульный тест (оба они являются членами класса PeriodDuration). Вот код:
}
Все тесты успешны независимо от того, указано ли значение первого LocalDateTime до и для каких-либо значений LocalTime.
источник
java.time.Period
где пользователи могут применять / создавать такие смешанные знаки из-за разного внутреннего дизайна).И версия @Thomas в Groovy с принимает нужные единицы в списке вместо жесткого кодирования значений. Эта реализация (которую можно легко перенести на Java - я сделал объявление функции явным) делает подход Thomas более пригодным для повторного использования.
На момент написания этой статьи приведенный выше код возвращается
47 Years, 8 Months, 9 Days, 22 Hours, 52 Minutes, 7 Seconds, 140 Millis
. И, для ввода @Gennady Kolomoets, код возвращается23 Hours
.Когда вы предоставляете список единиц, он должен быть отсортирован по размеру единиц (самый большой сначала):
источник
Вот очень простой ответ на ваш вопрос. Оно работает.
источник
Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old
. Я не думаю, что это то, что было желательно.Joda времени
Так как для многих ответов требовалась поддержка API 26, а для min API было 23, я решил это следующим кодом:
источник
Спустя более пяти лет я отвечаю на мой вопрос. Я думаю, что проблема с отрицательной продолжительностью может быть решена простой коррекцией:
Примечание: сайт https://www.epochconverter.com/date-difference теперь правильно рассчитывает разницу во времени.
Спасибо всем за обсуждение и предложения.
источник
toHours
,toMinutes
иtoSeconds
методыDuration
. С Java 9 даже больше отtoMinutesPart()
аtoSecondsPart()
. И я не вижу смысла в том, чтобы оборачивать часы, минуты и секунды в массив только для того, чтобы убрать их снова. В общем, хороший ответ, хотя.