Как в Java преобразовать секунды с начала эпохи в миллисекунды с 1 января 1970 года, 00:00:00 по Гринвичу

Короче говоря:

У меня есть время, которое находится в эпохе, и я хочу сделать его временем, начиная с January 1, 1970, 00:00:00 GMT, поскольку java.util.Date ожидает получить.

Этот код помогает продемонстрировать мою проблему:

import java.util.Date;
import java.util.Locale;

import org.junit.Test;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class TimeHelp {

    private String format = "EEE MMM dd HH:mm:ss yyyy";

    public SimpleDateFormat asSimpleDateFormat() {
        return new SimpleDateFormat(format, Locale.ENGLISH);
    }

    public DateTimeFormatter asDateTimeFormatter() {
        return DateTimeFormatter.ofPattern(format, Locale.ENGLISH);
    }

    @Test
    public void test() throws Exception {
        System.out.println(ZoneId.systemDefault());
        String s = "Sun Apr 04 02:00:01 2010";
        long t1 = asSimpleDateFormat().parse(s).getTime();

        ZonedDateTime zoned = LocalDateTime.parse(s, asDateTimeFormatter())
                    .atZone(ZoneId.systemDefault());
        long t2 = zoned.toEpochSecond() * 1000;

        long t3 = Date.from(zoned.toInstant()).getTime();

        long t4 = zoned.toInstant().toEpochMilli();

        System.out.println("t1 " + t1);
        System.out.println("t2 " + t2);
        System.out.println("t3 " + t3);
        System.out.println("t4 " + t4);
        System.out.println("Difference in minutes " + Math.abs(t1 - t2)/1000/60);
    } 
}

И это выводит:

Australia/Sydney
t1 1270310401000
t2 1270306801000
t3 1270306801000
t4 1270306801000
Difference in minutes 60

Обратите внимание, что t1 отличается от всех остальных, я думаю, потому что t1 — это GMT, а все остальные — UTC.

Если я использую SimpleDateFormat, значение long отличается от того, если я использую DateTimeFormatter, чтобы получить ZonedDateTime, после чего я вызываю toEpochSecond().

По причинам, по которым я хотел бы получить ZonedDateTime, и я хочу преобразовать его в Date, но похоже, что это не сработает, потому что Date работает по Гринвичу, а не UTC.


person Luke    schedule 13.02.2020    source источник
comment
Обновлен вопрос, чтобы включить это, обратите внимание, что он дает 1270306801000, а не 1270310401000   -  person Luke    schedule 13.02.2020
comment
Ошибка копирования/вставки: println("t4 " + t3);   -  person Andreas    schedule 13.02.2020
comment
Я надеюсь, вы знаете, что SimpleDateFormat заведомо проблематичен и давно устарел. Вы должны использовать DateTimeFormat и ZonedDateTime. Также подумайте, действительно ли вам нужны миллисекунды с эпохи. Если вы это сделаете, для полной точности используйте zoned.toInstant().toEpochMilli().   -  person Ole V.V.    schedule 13.02.2020


Ответы (1)


Цитируя timeanddate.com:

Когда местное дневное время приближалось к Sunday, April 4, 2010, 3:00:00 am, часы вместо этого повернулись на 1 час назад к Sunday, April 4, 2010, 2:00:00 am местному стандартному времени.

Это означает, что Sun Apr 04 02:00:01 2010 произошло дважды в тот день. Итак, какой из этих 2 вы получаете?

С SimpleDateFormat вы получаете позднее, хотя это недокументировано.

С ZonedDateTime вы получаете предыдущий один:

Для перекрытий общая стратегия заключается в том, что если локальная дата-время попадает в середину перекрытия, то предыдущее смещение будет сохранено. Если предыдущее смещение отсутствует или предыдущее смещение недопустимо, то используется более раннее смещение, обычно "летнее" время. Два дополнительных метода, withEarlierOffsetAtOverlap() и withLaterOffsetAtOverlap(), помогают управлять случаем перекрытия.

person Andreas    schedule 13.02.2020