从不同的日期字符串格式生成 INSTANT
Produce INSTANT from different date-string formats
我需要将日期字符串转换为 Instant 以及我期望用户提供的这三种格式
- yyyy-MM-dd
- yyyy-MM
- yyyy
将 yyyy-MM-dd 转换为瞬间并不难
Optional.ofNullable(request.getDate())
.map(LocalDate::parse)
.map(date -> date.atStartOfDay(ZoneId.of("America/New_York")).toInstant())
.map(pojo::dateAsInstant)
但是,我正在努力寻找将其他两种格式解析为 java.time.Instant 的解决方案。有人可以帮忙吗?
使用 DateTimeFormatterBuilder
and its parseDefaulting
,连同格式字符串中的可选部分。
本地日期
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("uuuu[-MM[-dd]]")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.toFormatter(Locale.US);
System.out.println(LocalDate.parse("2019-08-13", fmt)); // Prints: 2019-08-13
System.out.println(LocalDate.parse("2019-08" , fmt)); // Prints: 2019-08-01
System.out.println(LocalDate.parse("2019" , fmt)); // Prints: 2019-01-01
或者不使用模式字符串的长版本。
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4)
.optionalStart()
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.optionalStart()
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH, 2)
.optionalEnd()
.optionalEnd()
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.toFormatter(Locale.US);
System.out.println(LocalDate.parse("2019-08-13", fmt)); // Prints: 2019-08-13
System.out.println(LocalDate.parse("2019-08" , fmt)); // Prints: 2019-08-01
System.out.println(LocalDate.parse("2019" , fmt)); // Prints: 2019-01-01
ZonedDateTime
有了 2 个额外的默认值,您可以直接解析为 ZonedDateTime
。
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("uuuu[-MM[-dd]]")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.parseDefaulting(ChronoField.SECOND_OF_DAY, 0)
.toFormatter(Locale.US)
.withZone(ZoneId.of("America/New_York"));
System.out.println(ZonedDateTime.parse("2019-08-13", fmt)); // 2019-08-13T00:00-04:00[America/New_York]
System.out.println(ZonedDateTime.parse("2019-08" , fmt)); // 2019-08-01T00:00-04:00[America/New_York]
System.out.println(ZonedDateTime.parse("2019" , fmt)); // 2019-01-01T00:00-05:00[America/New_York]
即时
Instant
没有采用格式化程序的 parse
方法,因此解析调用略有不同。
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("uuuu[-MM[-dd]]")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.parseDefaulting(ChronoField.SECOND_OF_DAY, 0)
.toFormatter(Locale.US)
.withZone(ZoneId.of("America/New_York"));
System.out.println(fmt.parse("2019-08-13", Instant::from)); // 2019-08-13T04:00:00Z
System.out.println(fmt.parse("2019-08" , Instant::from)); // 2019-08-01T04:00:00Z
System.out.println(fmt.parse("2019" , Instant::from)); // 2019-01-01T05:00:00Z
带有可选破折号的即时
使用模式无法使它正常工作,但使用漫长的方式构建格式化程序时工作正常。
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4)
.optionalStart()
.optionalStart()
.appendLiteral('-')
.optionalEnd()
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.optionalStart()
.optionalStart()
.appendLiteral('-')
.optionalEnd()
.appendValue(ChronoField.DAY_OF_MONTH, 2)
.optionalEnd()
.optionalEnd()
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.parseDefaulting(ChronoField.SECOND_OF_DAY, 0)
.toFormatter(Locale.US)
.withZone(ZoneId.of("America/New_York"));
System.out.println(fmt.parse("2019-08-13", Instant::from)); // 2019-08-13T04:00:00Z
System.out.println(fmt.parse("20190813" , Instant::from)); // 2019-08-13T04:00:00Z
System.out.println(fmt.parse("2019-08" , Instant::from)); // 2019-08-01T04:00:00Z
System.out.println(fmt.parse("201908" , Instant::from)); // 2019-08-01T04:00:00Z
System.out.println(fmt.parse("2019" , Instant::from)); // 2019-01-01T05:00:00Z
我需要将日期字符串转换为 Instant 以及我期望用户提供的这三种格式
- yyyy-MM-dd
- yyyy-MM
- yyyy
将 yyyy-MM-dd 转换为瞬间并不难
Optional.ofNullable(request.getDate())
.map(LocalDate::parse)
.map(date -> date.atStartOfDay(ZoneId.of("America/New_York")).toInstant())
.map(pojo::dateAsInstant)
但是,我正在努力寻找将其他两种格式解析为 java.time.Instant 的解决方案。有人可以帮忙吗?
使用 DateTimeFormatterBuilder
and its parseDefaulting
,连同格式字符串中的可选部分。
本地日期
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("uuuu[-MM[-dd]]")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.toFormatter(Locale.US);
System.out.println(LocalDate.parse("2019-08-13", fmt)); // Prints: 2019-08-13
System.out.println(LocalDate.parse("2019-08" , fmt)); // Prints: 2019-08-01
System.out.println(LocalDate.parse("2019" , fmt)); // Prints: 2019-01-01
或者不使用模式字符串的长版本。
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4)
.optionalStart()
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.optionalStart()
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH, 2)
.optionalEnd()
.optionalEnd()
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.toFormatter(Locale.US);
System.out.println(LocalDate.parse("2019-08-13", fmt)); // Prints: 2019-08-13
System.out.println(LocalDate.parse("2019-08" , fmt)); // Prints: 2019-08-01
System.out.println(LocalDate.parse("2019" , fmt)); // Prints: 2019-01-01
ZonedDateTime
有了 2 个额外的默认值,您可以直接解析为 ZonedDateTime
。
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("uuuu[-MM[-dd]]")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.parseDefaulting(ChronoField.SECOND_OF_DAY, 0)
.toFormatter(Locale.US)
.withZone(ZoneId.of("America/New_York"));
System.out.println(ZonedDateTime.parse("2019-08-13", fmt)); // 2019-08-13T00:00-04:00[America/New_York]
System.out.println(ZonedDateTime.parse("2019-08" , fmt)); // 2019-08-01T00:00-04:00[America/New_York]
System.out.println(ZonedDateTime.parse("2019" , fmt)); // 2019-01-01T00:00-05:00[America/New_York]
即时
Instant
没有采用格式化程序的 parse
方法,因此解析调用略有不同。
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("uuuu[-MM[-dd]]")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.parseDefaulting(ChronoField.SECOND_OF_DAY, 0)
.toFormatter(Locale.US)
.withZone(ZoneId.of("America/New_York"));
System.out.println(fmt.parse("2019-08-13", Instant::from)); // 2019-08-13T04:00:00Z
System.out.println(fmt.parse("2019-08" , Instant::from)); // 2019-08-01T04:00:00Z
System.out.println(fmt.parse("2019" , Instant::from)); // 2019-01-01T05:00:00Z
带有可选破折号的即时
使用模式无法使它正常工作,但使用漫长的方式构建格式化程序时工作正常。
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4)
.optionalStart()
.optionalStart()
.appendLiteral('-')
.optionalEnd()
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.optionalStart()
.optionalStart()
.appendLiteral('-')
.optionalEnd()
.appendValue(ChronoField.DAY_OF_MONTH, 2)
.optionalEnd()
.optionalEnd()
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.parseDefaulting(ChronoField.SECOND_OF_DAY, 0)
.toFormatter(Locale.US)
.withZone(ZoneId.of("America/New_York"));
System.out.println(fmt.parse("2019-08-13", Instant::from)); // 2019-08-13T04:00:00Z
System.out.println(fmt.parse("20190813" , Instant::from)); // 2019-08-13T04:00:00Z
System.out.println(fmt.parse("2019-08" , Instant::from)); // 2019-08-01T04:00:00Z
System.out.println(fmt.parse("201908" , Instant::from)); // 2019-08-01T04:00:00Z
System.out.println(fmt.parse("2019" , Instant::from)); // 2019-01-01T05:00:00Z