Як отримати дату UTC + 0 у Java 8?


108

У мене проблеми з класом Date на Java. Клас дати повертає дату локальної машини, але мені потрібна UTC-0.

Я переглянув Google і знайшов чудове рішення для JavaScript, але для Java нічого корисного.

Як отримати дату UTC + 0 у Java 8?


12
java.util.Dateніколи не є місцевою машинною датою. Він завжди визначається як пропущений мілісек з 1970-01-01 щодо UTC + 00: 00. Можливо, поведінка його методу toString()збиває з пантелику те, що справді використовує представлення в локальному часовому поясі.
Meno Hochschild

Одну вірогідну відповідь можна знайти у питанні: stackoverflow.com/questions/45350095/…
Priya Jain

Відповіді:


146

З Java 8 ви можете писати:

OffsetDateTime utc = OffsetDateTime.now(ZoneOffset.UTC);

Щоб відповісти на ваш коментар, ви можете потім перетворити його на дату (якщо ви не залежите від застарілого коду, я не бачу жодної причини) або в мільйони з епох:

Date date = Date.from(utc.toInstant());
long epochMillis = utc.toEpochSecond() * 1000;

1
Дякую. можна перетворити ZonedDateTime в Date або в long (мс)?
Марк

7
Хоча код цього відповіді технічно працює, чи не буде його більш доцільним використовувати OffsetDateTime, ніж ZonedDateTimeвраховуючи, що ми працюємо з простою зміщенням від UTC, а не повним часовим поясом?
Василь Бурк

179

тл; д-р

Instant.now()

java.time

Смутні старі класи дат у часі з найдавнішими версіями Java були витіснені класами java.time, вбудованими в Java 8 і пізніші версії. Дивіться навчальний посібник Oracle . Значна частина функцій була підпорядкована на Java 6 та 7 у ThreeTen-Backport та додатково адаптована до Android у ThreeTenABP .

Instant

Позначає Instantмомент на часовій шкалі в UTC з роздільною здатністю до наносекунд .

Instant instant = Instant.now();

toStringМетод створює об'єкт типу String з текстом , що представляє значення дати і час , використовуючи один із стандартних ISO 8601 форматів.

String output = instant.toString();  

2016-06-27T19: 15: 25.864Z

InstantКлас є основним класом многокомпонентного в java.time. Це має бути ваш клас переходу під час обробки дати та часу, як правило, найкраща практика - відстежувати, зберігати та обмінювати значення дати в часі за UTC.

OffsetDateTime

Але Instantє такі обмеження, як відсутні параметри форматування для генерації рядків в альтернативних форматах. Для більшої гнучкості перетворіть Instantна OffsetDateTime. Вкажіть зміщення з-за UTC . У java.time це означає ZoneOffsetоб’єкт. Тут ми хочемо дотримуватися UTC (+00), щоб ми могли використовувати зручну константу ZoneOffset.UTC.

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC );

2016-06-27T19: 15: 25.864Z

Або пропустити Instantклас.

OffsetDateTime.now( ZoneOffset.UTC )

Тепер із OffsetDateTimeоб’єктом в руці ви можете використовувати DateTimeFormatterдля створення об'єктів String з текстом у альтернативних форматах. Переповнення стека пошуку для багатьох прикладів використання DateTimeFormatter.

ZonedDateTime

Коли ви хочете відобразити настінні годинники для певного часового поясу, застосуйте a, ZoneIdщоб отримати ZonedDateTime.

У цьому прикладі ми застосовуємо часовий пояс Монреаля. Влітку, за дурниць літнього часу (DST) , зона компенсується -04:00. Тому зауважте, як час виходу на чотири години раніше на виході, 15а не на 19години. Instantі те ZonedDateTimeі інше представляють той самий одночасний момент, щойно переглядається через дві різні лінзи.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

2016-06-27T15: 15: 25.864-04: 00 [Америка / Монреаль]

Перетворення

Хоча вам слід уникати старих класів дати-часу, якщо потрібно, ви можете конвертувати, використовуючи нові методи, додані до старих класів. Тут ми використовуємо java.util.Date.from( Instant )і java.util.Date::toInstant.

java.util.Date utilDate = java.util.Date.from( instant );

І йти іншим напрямком.

Instant instant= utilDate.toInstant();

Аналогічно шукайте нові методи, додані в GregorianCalendar(підклас Calendar) для перетворення в і з java.time.ZonedDateTime.

Таблиця типів класів дати-часу в сучасному java.time порівняно зі спадщиною.

Про java.time

Java.time каркас вбудований в Java 8 і пізніших версій. Ці класи витісняти неприємні старі застарілі класи дати і часу , такі як java.util.Date, Calendar, і SimpleDateFormat.

Щоб дізнатися більше, дивіться навчальний посібник Oracle . І шукайте переповнення стека за багатьма прикладами та поясненнями. Специфікація - JSR 310 .

Проект Joda-Time , який зараз знаходиться в режимі обслуговування , радить перейти до класів java.time .

Ви можете обмінюватися об'єктами java.time безпосередньо зі своєю базою даних. Використовуйте драйвер JDBC, сумісний з JDBC 4.2 або пізнішої версії. Немає необхідності в струнах, немає потреби в java.sql.*заняттях. Hibernate 5 & JPA 2.2 підтримують java.time .

Де отримати класи java.time?



тож якби DST не існувало ZonedDateTime, не було б потрібним, оскільки всі ZoneIdвідображатимуться до одного, який ZoneOffsetми могли б просто використати OffsetDateTime?
wilmol

1
@wilmol Ні. Перехід на літній час - лише одна з багатьох причин, чому політики вирішують переосмислити межі та компенсації часових поясів у цих зонах. Нещодавно Північна Корея змінила годинник на півгодини, щоб синхронізуватися з Південною Кореєю з дипломатичних причин. На війні окупанти / окупанти можуть змінити зсув, щоб відповідати мірі країни. В даний час існує нова пристрасть, коли уряди вирішують зупинити зміни DST, але постійно залишаються на DST, а не повертаються до попереднього стандартного часу. Завжди плануйте компенсувати зміну кожної зони, інакше ваша програма згодом зламається.
Василь Бурк

1
Фантастична відповідь! Я дуже ціную час, який ти вклав у це. :)
drognisep

ZoneId.of ("Америка / Монреаль"); чому б хтось вигадував таке в jdk? це некрасиво, огидно, не розповідати, чи є щось погано до запуску, хто може запам'ятати всі ці важкі коди? чому б не включити його до класу ENUM?
workplaylifecycle

4

У java8 я би використовував Instantклас, який вже є в UTC і з ним зручно працювати.

import java.time.Instant;

Instant ins = Instant.now();
long ts = ins.toEpochMilli();

Instant ins2 = Instant.ofEpochMilli(ts)

Крім того, ви можете використовувати наступне:

import java.time.*;

Instant ins = Instant.now(); 

OffsetDateTime odt = ins.atOffset(ZoneOffset.UTC);
ZonedDateTime zdt = ins.atZone(ZoneId.of("UTC"));

Повертатися до Instant

Instant ins4 = Instant.from(odt);

3
Ні, в цьому Instantє НЕ за місцевим часом. За Instantвизначенням знаходиться в UTC. Тому немає необхідності в махінаціях, які бачили в цьому Відповіді, намагаючись потрапити в UTC; Instantвже знаходиться в UTC. Дивіться мою відповідь для отримання додаткової інформації та набагато простішого коду.
Василь Бурк

Дякуємо за коментар
Абель Терефе


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.