ТЛ; др
Никогда не используйте устаревший класс java.util.Date
. Вместо этого используйте современные java.time.Instant
.
Instant // The modern way to represent a moment in UTC with a resolution of nanoseconds. Supplants the terrible `java.util.Date` class.
.ofEpochSecond( // Parse a count since epoch reference of 1970-01-01T00:00:00Z.
0L , // Passing zero for the count of whole seconds, to let the class determine this number from the 2nd argument.
Long.parse( "1558439504711000000" ) // Count of nanoseconds since the epoch reference of 1970-01-01T00:00:00Z.
) // Returns a `Instant` object.
.atZone( // Adjust from UTC to the wall-clock time used by the people of a specific region (a time zone).
ZoneId.of( "Europe/London" )
) // Returns a `ZonedDateTime` object. Same moment as the `Instant`, same point on the timeline, different wall-clock time.
.format( // Generate text to communicate the value of the moment as seen through this time zone.
DateTimeFormatter.ofPattern( // Define how to format our generated text.
"dd-MM-uuuu HH:mm:ss" , // Specify your desired formatting pattern.
Locale.UK // Pass a `Locale` to be used in localizing, to (a) determine human language used in translating name of day-of-week and such, and (b) determine cultural norms to decide issues of capitalization, abbreviation, etc. Not really needed for this particular formatting pattern, but a good habit to specify `Locale`.
) // Returns a `DateTimeFormatter` object.
) // Returns a `String` object containing our text.
21-05-2019 12: 51: 44
... или ...
Instant
.ofEpochSecond (
TimeUnit.NANOSECONDS.toSeconds(
Long.parse( "1558439504711000000" )
) ,
( 1_558_439_504_711_000_000L % 1_000_000_000L )
)
.toString()
2019-05-21T11: 51: 44.711Z
Обратите внимание на разницу в часах, потому что часовой пояс на час впереди UTC.
Избегайте устаревших классов даты и времени
java.util.Date
класс ужасен . Наряду с однопометниками, такими как Calendar
& SimpleDateFormat
, они представляют собой ужасный беспорядок. Избежать их. Sun, Oracle и сообщество JCP отказались от них, когда они приняли JSR 310.
Instant
Объект java.util.Date
представляет момент в UTC с разрешением миллисекунд . Его замена составляет java.time.Instant
, также в UTC, но с разрешением наносекунд . Внутренне, оба отслеживают счет начиная с эталона эпохи из первого момента 1970 года в UTC .
Чтобы не иметь дело с гигантскими числами, внутренне Instant
отслеживает количество целых секунд с 1970 плюс доли секунды, сохраняемой как число наносекунд. Два отдельных номера. Это то, что вам нужно кормить Instant.ofEpochSecond
.
Разобрать вашу входную строку как long
, используя класс Long
. Кстати, обратите внимание, что ваше значение приближается к пределу 64-битного целого числа.
long totalNanos = Long.parse( "1558439504711000000" ) ;
Используйте TimeUnit
enum , чтобы вычислить целые секунды.
long secondsPortion = TimeUnit.NANOSECONDS.toSeconds( totalNanos ) ;
по модулю на миллиард, остаток - наносекунды доли секунды.
long nanosPortion = ( totalNanos % 1_000_000_000L ) ;
Создание Instant
.
Instant instant = Instant.ofEpochSecond( secondsPortion , nanosPortion ) ;
Моя временная метка заканчивается 6 нулями, что говорит о том, что время в нано секундах.
На самом деле наносекунды насчитывают до миллиарда, поэтому девять (9) цифр, а не шесть (6). Дробная секунда в вашем отсчете от эпохи составляет 711000000
, или 711 000 000 нано. Ваше целое число секунд составляет 1558439504
, или 1 558 439 504 (полтора миллиарда). В десятичном виде:
1558 439 504,711000000 с 1970-01-01T00: 00Z
Часовой пояс
Я сталкивался с некоторыми примерами, когда люди использовали часовые пояса, которые мне не нужны.
Чтобы представить момент, определенную точку на временной шкале, вам всегда нужен часовой пояс (или смещение от UTC часов-минут-секунд).
Чтобы увидеть тот же самый момент через часы настенного времени, используемые людьми определенного региона (часового пояса), примените ZoneId
, чтобы получить ZonedDateTime
.
Укажите собственное имя часового пояса в формате Continent/Region
, например America/Montreal
, Africa/Casablanca
или Pacific/Auckland
. Никогда не используйте 2-4-буквенное сокращение, такое как BST
или EST
или IST
, поскольку они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).
ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.
2019-05-21T12: 51: 44,711 + 01: 00 [Europe / London]
Обратите внимание на корректировку времени суток, переходя с 11 на 12 час. Это имеет смысл, поскольку зона Europe/London
на час опережает UTC на эту дату. Тот же момент, та же точка на временной шкале, другое время на настенных часах.
Ярлык
Как Оле В.В. отметил в комментарии, вы можете пропустить математику, обсужденную выше. Укажите все число наносекунд в качестве второго аргумента ofEpochSecond
. Класс внутренне выполняет математику, чтобы отделить целые секунды от доли секунды.
Instant instant = Instant.ofEpochSecond( 0L , 1_558_439_504_711_000_000L ) ;
См. Этот код, запущенный в режиме реального времени на IdeOne.com.
Создать текст
Создание текста, представляющего значение этого ZonedDateTime
в стандартном формате ISO 8601 , расширенном для добавления имени часового пояса в квадратных скобках.
String output = zdt.toString() ;
2019-05-21T12: 51: 44,711 + 01: 00 [Europe / London]
Или пусть java.time автоматически локализуется для вас.
Locale locale = Locale.UK;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT ).withLocale( locale );
String output = zdt.format( f );
21/05/2019, 12: 51
Или укажите пользовательский формат.
Locale locale = Locale.UK;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MM-uuuu HH:mm:ss" , locale ) ;
String output = zdt.format( f );
21-05-2019 12: 51: 44
Совет: будьте очень внимательны при указании даты и времени без явного указания зоны. Это создает неоднозначность, когда пользователь может предположить, что другая зона / смещение находятся в игре.