使用Java 8 DateTimeFormatter和西class牙语月份名称进行解析
使用’old’,Java 8之前的SimpleDateFormat
我可以做到:
new java.text.SimpleDateFormat("MMM yyyy", new java.util.Locale("es", "ES")).parse("Mayo 2017")
获取具有西class牙月份名称的日期的Date
对象。
如何使用Java 8和DateTimeFormatter
实现相同的function?
我试过了:
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
仅接受小写名称(至少在我使用西class牙语语言环境进行的测试中),因此您必须将格式化程序设置为不区分大小写。
您可以使用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对此非常严格,除非您告诉它,否则不会创建默认值。 配置它的一种方法是使用parseDefaulting
和java.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_York
或Europe/Berlin
),因此您可以调用ZoneId.of("America/New_York")
。 避免使用3个字母的缩写(如CST
或PST
),因为它们不明确且不标准 。
您可以通过调用ZoneId.getAvailableZoneIds()
获取可用时区列表(并选择最适合您系统的时区ZoneId.getAvailableZoneIds()
。