簡體   English   中英

為什么通過僅設置一個TimeZone,SimpleDateFormat.format()和SimpleDateFormat.parse()會給出不同的時間?

[英]Why SimpleDateFormat.format() and SimpleDateFormat.parse() are giving different time though setting only one TimeZone?

我正在嘗試通過SimpleDateFormat將時區設置為其他國家的時區。 SimpleDateFormat.format()返回給定時區的正確當前時間,但是SimpleDateFormat.parse()返回本地當前時間,我不知道為什么會這樣。 這是我的代碼-

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:MM:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
System.out.println("Time1 : " + dateFormat.format(new Date()));
System.out.println("Time2 : " + dateFormat.parse(dateFormat.format(new Date())));

輸出是-

Time1 : 2013-01-17 21:01:55
Time2 : Fri Jan 18 10:30:55 IST 2013

Time1是“ America / Los_Angeles”的輸出,而Time2是local(即“ Asia / Calcutta”)的輸出

我只想要UTC秒格式的給定時區的當前時間(即,自1970年1月1日以來的秒)。

為什么雖然只設置一個時區,但SimpleDateFormat.format()和SimpleDateFormat.parse()卻給出了不同的時間?

請幫我。

使用Parse ,您可以命令編譯器理解特定格式的給定日期。 它了解並保持其自己的格式,並准備提供您想要的任何格式!

您將得到一個輸出,這表示您輸入日期已成功解析。 您無法控制變量存儲的date的格式。

使用格式,您可以將日期轉換為任何所需的格式。

只需解析->閱讀(我可以以任何方式閱讀並以我想要的任何方式存儲)格式->寫(我會以您想要的格式給您)

dateFormat.format()將為您提供給定格式的輸出,並將時區更改為格式化程序中設置的時區。 (例如dateFormat.setTimeZone(TimeZone.getTimeZone(“ America / Los_Angeles”)));)

而dateFormat.parse()假定日期已在提到的時區中,它將日期轉換為您的本地時區。

第二個println中的dateFormat.parse()

System.out.println("Time2 : " + dateFormat.parse(dateFormat.format(new Date())));

返回Date和Date.toString()以EEE MMM dd HH:mm:ss zzz yyyy格式返回日期的字符串表示形式。 參見Date.toString()API

在第一行中,您正在將本地日期格式化為特定時區,它將返回一個字符串,該字符串表示在特定時區中傳遞的參數日期,但是解析函數有所不同。它將返回一個日期對象,該對象表示自一月份以來的毫秒數1970年1月1日,UTC。 它不包含任何時區信息。

tl; dr

糟糕的舊日期時間類非常令人困惑,尤其是在處理隱式默認時區時。 但是,您的謎尚無足輕重 ,因為這些可怕的舊類早在幾年前就被現代的java.time類所取代。

Instant.now()                // Capture current moment in UTC. This class replaces `java.util.Date`. 
.atZone(                     // Adjust from UTC to the wall-clock time used by the people of a particular region, a time zone.
    ZoneId.of( "America/Montreal" ) 
)                            // Returns a `ZonedDateTime`
.format(
    DateTimeFormatter.ISO_LOCAL_DATE_TIME
)                            // Returns a String like: `2013-01-17T21:01:55`.
.replace( "T" , " " )        // Replace the `T` in the middle (from the standard ISO 8601 format) with a SPACE.

2013-01-17 21:01:55

java.time

由於可怕的舊日期時間類(例如SimpleDateFormat已被java.time取代,因此該問題不存在

當前時刻

java.util.Date類由java.time.Instant替換。 兩者都代表UTC時刻,始終代表UTC。 (盡管在應用JVM的當前默認時區時對您說謊,盡管Date::toString 。)

Instant instant = Instant.now() ;  // Capture current moment in UTC.

調整到一個時區。

ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

調整到另一個時區。

ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" ) ;  // Contemporary time in India. 
ZonedDateTime zdtKolkata = instant.atZone( zKolkata ) ;

這三個對象( instantzdtzdtKolkata )都表示同一時刻 ,時間軸上的同一點。 只有掛鍾時間不同。

弦樂

當生成表示日期時間值的字符串時,除非上下文絕對清晰,否則我建議始終包括偏移量/區域信息。 在時間范圍不明確的報告中,我在商業世界中看到了很多困惑。

但是,如果您堅持要用DateTimeFormatter類定義自己的格式化模式,或者使用給定的格式化程序ISO_LOCAL_DATE_TIME並將中間的T替換為SPACE。

DateTimeFormatter f = DateTimeFormatter.ISO_LOCAL_DATE_TIME ;
String output = zdt.format( f ) ;

2013-01-17 21:01:55

未分區日期時間

問題的一部分是您的字符串的歧義2013-01-17 21:01:55 該字符串缺少任何時區或UTC偏移量的指示。 這樣的值不是時刻, 也不是時間軸上的一點。 例如,印度的晚上9點比魁北克的晚上9點早幾個小時。 沒有區域或偏移量,該字符串僅代表沿全球時區范圍約26-27小時的潛在時刻。

傳統類沒有此類代表這種價值的類。 在現代類中,我們為此設置了LocalDateTime ,這是一個無時區,日期和時間的無區域/偏移量。

解析/生成字符串時, java.time類默認使用ISO 8601標准格式。 您的輸入幾乎符合要求。 我們只需要在中間用T替換SPACE即可。

LocalDateTime ldt = LocalDateTime.parse( "2013-01-17 21:01:55".replace( "" , "T" ) ) ;

如果您知道該字符串后面的意圖是表示特定時區中的某個時刻,請應用ZoneId來獲取ZonedDateTime 例如,如果您確定它代表了北美大部分西海岸的一刻,請使用America/Los_Angeles

ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ; 

要從該區域調整為UTC,請提取一個Instant對象。 Instant類以UTC表示時間軸上的時刻,分辨率為納秒 (最多十進制的九(9)位數字)。

Instant instant = zdt.toInstant() ;  // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.

關於java.time

java.time框架內置於Java 8及更高版本中。 這些類取代了麻煩的舊的舊式日期時間類,例如java.util.DateCalendarSimpleDateFormat

現在處於維護模式Joda-Time項目建議遷移到java.time類。

要了解更多信息,請參見Oracle教程 並在Stack Overflow中搜索許多示例和說明。 規格為JSR 310

您可以直接與數據庫交換java.time對象。 使用與JDBC 4.2或更高版本兼容的JDBC驅動程序 不需要字符串,不需要java.sql.*類。

在哪里獲取java.time類?

ThreeTen-Extra項目使用其他類擴展了java.time。 該項目為將來可能在java.time中添加內容提供了一個試驗場。 您可以在這里找到一些有用的類,比如IntervalYearWeekYearQuarter ,和更多

暫無
暫無

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

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