我试图将19位Unix时间戳(例如1558439504711000000
(一个quintillion一半)转换为可读的日期/时间格式。我的时间戳以6个零结尾,表示时间以纳秒为单位。
我遇到了一些例子,其中人们使用了我不需要的时区。另一个示例使用ofEpochSecond像这样:
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格式。
答案 0 :(得分:2)
请勿使用旧版类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中的时刻,分辨率为milliseconds。替换为java.time.Instant
,也是UTC的片刻,但分辨率为nanoseconds。在内部,两者都跟踪自epoch reference的first moment of 1970 in UTC开始的计数。
为避免处理巨大的数字,内部Instant
跟踪自1970年以来的整秒数,加上小数秒保持为纳秒。两个单独的数字。这些就是您需要喂Instant.ofEpochSecond
的地方。
使用Long
类将输入字符串解析为long
。顺便说一下,请注意,您的值正在逼近the limit整数的64-bit。
long totalNanos = Long.parse( "1558439504711000000" ) ;
long secondsPortion = TimeUnit.NANOSECONDS.toSeconds( totalNanos ) ;
Modulo十亿分之一,其余为小数秒的纳秒。
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(十亿分之一)。用小数点表示:
自1970-01-01T00:00Z开始的1,558,439,504.711000000秒
我遇到了一些例子,其中人们使用了我不需要的时区。
要表示时刻,是时间轴上的特定点,您总是需要time zone (或offset-from-UTC小时-分钟,秒)。
要查看特定区域(时区)的人们在墙上时钟所用的同一时刻,请应用ZoneId
以获得ZonedDateTime
。
以Continent/Region
的格式指定proper time zone name,例如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 [欧洲/伦敦]
请注意在一天中的调整时间,从11点到12点。这很有意义,因为Europe/London
区域比该日期的UTC早一个小时。同一时刻,时间轴上的同一点,不同的时钟时间。
如Ole V.V.在评论中指出,您可以跳过上面讨论的数学。将整个纳秒数作为ofEpochSecond
的第二个参数。该类在内部进行数学运算,以将整秒与小数秒分开。
Instant instant = Instant.ofEpochSecond( 0L , 1_558_439_504_711_000_000L ) ;
查看此code run live at IdeOne.com.
生成以标准ISO 8601格式表示该ZonedDateTime
的值的文本,该文本已扩展为将时区的名称附加在方括号中。
String output = zdt.toString() ;
2019-05-21T12:51:44.711 + 01:00 [欧洲/伦敦]
或者让 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
提示:在提供日期时间时要非常小心,不要显式指定区域。这会产生歧义,用户可能会假设正在玩一个不同的区域/偏移。
答案 1 :(得分:0)
我认为这没什么不对,您正在处理一个表示FUTURE(将来很远的日期)中的日期的时间戳。
如果您考虑这一点:
String timeStamp = "1558439504";
这应该给您:05/21/2019 @ 11:51 am(UTC)
然后我想有一种简单的方法来获取日期。只需首先根据该时间戳创建即时消息,然后执行:
Date myDate = Date.from(instant);
答案 2 :(得分:0)
尝试使用此
Date date = new java.util.Date(timeStamp/1000000);
除以 1000000
,而不是乘以 1000