簡體   English   中英

Java將19位Unix時間戳轉換為可讀日期

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

我正在嘗試將19位Unix時間戳(例如1558439504711000000 (一個五分之五 ))轉換為可讀的日期/時間格式。 我的時間戳以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格式顯示年份格式。

tl; dr

永遠不要使用遺留類java.util.Date 而是使用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

…要么…

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類很糟糕 連同它的CalendarSimpleDateFormat ,真是一團糟。 避免他們。 Sun,Oracle和JCP社區在采用JSR 310時放棄了它們。

Instant

一個java.util.Date對象用UTC表示一個時刻,分辨率為毫秒 它的替換內容是java.time.Instant ,也是UTC中的一刻,但分辨率為納秒 UTC 1970年第一時刻紀元參考開始,兩者在內部都進行計數。

為了避免處理巨大的數字, Instant在內部跟蹤自1970年以來的整數秒, 外加小數秒(以納秒為單位)。 兩個單獨的數字。 這些就是您需要提供Instant.ofEpochSecond

使用Long類將輸入字符串解析為long 順便說一句,請注意您的值正在逼近64位整數的限制

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

使用TimeUnit 枚舉來算出整秒的數學運算。

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

為十億分之一,其余為小數秒的納秒。

long nanosPortion = ( totalNanos % 1_000_000_000L ) ;

實例化一個Instant

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

我的時間戳以6個零結尾,這表明時間以納秒為單位。

實際上,納秒的計數高達十億,因此九(9)位數字不是六(6)位。 從紀元開始711000000711000000 ,即711,000,000納秒。 您的總秒數為1558439504或1,558,439,504(十億分之一)。 作為小數點:

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

時區

我遇到了一些示例,其中人們使用了我不需要的時區。

為了表示一個時刻,即時間軸上的特定點, 始終需要一個時區 (或從UTC偏移小時-分鍾-秒)。

要查看特定區域(時區)的人們在牆上時鍾所用的同一時刻,請應用ZoneId來獲取ZonedDateTime

Continent/Region的格式指定正確的時區名稱 ,例如America/MontrealAfrica/CasablancaPacific/Auckland 切勿使用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 [歐洲/倫敦]

請注意一天中的時間調整,從11點到12點。這很有意義,因為Europe/London地區比該日期的UTC早一個小時。 同一時刻,時間軸上的同一點,不同的時鍾時間。

捷徑

正如Ole VV在評論中指出的,您可以跳過上面討論的數學。 將完整的納秒數作為ofEpochSecond的第二個參數。 該類在內部進行數學運算,以將整秒與小數秒分開。

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

看到此代碼在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

提示:在提供日期時間時要非常小心,不要顯式指定區域。 這會產生歧義,用戶可能會假設正在玩一個不同的區域/偏移。

我認為這沒什么不對,您正在處理一個表示FUTURE(未來)中某個日期的時間戳(將來的日期非常遙遠)。

如果您考慮以下情況:

String timeStamp = "1558439504";

這應該給你:05/21/2019 @ 11:51 am(UTC)

然后,我想一種簡單的方法來獲取日期。 只需首先根據該時間戳創建即時消息,然后執行以下操作:

Date myDate = Date.from(instant);

試試這個

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

而不是乘以1000 ,除以1000000

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM