简体   繁体   English

Java将19位Unix时间戳转换为可读日期

[英]Java Converting 19-digit Unix Timestamp to a Readable Date

I am trying to convert 19 digit Unix timestamp such as 1558439504711000000 (one and a half quintillion ) into a readable date/time format. 我正在尝试将19位Unix时间戳(例如1558439504711000000 (一个五分之五 ))转换为可读的日期/时间格式。 My timestamp ends with 6 zeros which suggests the time is in nano seconds. 我的时间戳以6个零结尾,这表明时间以纳秒为单位。

I have come across some examples where people have used time zones which I don't need. 我遇到了一些示例,其中人们使用了我不需要的时区。 Another example uses ofEpochSecond like so: 另一个示例使用ofEpochSecond像这样:

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

But I am not sure whether I need to use ofEpochSecond. 但是我不确定是否需要使用EpochSecond。

The code below gives my most recent approach of achieving this: 下面的代码提供了我最新的实现方法:

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); 

But the output I get is something like this: 但是我得到的输出是这样的:

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

Which does not show the year format in eg 2019 format. 它不以例如2019格式显示年份格式。

tl;dr tl; dr

Never use legacy class java.util.Date . 永远不要使用遗留类java.util.Date Instead, use modern java.time.Instant . 而是使用modern 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 21-05-2019 12:51:44

…or… …要么…

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 2019-05-21T11:51:44.711Z

Note the hour difference because the time zone is one hour ahead of UTC. 注意时差,因为时区比UTC早一小时。

Avoid legacy date-time classes 避免使用旧的日期时间类

The java.util.Date class is terrible . java.util.Date类很糟糕 Along with its littermates such as Calendar & SimpleDateFormat , they amount to a awful mess. 连同它的CalendarSimpleDateFormat ,真是一团糟。 Avoid them. 避免他们。 Sun, Oracle, and the JCP community gave up on them when they adopted JSR 310. Sun,Oracle和JCP社区在采用JSR 310时放弃了它们。

Instant

A java.util.Date object represents a moment in UTC , with a resolution of milliseconds . 一个java.util.Date对象用UTC表示一个时刻,分辨率为毫秒 Its replacement is java.time.Instant , also a moment in UTC but with a resolution of nanoseconds . 它的替换内容是java.time.Instant ,也是UTC中的一刻,但分辨率为纳秒 Internally, both track a count since the epoch reference of first moment of 1970 in UTC . UTC 1970年第一时刻纪元参考开始,两者在内部都进行计数。

To avoid dealing with gigantic numbers, internally a Instant tracks a number of whole seconds since 1970 plus a fractional second kept as a number of nanoseconds. 为了避免处理巨大的数字, Instant在内部跟踪自1970年以来的整数秒, 外加小数秒(以纳秒为单位)。 Two separate numbers. 两个单独的数字。 Those are what you need to feed Instant.ofEpochSecond . 这些就是您需要提供Instant.ofEpochSecond

Parse your input string as a long using the Long class. 使用Long类将输入字符串解析为long By the way, notice that your value is pushing towards to the limit of a 64-bit integer. 顺便说一句,请注意您的值正在逼近64位整数的限制

long totalNanos = Long.parse( "1558439504711000000" ) ;

Use the TimeUnit enum to do the math of splitting out whole seconds. 使用TimeUnit 枚举来算出整秒的数学运算。

long secondsPortion = TimeUnit.NANOSECONDS.toSeconds( totalNanos ) ;

Modulo by a billion, the remainder being the nanoseconds of the fractional second. 为十亿分之一,其余为小数秒的纳秒。

long nanosPortion = ( totalNanos % 1_000_000_000L ) ;

Instantiate an Instant . 实例化一个Instant

Instant instant = Instant.ofEpochSecond( secondsPortion , nanosPortion ) ;

My timestamp ends with 6 zeros which suggests the time is in nano seconds. 我的时间戳以6个零结尾,这表明时间以纳秒为单位。

Actually, nanoseconds count up to a billion, so nine (9) digits not six (6). 实际上,纳秒的计数高达十亿,因此九(9)位数字不是六(6)位。 The fractional second in your count from epoch is 711000000 , or 711,000,000 nanos. 从纪元开始711000000711000000 ,即711,000,000纳秒。 Your number of whole seconds is 1558439504 , or 1,558,439,504 (one and a half billion). 您的总秒数为1558439504或1,558,439,504(十亿分之一)。 As a decimal: 作为小数点:

