簡體   English   中英

使用 Java 8 DateTimeFormatter 和西班牙語月份名稱進行解析

[英]Parsing with Java 8 DateTimeFormatter and Spanish month names

使用“舊的”,Java 8 之前的SimpleDateFormat我可以做到:

new java.text.SimpleDateFormat("MMM yyyy", new java.util.Locale("es", "ES")).parse("Mayo 2017")

獲取具有西班牙月份名稱的日期的Date對象。

如何使用 Java 8 和DateTimeFormatter實現相同的目標?

我試過:

DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withLocale(new Locale("es", "ES")).ofPattern("MMM yyyy").parse("Mayo 2017")

但只得到一個java.time.format.DateTimeParseException

可以刪除對ofLocalizedDateTime()的調用,因為最后你調用ofPattern() ,創建另一個具有完全不同模式的格式化程序(並且ofLocalizedDateTime(FormatStyle.FULL)返回的模式與僅month year非常不同,所以這是不是你想要的)。

另一個細節是Mayo是完整的月份名稱,因此模式必須是MMMM (有關更多詳細信息, 請查看 javadoc )。 此外,默認情況下DateTimeFormatter僅接受小寫名稱(至少在我使用西班牙語言環境進行的測試中),因此您必須將格式化程序設置為不區分大小寫。

您可以通過使用java.time.format.DateTimeFormatterBuilder來做到這java.time.format.DateTimeFormatterBuilder

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // case insensitive
    .parseCaseInsensitive()
    // pattern with full month name (MMMM)
    .appendPattern("MMMM yyyy")
    // set locale
    .toFormatter(new Locale("es", "ES"));
// now it works
fmt.parse("Mayo 2017");

或者,您可以直接將其解析為java.time.YearMonth對象,因為它似乎是這種情況下的最佳選擇(因為輸入只有年和月):

YearMonth ym = YearMonth.parse("Mayo 2017", fmt);
System.out.println(ym); // 2017-05

默認值

當輸入沒有所有字段時, SimpleDateFormat只為它們使用一些默認值。 在這種情況下,輸入只有年和月,因此解析的Date將等同於解析的月/年,但日將設置為 1,時間設置為午夜(在 JVM 默認時區)。

新 API 對此非常嚴格並且不會創建默認值,除非您告訴它這樣做。 配置它的一種方法是將parseDefaultingjava.time.temporal.ChronoField一起使用:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // case insensitive
    .parseCaseInsensitive()
    // pattern with full month name (MMMM)
    .appendPattern("MMMM yyyy")
    // default value for day of month
    .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
    // default value for hour
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
    // default value for minute
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    // set locale
    .toFormatter(new Locale("es", "ES"));

有了這個,您可以將其解析為LocalDateTime並將缺失的字段分配給相應的默認值:

LocalDateTime dt = LocalDateTime.parse("Mayo 2017", fmt);
System.out.println(dt); // 2017-05-01T00:00

如果您需要獲取與SimpleDateFormat創建的具有相同值的java.util.Date ,您可以將此LocalDateTime轉換為 JVM 默認時區,然后將其轉換為Date

Date javaUtilDate = Date.from(dt.atZone(ZoneId.systemDefault()).toInstant());

請注意,我必須明確使用 JVM 默認時區 ( ZoneId.systemDefault() ),它是SimpleDateFormat隱式使用的。


另一種選擇是手動設置YearMonth值中的值:

// in this case, the formatter doesn't need the default values
YearMonth ym = YearMonth.parse("Mayo 2017", fmt);
ZonedDateTime z = ym
    // set day of month to 1
    .atDay(1)
    // midnight at JVM default timezone
    .atStartOfDay(ZoneId.systemDefault());
Date javaUtilDate = date.from(z.toInstant());

默認時區可以在沒有通知的情況下更改,即使在運行時也是如此,因此最好始終明確您正在使用哪個時區。

API 使用IANA 時區名稱(始終采用Region/City格式,例如America/New_YorkEurope/Berlin ),因此您可以調用ZoneId.of("America/New_York")例如。 避免使用 3 個字母的縮寫(如CSTPST ),因為它們含糊不清且不標准

您可以通過調用ZoneId.getAvailableZoneIds()獲取可用時區列表(並選擇最適合您系統的時區ZoneId.getAvailableZoneIds()

暫無
暫無

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

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