Преобразование TimeUnit из Миллисекунд в Дни у меня не работает - PullRequest
0 голосов
/ 25 мая 2018

Я пытаюсь получить разницу двух временных меток в днях, и TimeUnit возвращает совершенно неверные результаты для меня.

Вот мой код:

long ts = 1522242239952L;
long now = 1527274162820L;
long difference = now - ts;
int ageInDays = (int) TimeUnit.MILLISECONDS.convert(difference, TimeUnit.DAYS);
int ageInDays2 = (int) (difference/(1000 * 60 * 60 * 24));
System.out.println(ageInDays);
System.out.println(ageInDays2);

Вывод:

-1756844032
58

Почему расчет TimeUnit такой неправильный?

Ответы [ 3 ]

0 голосов
/ 25 мая 2018

Потому что вы используете TimeUnit.convert в обратном направлении.Попробуйте

TimeUnit.DAYS.convert(difference, TimeUnit.MILLISECONDS);

или просто

TimeUnit.MILLISECONDS.toDays(difference);

Ссылка: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/TimeUnit.html#convert(long,%20java.util.concurrent.TimeUnit)

0 голосов
/ 25 мая 2018

Почему расчет TimeUnit такой неправильный?

Другие ответы верны: вы выполняли обратное преобразование того, которое планировали.TimeUnit.MILLISECONDS.convert(difference, TimeUnit.DAYS); конвертируется из дней в миллисекунды.

Но почему вы получили отрицательное число ??Это из-за переполнения int.Обратное преобразование было выполнено правильно и дало 434 758 135 795 200 000. Это намного больше, чем 32-битный int.Поэтому, когда вы приводите к int, самые значимые биты обрезаются.Случайно, бит, который в конечном итоге стал знаковым битом int, был 1, что означает отрицательный.Я обычно избегаю делать такой бросок без проверки дальности.Вы можете приобрести ту же привычку.Math.toIntExact() очень полезен здесь.

Как исправить: java.time

Другие ответы по-прежнему в основном верны.Тем не менее, я хотел бы предоставить пару предложений.

Если вы считаете, что время, скажем, с 16:04 один день до 16:04 следующего дня составляет 1 день, то вам нужно использовать часовой поясчтобы получить правильный результат.Например:

    ZoneId zone = ZoneId.of("Africa/Mogadishu");
    ZonedDateTime birth = Instant.ofEpochMilli(ts).atZone(zone);
    long ageInDays = ChronoUnit.DAYS.between(birth, ZonedDateTime.now(zone));
    System.out.println(ageInDays);

В этом случае результат выполнения кода прямо сейчас также тот, который вы ожидали:

58

Если, с другой стороны, вы определяете 1 день как 24 часа, независимо от того, что показывают настенные часы, вот способ получить возраст с точностью до секунды.Вы всегда можете преобразовать в последующие дни.

    Instant birth = Instant.ofEpochMilli(ts);
    Duration age = Duration.between(birth, Instant.now());
    System.out.println(age);
    System.out.println(age.toDays());

Вывод:

PT1398H52M13.994841S
58

В первой из двух строк указано, что возраст составляет 1398 часов 52 минуты 13,994841 секунды.Вторая строка согласуется с предыдущим результатом.

Мысли о двух фрагментах также можно комбинировать и смешивать.В целом, я думаю, что java.time дает некоторые возможности, которые было бы труднее получить с помощью TimeUnit, и некоторый довольно четкий и понятный код, в котором вы не могли бы легко совершить ту же ошибку, что и в вопросе.

Ссылки:

0 голосов
/ 25 мая 2018

Вы неправильно поняли документацию TimeUnit:

длинное преобразование (long sourceDuration, TimeUnit sourceUnit)

Преобразование данной длительности в заданной единице в этуед.

...