1,558,439,504.711000000 seconds since 1970-01-01T00:00Z 自1970-01-01T00:00Z起1,558,439,504.711000000秒

Time Zone 时区

I have come across some examples where people have used time zones which I don't need. 我遇到了一些示例,其中人们使用了我不需要的时区。

To represent a moment, a specific point on the timeline, you always need a time zone (or offset-from-UTC of hours-minutes-seconds). 为了表示一个时刻,即时间轴上的特定点, 始终需要一个时区 (或从UTC偏移小时-分钟-秒)。

To see that same moment through the wall-clock time used by the people of a particular region (a time zone), apply a ZoneId to get a ZonedDateTime . 要查看特定区域(时区)的人们在墙上时钟所用的同一时刻,请应用ZoneId来获取ZonedDateTime

Specify a proper time zone name in the format of Continent/Region , such as America/Montreal , Africa/Casablanca , or Pacific/Auckland . Continent/Region的格式指定正确的时区名称 ,例如America/MontrealAfrica/CasablancaPacific/Auckland Never use the 2-4 letter abbreviation such as BST or EST or IST as they are not true time zones, not standardized, and not even unique(!). 切勿使用2-4个字母的缩写,例如BSTESTIST因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。

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] 2019-05-21T12:51:44.711 + 01:00 [欧洲/伦敦]

Notice the adjustment in the time-of-day, going from hour 11 to hour 12. This makes sense as Europe/London zone is an hour ahead of UTC on that date. 请注意一天中的时间调整,从11点到12点。这很有意义,因为Europe/London地区比该日期的UTC早一个小时。 Same moment, same point on the timeline, different wall-clock time. 同一时刻,时间轴上的同一点,不同的时钟时间。

Shortcut 捷径

As Ole VV noted in the comment, you could skip the math discussed above. 正如Ole VV在评论中指出的,您可以跳过上面讨论的数学。 Feed the entire number of nanoseconds as the second argument to ofEpochSecond . 将完整的纳秒数作为ofEpochSecond的第二个参数。 The class internally does the math to separate whole seconds from the fractional second. 该类在内部进行数学运算,以将整秒与小数秒分开。

Instant instant = Instant.ofEpochSecond( 0L , 1_558_439_504_711_000_000L ) ;

See this code run live at IdeOne.com. 看到此代码在IdeOne.com上实时运行。

Generate text 产生文字

Generate text representing the value of that ZonedDateTime in standard ISO 8601 format extended to append the name of the time zone in square brackets. 以标准ISO 8601格式生成表示该ZonedDateTime值的文本,该格式已扩展为将时区的名称附加在方括号中。

String output = zdt.toString() ;

2019-05-21T12:51:44.711+01:00[Europe/London] 2019-05-21T12:51:44.711 + 01:00 [欧洲/伦敦]

Or let java.time automatically localize for you. 或者让java.time自动为您本地化。

Locale locale = Locale.UK;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT ).withLocale( locale );
String output = zdt.format( f );

21/05/2019, 12:51 21/05/2019,12:51

Or specify a custom format. 或指定自定义格式。

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 21-05-2019 12:51:44

Tip: Be very careful about providing a date-time without specifying the zone explicitly. 提示:在提供日期时间时要非常小心,不要显式指定区域。 This creates ambiguity, where the user may assume a different zone/offset is in play. 这会产生歧义,用户可能会假设正在玩一个不同的区域/偏移。

I think there is nothing wrong with that, you are dealing with a timestamp that represent a date in the FUTURE (a really far away date in the future). 我认为这没什么不对,您正在处理一个表示FUTURE(未来)中某个日期的时间戳(将来的日期非常遥远)。

If you consider this: 如果您考虑以下情况:

String timeStamp = "1558439504";

this should give you: 05/21/2019 @ 11:51am (UTC) 这应该给你:05/21/2019 @ 11:51 am(UTC)

Then there is I think an easy way to get the Date. 然后,我想一种简单的方法来获取日期。 Just create the Instant first based on that timestamp and then do: 只需首先根据该时间戳创建即时消息,然后执行以下操作:

Date myDate = Date.from(instant);

Try using this 试试这个

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

Instead of multiplying by 1000 , divide by 1000000 而不是乘以1000 ,除以1000000

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM