2017-06-25 64 views
3

如何解析PDT時區中的此日期時間值?嘗試解析PDT中的日期時間爲ZonedDateTime表示形式

06/24/2017 07:00 AM (PDT) 

我想保留時區,以便我可以根據網站訪客偏好來表示其他時區的時間。

我嘗試使用ZonedDateTime,但我得到解析錯誤:

java.time.ZonedDateTime.parse("06/24/2017 07:00 AM (PDT)") 

的錯誤是:

java.time.format.DateTimeParseException: Text '06/24/2017 07:00 AM (PDT)' could not be parsed at index 0 
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949) 
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851) 
    at java.time.ZonedDateTime.parse(ZonedDateTime.java:597) 
    at java.time.ZonedDateTime.parse(ZonedDateTime.java:582) ... 29 elided 

另外,你同意,我應該使用ZonedDateTime

+0

「您是否同意我應該使用ZonedDateTime?」:取決於要實現的功能。如果目標是從運行代碼的語言環境獲取java.util.Date,那麼使用java.text.SimpleDateFormat可能會更好。 –

+0

當您可以使用現代日期和時間API(其中'ZonedDateTime'屬於)時,您不會希望獲得'java.util.Date'。你一定要避免'SimpleDateFormat'。 @AxelRichter –

回答

4

由於您的格式是非標準的,你需要把它指定給解析器:

ZonedDateTime.parse(
    "06/24/2017 07:00 AM (PDT)", 
    DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm a (zzz)") 
); 
4

parse method expects a String in a specific format,像2007-12-03T10:15:30+01:00[Europe/Paris]。由於您的輸入格式不同,您需要一個DateTimeFormatter

需要注意的一個細節是API使用IANA timezones names(始終格式爲Continent/City,如America/Sao_PauloEurope/Berlin)。 避免使用3字母縮寫(如CST或),因爲它們是ambiguous and not standard

該API會對特定ID進行一些例外處理,併爲它們提供一些默認值。對於PDT,它默認爲America/Los_Angeles

另一個細節是,在下面的例子中我在圖案中使用小寫hh:該格式具有AM/PM指示,所以我認爲hh是正確的模式,如its value is from 1 to 12(共用值時,有在AM/PM指示符)。

如果您使用大寫HH,它允許從0到23的值(和它的不常見的帶AM/PM使用),並如果輸入包含像07:00 PM一個小時它會拋出異常。

因此,代碼將是這樣的:

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm a (zzz)"); 
ZonedDateTime z = ZonedDateTime.parse("06/24/2017 07:00 AM (PDT)", fmt); 
System.out.println(z); 

輸出是:

2017-06-24T07:00-07:00[America/Los_Angeles]

但並不是所有的3個字母的時區的名稱將由API的認可,並會拋出異常。

無論如何,還有其他時區也在光動力療法(如America/Vancouver) - 你可以通過調用ZoneId.getAvailableZoneIds()得到所有的列表。如果你想使用一個不同的時區爲默認值,你可以創建一組優選區,並建立一個格式化這一套:

Set<ZoneId> preferredZones = new HashSet<>(); 
// set America/Vancouver as preferred zone 
preferredZones.add(ZoneId.of("America/Vancouver")); 
DateTimeFormatter fmt = new DateTimeFormatterBuilder() 
    // pattern 
    .appendPattern("MM/dd/yyyy hh:mm a (") 
    // append timezone with set of prefered zones 
    .appendZoneText(TextStyle.SHORT, preferredZones) 
    // finish the pattern 
    .appendPattern(")") 
    // create formatter 
    .toFormatter(); 
System.out.println(ZonedDateTime.parse("06/24/2017 07:00 AM (PDT)", fmt)); 

的API將使用的首選區域設置(在這種情況下,America/Vancouver)而不是默認的(America/Los_Angeles)。輸出將是:

2017-06-24T07:00-07:00[America/Vancouver]


其中輸入String的來自目前尚不清楚。如果你無法控制他們的格式,那麼你別無選擇:他們需要這樣解析。然後,你可以使用withZoneSameInstant方法將其轉換爲另一個時區:

// parse the input string 
ZonedDateTime z = ZonedDateTime.parse("06/24/2017 07:00 AM (PDT)", fmt); 
// convert to another timezone 
ZonedDateTime other = z.withZoneSameInstant(ZoneId.of("America/Sao_Paulo")); // 2017-06-24T11:00-03:00[America/Sao_Paulo] 

other值將是2017-06-24T11:00-03:00[America/Sao_Paulo]

但如果你能控制輸出,它總是更好(IMO)在內部與UTC(java.time.Instant)工作,並轉換成顯示給用戶,只有當一些時區:

// convert ZonedDateTime to instant 
ZonedDateTime z = // parse input 
// convert to UTC (Instant is always in UTC) 
Instant instant = z.toInstant(); 
// internally work with instant (as it's always in UTC) 

// convert instant to some timezone only when necessary (like displaying to users) 
ZonedDateTime converted = instant.atZone(ZoneId.of("Europe/London")); 
4

你得到的錯誤是已經在其他答案中涵蓋了。

Also, do you agree that I should be using a ZonedDateTime ?

是的,沒有。你的字符串肯定會被解析成ZonedDateTime。我建議你將它轉換爲Instant並存儲它。然後,當您需要根據他/她的時區首選項將其呈現給用戶時,可以將Instant再次轉換爲ZonedDateTime,或者僅使用具有所需默認時區的DateTimeFormatter對其進行格式化。

爲什麼這樣呢?首先,通常的做法是存儲Instant。有些人更喜歡從時代開始就存儲幾毫秒,我認爲這是一些(經常被誤解的)性能測量。當然這樣的毫秒我相當難讀,而Instant s可以在視覺上破譯,至少粗略的。我唯一尊重的其他選擇是,當您確定您的應用程序永遠不需要關注時區時(這是否會發生?),則有時使用LocalDateTime進行存儲。

如果我正確理解您的情況,您需要將時間點存儲到多個時區中。您不需要存儲最初輸入時間的時區(如PDT,但PDT並非真正的全時區)。 Instant是時區中性,這是我更喜歡它在某個時區存儲時間的原因之一,因爲ZonedDateTime會。另外一個Instant在概念上更簡單,我的猜測是它在實現方面也更簡單。

這裏有幾個更好的答案:Best practices with saving datetime & timezone info in database when data is dependant on datetime

+0

爲什麼立即通過zonedddatetime,b/c更通用? – Blankman

+0

@Blankman,我試圖在我的編輯中解釋(從假日直接回家,我的編程自我還沒有達到全速,所以希望它是有道理的)。 –