繁体   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