Преобразовать временную метку в числовом формате в LocalDateTime в Java

#java #datetime-format

#java #datetime-формат

Вопрос:

При вызове API я получаю временную метку как: 1591290491238. Мне нужно преобразовать ее в LocalDateTime в Java. Я написал код как:

 String timestamp = "1584453053825";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMdduuHHmmss");
LocalDateTime localDateTime = LocalDateTime.parse( timestamp , formatter );
 

Но это выдает ошибку:

 Text '1584453053825' could not be parsed at index 12
 

Комментарии:

1. К вашему сведению, LocalDateTime здесь указан неправильный тип. Ваш входной номер, вероятно, представляет собой количество с момента ссылки на эпоху. Таким образом, этот ввод представляет момент, определенную точку на временной шкале. Для этого вам нужен Instant класс. LocalDateTime Класс не может представлять момент, поскольку в нем отсутствует какое-либо понятие часового пояса или смещения от UTC.

2. @BasilBourque очень прав, не используйте LocalDateTime здесь (и редко используйте его вообще). Если вам нужны дата и время суток, используйте ZonedDateTime .

3. Что дал ваш поиск? Я нашел это, я думаю, это полезно: Java — Как преобразовать миллисекунды эпохи в LocalDateTime?

Ответ №1:

Число представляет время в формате Unix, то есть количество миллисекунд, прошедших с момента начала эпохи, то есть 1 января 1970 года в полночь по Гринвичу.

Вы можете преобразовать ее LocalDateTime следующим образом:

 LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(timestamp)), ZoneId.systemDefault());
 

Ответ №2:

Используйте ZonedDateTime для даты и времени суток

Ваша временная метка — это количество миллисекунд с эпохи Java / Unix от 1 января 1970 года в начале дня по UTC. Чтобы преобразовать его в дату и время суток, вам сначала нужно выбрать для этого часовой пояс, поскольку во всех часовых поясах никогда не бывает одного и того же времени (даже одной и той же даты). Пока число больше 1000, Java анализирует строку, содержащую его напрямую.

     ZoneId zone = ZoneId.of("America/New_York");
    DateTimeFormatter numericalFormatter = new DateTimeFormatterBuilder()
            .appendValue(ChronoField.INSTANT_SECONDS, 1, 19, SignStyle.NEVER)
            .appendValue(ChronoField.MILLI_OF_SECOND, 3)
            .toFormatter()
            .withZone(zone);
    
    String timestamp = "1591290491238";
    
    ZonedDateTime dateTime = ZonedDateTime.parse(timestamp, numericalFormatter);
    
    System.out.println(dateTime);
 

Вывод из этого фрагмента примера:

2020-06-04T13:08:11.238-04:00[Америка / New_York]

Как уже сказал Бэзил Бурк в комментарии, LocalDateTime это неправильный класс для вашей даты и времени. ZonedDateTime дает вам то же самое и даже больше, поскольку он также содержит часовой пояс и, следовательно, определяет момент времени, определенный исходной строкой временной метки. Вы можете преобразовать в LocalDateTime , тем самым выбросив информацию, которую хотите сохранить. Так что делайте это только в том случае, если вам нужен LocalDateTime API для API, разработанный людьми, которые не понимали, что это неправильный класс.

     LocalDateTime amputatedDateTime = dateTime.toLocalDateTime();
    System.out.println(amputatedDateTime);
 

2020-06-04T13:08:11.238

Вы заметили, что теперь мы потеряли смещение от UTC и часового пояса.

Что пошло не так в вашем коде?

Вы пытались проанализировать строку, используя шаблон форматирования MMdduuHHmmss . Шаблон определяет 12 цифр, но в строке их 13. Используемый вами шаблон предполагает, что 1591290491238 относится к 12-му дню 159-го месяца 2090 года в 49:12:38 на 24-часовых часах или что-то в этом роде. Это чушь. Также потому, что, как я уже сказал, число относится к моменту времени, а не к дате и времени, и для получения последнего нам сначала нужно указать часовой пояс.

Ответ №3:

Ваша временная метка на самом деле представляет собой количество миллисекунд с 1970-01-01T00:00:00Z момента, когда Z обозначается Zulu дата-время или дата-время в UTC (т. Е. Со смещением часового 00:00 пояса в часах). Вы должны разобрать ее до a long , а затем получить Instant из нее.

Если у вас есть объект Instant , вы можете получить из него объекты других типов даты и времени, как показано ниже:

 import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String timestamp = "1584453053825";
        long epochMilli = Long.parseLong(timestamp);
        Instant instant = Instant.ofEpochMilli(epochMilli);

        // Convert instant to ZonedDateTime with the time zone of JVM
        ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());

        // Get LocalDateTime from instant
        LocalDateTime ldt = zdt.toLocalDateTime();

        // Display ldt in the default format i.e. the value returned by ldt#toString
        System.out.println(ldt);

        // Display ldt in a custom format e.g. EEE MMMM dd, uuuu hh:mm:ss a
        System.out.println(ldt.format(DateTimeFormatter.ofPattern("EEE MMMM dd, uuuu hh:mm:ss a", Locale.ENGLISH)));
    }
}
 

Вывод:

 2020-03-17T13:50:53.825
Tue March 17, 2020 01:50:53 PM
 

Узнайте о современном API для определения даты и времени из Trail: Date Time .