Потеря часа при возврате даты января 1970 года из миллисекунд.
-
26-10-2019 - |
Вопрос
У меня есть следующий код, который принимает строку миллисекунд (будет из 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.