Java Преобразование 19-значной метки времени Unix в читаемую дату - PullRequest
0 голосов
/ 23 мая 2019

Я пытаюсь преобразовать 19-разрядную метку времени Unix, например 1558439504711000000 (полтора с половиной квинтиллион ), в читаемый формат даты / времени. Моя отметка времени заканчивается 6 нулями, что говорит о том, что время в нано секундах.

Я сталкивался с некоторыми примерами, когда люди использовали часовые пояса, которые мне не нужны. Другой пример использует EpochSecond так:

Instant instant = Instant.ofEpochSecond(seconds, nanos);

Но я не уверен, нужно ли мне использовать EpochSecond.

Код ниже дает мой самый последний подход к достижению этого:

String timeStamp = "1558439504711000000";
long unixNanoSeconds = Long.parseLong(timeStamp);
Date date = new java.util.Date(timeStamp*1000L); 
// My preferred date format
SimpleDateFormat sdf = new java.text.SimpleDateFormat("dd-MM-yyyy HH:mm:ss");                    
String formattedDate = sdf.format(date);
System.out.println("The timestamp in your preferred format is: " +  formattedDate); 

Но вывод, который я получаю, выглядит примерно так:

// The timestamp in your preferred format is: 11-12-49386951 11:43:20

Который не показывает формат года, например, Формат 2019.

Ответы [ 3 ]

2 голосов
/ 23 мая 2019

ТЛ; др

Никогда не используйте устаревший класс 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

Совет: будьте очень внимательны при указании даты и времени без явного указания зоны. Это создает неоднозначность, когда пользователь может предположить, что другая зона / смещение находятся в игре.

0 голосов
/ 23 мая 2019

Попробуйте использовать это

Date date = new java.util.Date(timeStamp/1000000); 

Вместо умножения на 1000 , разделите на 1000000

0 голосов
/ 23 мая 2019

Я думаю, что в этом нет ничего плохого, вы имеете дело с меткой времени, представляющей дату в БУДУЩЕМ (действительно далекую дату в будущем).

Если учесть это:

String timeStamp = "1558439504";

это должно дать вам: 21.05.2009 @ 11:51 (UTC)

Тогда есть простой способ получить Дату. Просто сначала создайте Instant на основе этой временной метки, а затем выполните:

Date myDate = Date.from(instant);
...