Потеря часа при возврате даты января 1970 года из миллисекунд.

StackOverflow https://stackoverflow.com/questions/5816510

Вопрос

У меня есть следующий код, который принимает строку миллисекунд (будет из RSS-канала, поэтому это будет строка, пример ниже представляет собой программу быстрого тестирования) и преобразует эти миллисекунды в объект Date.

public static void main(String[] args) {
    String ms = "1302805253";
    SimpleDateFormat dateFormatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(Long.parseLong(ms));

    try {
        String dateFormat = dateFormatter.format(calendar.getTime());
        System.out.println("Date Format = " + dateFormat);

        Date dateParse = dateFormatter.parse(dateFormatter.format(calendar.getTime()));
        System.out.println("Date Parse  = " + dateParse);
    } catch (ParseException e) {
        // TODO: handle exception
    }
}


Output:
    Date Format = Fri, 16 Jan 1970 02:53:25 GMT
    Date Parse  = Fri Jan 16 03:53:25 GMT 1970

Как видите, между форматированием объекта календаря и разбором полученной строки теряется час.Кроме того, изменилось форматирование вывода.Может ли кто-нибудь помочь мне понять, почему это происходит и как это обойти?Я хочу, чтобы объект Date имел тот же формат, что и вывод «Формат даты».

Это было полезно?

Решение

Я считаю, что это происходит потому, что Великобритания этого не сделала. на самом деле используйте GMT ​​в 1970 году, и в Java есть ошибка...это будет формат дата в 1970 году, как если бы Великобритания использовала время по Гринвичу, но без фактического изменения смещения.Простой пример:

Date date = new Date(0);
SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss zzz");
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
System.out.println(sdf.format(date));

Результат:

01 Jan 1970 01:00:00 GMT

Обратите внимание, что он утверждает, что сейчас 1 час ночи по Гринвичу...что неверно.Это был 1 час ночи по европейскому/лондонскому времени, но Европа/Лондон не соблюдала GMT.

Джода Время делает это правильно, поскольку распечатывает BST, но Joda Time не любит анализ значения с сокращениями часовых поясов.Однако вы можете заставить его использовать часовой пояс. компенсации вместо:

import org.joda.time.*;
import org.joda.time.format.*;

public class Test {
    public static void main(String[] args) throws Exception {
        DateTime date = new DateTime(0, DateTimeZone.forID("Europe/London"));

        DateTimeFormatter formatter = DateTimeFormat.forPattern(
            "dd MMM yyyy HH:mm:ss Z");

        String text = formatter.print(date); // 01 Jan 1970 01:00:00 +0100
        System.out.println(text);

        DateTime parsed = formatter.parseDateTime(text);
        System.out.println(parsed.equals(date)); // true
    }
}

Другие советы

А Ответ Джона Скита правильно.

Java.time

Давайте запустим тот же вход через Java.Time, чтобы увидеть результаты.

Укажите Правильное название часового пояса. Анкет Никогда не используйте аббревиатуру 3-4 буквы, например BST, EST, или же IST поскольку они не настоящие часовые пояса, не стандартизированные и даже не уникальные (!). Итак, мы используем Europe/London.

А Instant Класс представляет момент на временной шкале в универсальное глобальное время с разрешением наносекунд.

String input = "1302805253";
long millis = Long.parseLong ( input );
Instant instant = Instant.ofEpochMilli ( millis );

Применить часовой пояс для производства ZonedDateTime объект.

ZoneId zoneId = ZoneId.of ( "Europe/London" );
ZonedDateTime zdt = instant.atZone ( zoneId );

Сбросить в консоли. Мы действительно видим, что Europe/London Время опережает UTC в тот момент. Так что время дня 02 часы, а не 01 часы. Оба представляют один и тот же одновременный момент на временной шкале, просто просматривая линзы двух разных настенные времена.

System.out.println ( "input: " + input + " | instant: " + instant + " | zdt: " + zdt );

Ввод: 1302805253 | Мгновенный: 1970-01-16T01: 53: 25.253Z | ZDT: 1970-01-16T02: 53: 25.253+01: 00 [Европа/Лондон

Целые секунды

Кстати, я подозреваю, что ваша входная строка представляет весь секунды с момента эпохи UTC 1970 года, а не миллисекунды. Анкет Интерпретировал это как секунды, мы получаем дату в 2011 году, в месяц, опубликованный этот вопрос.

String output = Instant.ofEpochSecond ( Long.parseLong ( "1302805253" ) ).atZone ( ZoneId.of ( "Europe/London" ) ).toString ();

2011-04-14T19: 20: 53+01: 00 [Европа/Лондон

О Java.time

А Java.time Рамки встроены в Java 8 и позже. Эти классы вытесняют старые неприятные уроки даты времени, такие как java.util.Date, .Calendar, & java.text.SimpleDateFormat.

А Joda-Time Проект, теперь в Режим технического обслуживания, советует миграцию в Java.Time.

Чтобы узнать больше, увидеть Оракул Учебник. Анкет И поиск стека переполнены для многих примеров и объяснений.

Большая часть функциональности Java.Time возвращается к Java 6 и 7 в Трит-Бэкпорт и дальнейший адаптирован к Android в Threetenabp.

А Третена-Экстра Проект расширяет Java.Time с дополнительными классами. Этот проект является проверкой для возможных будущих дополнений к Java.Time.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top