java - 从不同的日期字符串格式生成 INSTANT

标签 java date-parsing

我需要将日期字符串转换为即时数据以及我期望用户提供的这三种格式

  • yyyy-MM-dd
  • yyyy-MM

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及其 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

分区日期时间

通过 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

关于java - 从不同的日期字符串格式生成 INSTANT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57487050/

相关文章:

java - 结合 Java 泛型和反射以避免强制转换

Java 日期解析不适用于 ET 时区,而适用于 IST

java - 如何在 SimpleDateFormat 中禁用零填充宽大处理

java - 是否有 Spring Boot 标志来禁用宽松的 Jackson 对 LocalDate 值的时间解析?

java - 无法使用 DateTimeFormatter 解析月+日

java - 使用出站拦截器修改 Apache cxf JAX RS 响应

java - 读取 servlet 中由用户输入的文本文件

java - 如何在 Firebase Android 中执行查询 SQL IN 子句

java - 当用户在特定区域时如何发送 toast ?

没有 ":"的时区的 java 日期模式