Java Convert GMT / UTC по местному времени не работает должным образом
103994 просмотра
6 ответа
Чтобы показать воспроизводимый сценарий, я делаю следующее
Получить текущее системное время (местное время)
Конвертировать местное время в UTC // Работает отлично До здесь
Обратное время UTC, назад к местному времени. Использовали 3 разных подхода (перечислены ниже), но все 3 подхода сохраняют время только в UTC.
{
long ts = System.currentTimeMillis(); Date localTime = new Date(ts); String format = "yyyy/MM/dd HH:mm:ss"; SimpleDateFormat sdf = new SimpleDateFormat (format); // Convert Local Time to UTC (Works Fine) sdf.setTimeZone(TimeZone.getTimeZone("UTC")); Date gmtTime = new Date(sdf.format(localTime)); System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:" + gmtTime.toString() + "-" + gmtTime.getTime()); // Reverse Convert UTC Time to Locale time (Doesn't work) Approach 1 sdf.setTimeZone(TimeZone.getDefault()); localTime = new Date(sdf.format(gmtTime)); System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:" + gmtTime.toString() + "-" + gmtTime.getTime()); // Reverse Convert UTC Time to Locale time (Doesn't work) Approach 2 using DateFormat DateFormat df = new SimpleDateFormat (format); df.setTimeZone(TimeZone.getDefault()); localTime = df.parse((df.format(gmtTime))); System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:" + gmtTime.toString() + "-" + gmtTime.getTime()); // Approach 3 Calendar c = new GregorianCalendar(TimeZone.getDefault()); c.setTimeInMillis(gmtTime.getTime()); System.out.println("Local Time " + c.toString());
}
Ответы (6)
56 плюса
Я также рекомендую использовать Йоду, как упоминалось ранее.
Решение вашей проблемы с использованием только стандартных объектов Java Date
может быть выполнено следующим образом:
// **** YOUR CODE **** BEGIN ****
long ts = System.currentTimeMillis();
Date localTime = new Date(ts);
String format = "yyyy/MM/dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(format);
// Convert Local Time to UTC (Works Fine)
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date gmtTime = new Date(sdf.format(localTime));
System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:"
+ gmtTime.toString() + "," + gmtTime.getTime());
// **** YOUR CODE **** END ****
// Convert UTC to Local Time
Date fromGmt = new Date(gmtTime.getTime() + TimeZone.getDefault().getOffset(localTime.getTime()));
System.out.println("UTC time:" + gmtTime.toString() + "," + gmtTime.getTime() + " --> Local:"
+ fromGmt.toString() + "-" + fromGmt.getTime());
Выход:
Local:Tue Oct 15 12:19:40 CEST 2013,1381832380522 --> UTC time:Tue Oct 15 10:19:40 CEST 2013,1381825180000
UTC time:Tue Oct 15 10:19:40 CEST 2013,1381825180000 --> Local:Tue Oct 15 12:19:40 CEST 2013-1381832380000
Автор: trylimits
Размещён: 15.10.2013 10:19
4 плюса
Joda времени
ОБНОВЛЕНИЕ: проект Joda-Time сейчас находится в режиме обслуживания , и команда советует перейти на классы java.time . Смотрите Учебник по Oracle .
Посмотрите мой другой ответ, используя лучшие в отрасли классы java.time .
Обычно мы считаем плохой формой на StackOverflow.com отвечать на конкретный вопрос, предлагая альтернативную технологию. Но в случае классов даты, времени и календаря, связанных с Java 7 и более ранними версиями, эти классы настолько заведомо плохи как в дизайне, так и в исполнении, что я вынужден предложить вместо этого использовать стороннюю библиотеку: Joda-Time .
Joda-Time работает, создавая неизменные объекты . Поэтому вместо того, чтобы изменять часовой пояс объекта DateTime, мы просто создаем новый DateTime с другим назначенным часовым поясом.
Ваша главная задача использования местного и UTC-времени очень проста в Joda-Time, занимая всего 3 строки кода.
org.joda.time.DateTime now = new org.joda.time.DateTime();
System.out.println( "Local time in ISO 8601 format: " + now + " in zone: " + now.getZone() );
System.out.println( "UTC (Zulu) time zone: " + now.toDateTime( org.joda.time.DateTimeZone.UTC ) );
Выход при запуске на западном побережье Северной Америки может быть:
Local time in ISO 8601 format: 2013-10-15T02:45:30.801-07:00
UTC (Zulu) time zone: 2013-10-15T09:45:30.801Z
Вот класс с несколькими примерами и дальнейшими комментариями. Использование Joda-Time 2.5.
/**
* Created by Basil Bourque on 2013-10-15.
* © Basil Bourque 2013
* This source code may be used freely forever by anyone taking full responsibility for doing so.
*/
public class TimeExample {
public static void main(String[] args) {
// Joda-Time - The popular alternative to Sun/Oracle's notoriously bad date, time, and calendar classes bundled with Java 8 and earlier.
// http://www.joda.org/joda-time/
// Joda-Time will become outmoded by the JSR 310 Date and Time API introduced in Java 8.
// JSR 310 was inspired by Joda-Time but is not directly based on it.
// http://jcp.org/en/jsr/detail?id=310
// By default, Joda-Time produces strings in the standard ISO 8601 format.
// https://en.wikipedia.org/wiki/ISO_8601
// You may output to strings in other formats.
// Capture one moment in time, to be used in all the examples to follow.
org.joda.time.DateTime now = new org.joda.time.DateTime();
System.out.println( "Local time in ISO 8601 format: " + now + " in zone: " + now.getZone() );
System.out.println( "UTC (Zulu) time zone: " + now.toDateTime( org.joda.time.DateTimeZone.UTC ) );
// You may specify a time zone in either of two ways:
// • Using identifiers bundled with Joda-Time
// • Using identifiers bundled with Java via its TimeZone class
// ----| Joda-Time Zones |---------------------------------
// Time zone identifiers defined by Joda-Time…
System.out.println( "Time zones defined in Joda-Time : " + java.util.Arrays.toString( org.joda.time.DateTimeZone.getAvailableIDs().toArray() ) );
// Specify a time zone using DateTimeZone objects from Joda-Time.
// http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTimeZone.html
org.joda.time.DateTimeZone parisDateTimeZone = org.joda.time.DateTimeZone.forID( "Europe/Paris" );
System.out.println( "Paris France (Joda-Time zone): " + now.toDateTime( parisDateTimeZone ) );
// ----| Java Zones |---------------------------------
// Time zone identifiers defined by Java…
System.out.println( "Time zones defined within Java : " + java.util.Arrays.toString( java.util.TimeZone.getAvailableIDs() ) );
// Specify a time zone using TimeZone objects built into Java.
// http://docs.oracle.com/javase/8/docs/api/java/util/TimeZone.html
java.util.TimeZone parisTimeZone = java.util.TimeZone.getTimeZone( "Europe/Paris" );
System.out.println( "Paris France (Java zone): " + now.toDateTime(org.joda.time.DateTimeZone.forTimeZone( parisTimeZone ) ) );
}
}
Автор: Basil Bourque
Размещён: 15.10.2013 10:00
3 плюса
ТЛ; др
Instant.now() // Capture the current moment in UTC.
.atZone( ZoneId.systemDefault() ) // Adjust into the JVM's current default time zone. Same moment, different wall-clock time. Produces a `ZonedDateTime` object.
.toInstant() // Extract a `Instant` (always in UTC) object from the `ZonedDateTime` object.
.atZone( ZoneId.of( "Europe/Paris" ) ) // Adjust the `Instant` into a specific time zone. Renders a `ZonedDateTime` object. Same moment, different wall-clock time.
.toInstant() // And back to UTC again.
java.time
Современный подход использует классы java.time, которые вытеснили проблемные старые унаследованные классы даты и времени ( Date
, Calendar
и т. Д.).
Использование вами слова «local» противоречит использованию в классе java.time . В java.time «местный» означает любой населенный пункт или все населенные пункты, но не один конкретный населенный пункт. В java.time классы с именами , начинающимися с «Local ...» все не хватает какой - либо концепции временной зоны или офсетным из-UTC. Таким образом, они не представляют конкретный момент, они не являются точкой на временной шкале, в то время как ваш Вопрос связан с моментами, точками на временной шкале, просматриваемыми в различные часы.
Получить текущее системное время (местное время)
Если вы хотите зафиксировать текущий момент в UTC, используйте Instant
. Instant
Класс представляет собой момент на временной шкале в формате UTC с разрешением наносекунд (до девяти (9) цифр десятичной дроби).
Instant instant = Instant.now() ; // Capture the current moment in UTC.
Настройтесь на часовой пояс, применяя, ZoneId
чтобы получить ZonedDateTime
. Тот же самый момент, та же самая точка на временной шкале, другое время настенных часов.
Укажите правильное время имя зоны в формате continent/region
, например America/Montreal
, Africa/Casablanca
или Pacific/Auckland
. Никогда не используйте 3-4-буквенное сокращение, такое как EST
или IST
поскольку они не являются истинными часовыми поясами, не стандартизированы и даже не уникальны (!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, different wall-clock time.
В качестве ярлыка, вы можете пропустить использование, Instant
чтобы получить ZonedDateTime
.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
Конвертировать местное время в UTC // Работает отлично До здесь
Вы можете отрегулировать от зонированной даты и времени до UTC, извлекая Instant
из ZonedDateTime
.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
Instant instant = zdt.toInstant() ;
Обратное время UTC, назад к местному времени.
Как показано выше, примените a, ZoneId
чтобы скорректировать тот же момент в другое время на настенных часах, используемое людьми определенного региона (часового пояса).
Instant instant = Instant.now() ; // Capture current moment in UTC.
ZoneId zDefault = ZoneId.systemDefault() ; // The JVM's current default time zone.
ZonedDateTime zdtDefault = instant.atZone( zDefault ) ;
ZoneId zTunis = ZoneId.of( "Africa/Tunis" ) ; // The JVM's current default time zone.
ZonedDateTime zdtTunis = instant.atZone( zTunis ) ;
ZoneId zAuckland = ZoneId.of( "Pacific/Auckland" ) ; // The JVM's current default time zone.
ZonedDateTime zdtAuckland = instant.atZone( zAuckland ) ;
Возвращаясь к UTC с зонированной даты и времени, звоните ZonedDateTime::toInstant
. Концептуально думайте об этом как: ZonedDateTime = Instant + ZoneId .
Instant instant = zdtAuckland.toInstant() ;
Все эти объекты, Instant
и все три ZonedDateTime
объекта представляют один и тот же момент одновременности, одну и ту же точку истории.
Использовали 3 разных подхода (перечислены ниже), но все 3 подхода сохраняют время только в UTC.
Забудьте о попытке исправить код , используя эти ужасные Date
, Calendar
и GregorianCalendar
классы. Это жалкий беспорядок плохого дизайна и недостатков. Тебе больше никогда не нужно их трогать. Если вам нужно взаимодействовать со старым кодом, который еще не обновлен до java.time , вы можете конвертировать туда и обратно с помощью новых методов преобразования, добавленных к старым классам.
О java.time
Java.time каркас встроен в Java 8 и более поздних версий. Эти классы вытеснять неприятные старые устаревшие классы даты и времени , такие как java.util.Date
, Calendar
, и SimpleDateFormat
.
Проект Joda-Time , находящийся сейчас в режиме обслуживания , рекомендует перейти на классы java.time .
Чтобы узнать больше, смотрите Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .
Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, соответствующий JDBC 4.2 или более поздней версии . Нет необходимости в строках, нет необходимости в java.sql.*
классах.
Где взять классы java.time?
- Java SE 8 , Java SE 9 , Java SE 10 и более поздние версии
- Встроенный.
- Часть стандартного Java API с комплексной реализацией.
- Java 9 добавляет некоторые незначительные функции и исправления.
- Java SE 6 и Java SE 7
- Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport .
- Android
- Более поздние версии Android связывают реализации классов java.time.
- Для более ранних версий Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). Смотрите Как использовать ThreeTenABP… .
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь , такие как Interval
, YearWeek
, YearQuarter
, и более .
2 плюса
У вас есть дата с известным часовым поясом (Здесь Europe/Madrid
) и целевой часовой пояс ( UTC
)
Вам просто нужно два SimpleDateFormats:
long ts = System.currentTimeMillis (); Дата localTime = новая дата (тс); SimpleDateFormat sdfLocal = new SimpleDateFormat ("гггг / мм / дд чч: мм: сс"); sdfLocal.setTimeZone (TimeZone.getTimeZone ( "Europe / Madrid")); SimpleDateFormat sdfUTC = новый SimpleDateFormat ("гггг / мм / дд чч: мм: сс"); sdfUTC.setTimeZone (TimeZone.getTimeZone ( "UTC")); // Преобразование местного времени в UTC Date utcTime = sdfLocal.parse (sdfUTC.format (localTime)); System.out.println ("Local:" + localTime.toString () + "," + localTime.getTime () + "-> время UTC:" + utcTime.toString () + "-" + utcTime.getTime ( )); // Обратное преобразование времени UTC в местное время localTime = sdfUTC.parse (sdfLocal.format (utcTime)); System.out.println ("UTC:" + utcTime.toString () + "," + utcTime.getTime () + "-> Местное время:" + localTime.toString () + "-" + localTime.getTime ( ));
Таким образом, после того, как вы увидите, что он работает, вы можете добавить этот метод к своим утилитам:
public Date convertDate (Date dateFrom, String fromTimeZone, String toTimeZone) выдает ParseException { Образец строки = "гггг / мм / дд чч: мм: сс"; SimpleDateFormat sdfFrom = new SimpleDateFormat (шаблон); sdfFrom.setTimeZone (TimeZone.getTimeZone (fromTimeZone)); SimpleDateFormat sdfTo = новый SimpleDateFormat (шаблон); sdfTo.setTimeZone (TimeZone.getTimeZone (toTimeZone)); Date dateTo = sdfFrom.parse (sdfTo.format (dateFrom)); вернуть dateTo; }Автор: albfan Размещён: 01.08.2016 09:04
2 плюса
Я присоединяюсь к хору рекомендуя , что вы пропустите уже давно устаревшие классы Date
, Calendar
, SimpleDateFormat
и друг. В частности, я бы предостерег от использования устаревших методов и конструкторов Date
класса, таких как Date(String)
используемый вами конструктор. Они устарели, потому что они не работают надежно в разных часовых поясах, поэтому не используйте их. И да, большинство конструкторов и методов этого класса устарели.
В то время как вы задавали вопрос, Joda-Time был (насколько я знаю) явно лучшей альтернативой, время снова пошло дальше. Сегодня Joda-Time - в значительной степени законченный проект, и его разработчики рекомендуют использовать java.time
вместо этого современный Java-интерфейс даты и времени. Я покажу вам, как.
ZonedDateTime localTime = ZonedDateTime.now(ZoneId.systemDefault());
// Convert Local Time to UTC
OffsetDateTime gmtTime
= localTime.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC);
System.out.println("Local:" + localTime.toString()
+ " --> UTC time:" + gmtTime.toString());
// Reverse Convert UTC Time to Local time
localTime = gmtTime.atZoneSameInstant(ZoneId.systemDefault());
System.out.println("Local Time " + localTime.toString());
Для начала, обратите внимание, что код не только вдвое меньше вашего, но и понятнее.
На моем компьютере код печатает:
Local:2017-09-02T07:25:46.211+02:00[Europe/Berlin] --> UTC time:2017-09-02T05:25:46.211Z
Local Time 2017-09-02T07:25:46.211+02:00[Europe/Berlin]
Я пропустил миллисекунды из эпохи. Вы всегда можете получить их, System.currentTimeMillis();
как в вашем вопросе, и они не зависят от часового пояса, поэтому я не нашел их здесь интересными.
Я нерешительно сохранил ваше имя переменной localTime
. Я думаю, что это хорошее имя. В современном API есть класс с именем LocalTime
, поэтому использование этого имени, только без заглавной буквы, LocalTime
может привести к путанице в объекте, у которого нет типа (a LocalTime
не содержит информацию о часовом поясе, которую мы должны здесь сохранить, чтобы иметь возможность правильное преобразование, оно также содержит только время суток, а не дату).
Ваше преобразование из местного времени в UTC было неправильным и невозможным
Устаревший Date
класс не содержит никакой информации о часовом поясе (вы можете сказать, что внутренне он всегда использует UTC), поэтому нет такой вещи, как преобразование Date
одного часового пояса в другой. Когда я просто запустил ваш код на моем компьютере, первая напечатанная строка была:
Local:Sat Sep 02 07:25:45 CEST 2017,1504329945967 --> UTC time:Sat Sep 02 05:25:45 CEST 2017-1504322745000
07:25:45 CEST
правильно, конечно. Правильное время UTC было бы 05:25:45 UTC
, но он CEST
снова говорит , что неверно.
Теперь вам больше никогда не понадобится этот Date
класс, :-), но если вы когда-нибудь захотите, то обязательно прочитайте « Все о java.util.Date» в кодовом блоге Джона Скита.
Вопрос: Могу ли я использовать современный API с моей версией Java?
Если вы используете хотя бы Java 6 , вы можете.
- В Java 8 и более поздних версиях новый API поставляется встроенным.
- В Java 6 и 7 получают ThreeTen Backport , бэкпорт новых классов (это ThreeTen для JSR-310, где впервые был определен современный API).
- На Android используйте Android-версию ThreeTen Backport. Он называется ThreeTenABP, и я думаю, что в этом вопросе есть замечательное объяснение : как использовать ThreeTenABP в Android Project .
1 плюс
Я настоятельно рекомендую использовать Joda Time http://joda-time.sourceforge.net/faq.html
Автор: Tomasz Waszczyk Размещён: 15.10.2013 07:21Вопросы из категории :
- java В чем разница между int и Integer в Java и C #?
- java Как я могу определить IP моего маршрутизатора / шлюза в Java?
- java Каков наилучший способ проверки XML-файла по сравнению с XSD-файлом?
- java Как округлить результат целочисленного деления?
- simpledateformat Как разобрать дату?
- simpledateformat Несовместимый разбор дат с использованием SimpleDateFormat
- simpledateformat SimpleDateFormat и строка формата на основе локали
- simpledateformat simpledateformat parsing date with 'Z' literal
- utc Как преобразовать локальное время в UTC в Python?
- utc Почему DateTime.Now.ToString ("u") не работает?
- utc Как заставить функции MySQL NOW () и CURDATE () использовать UTC?
- utc Как вы конвертируете дату JavaScript в UTC?
- date-formatting Format date in <f:selectItem(s) itemLabel> using DateTimeConverter
- date-formatting Как отформатировать время с ххх, например, «4 минуты назад», как на сайтах Stack Exchange
- date-formatting Дата разбора в MySQL
- date-formatting Существует ли формат даты для отображения дня недели в java?
- timestamp-with-timezone Google timezone API - параметр временной метки
- timestamp-with-timezone Параметр даты без часовой пояс javascript
- timestamp-with-timezone Java Convert GMT / UTC по местному времени не работает должным образом
- timestamp-with-timezone STR_TO_DATE и ISO8601 в формате Atomtime