java8日期/时间api:使用通用日期/时间格式进行解析,以提取从epoch开始的毫秒数

r9f1avp5  于 2021-06-27  发布在  Java
关注(0)|答案(2)|浏览(330)

给定任何日期/时间格式(由用户传递),我需要用它解析日期并返回自java epoch以来的毫秒数,这可以通过使用旧日期api的以下代码来完成:

//dateFormatter is SimpleDateFormat
Date d = dateFormatter.parse(value);
return d.getTime();

格式的唯一要求是包含日期部分,例如,以下所有格式都是可能的:

"dd/MM/yyyy"
"dd/MM/yyyy HH:mm X" //with timezone

缺失部分以当天开始/当地时区完成。因此,我提出了以下建议,似乎更加冗长,不确定是否有更有效的方法:

//dateFormatter is DateTimeFormatter
        TemporalAccessor ta = dateFormatter.parse(value);

        LocalDate ld = LocalDate.from(ta); //assume must have date part

        LocalTime lt = ta.query(TemporalQueries.localTime());
        if (lt == null) {
            lt = LocalTime.MIN;
        }

        ZoneId zoneId = ta.query(TemporalQueries.zone());
        if (zoneId == null) {
            zoneId = ZoneId.systemDefault();
        }

        Instant d = LocalDateTime.of(ld, lt).atZone(zoneId).toInstant();
        return d.toEpochMilli();
ruyhziif

ruyhziif1#

使用 DateTimeFormatterBuilder.parseDefaulting 要在格式字符串中找不到该字段时设置默认值,请执行以下操作:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
        .appendPattern(patternFromTheUser)
        // make everything non-required default to 0
        .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
        .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
        .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
        .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
        .toFormatter();
System.out.println(ZonedDateTime.parse("01/01/2021 20:00", formatter)
        .toInstant()
        .toEpochMilli());
fd3cxomn

fd3cxomn2#

如sweeper在answer by sweeper中所示,您可以在格式化程序中指定默认值。
区域id的处理方式不同,它不仅是一个默认值,也是一种覆盖,必须使用 withZone(ZoneId zone) 在构建格式化程序之后。
如果格式和值指定了一个区域id,那么就使用它,一切正常。如果未指定区域id或区域偏移量,则使用给定的“default”。但是,如果只指定了区域偏移量,则它将用于解析,但“默认”区域id将覆盖结果,并相应地调整时间和区域偏移量。
因为您需要epoch毫秒,所以这实际上并不影响这段代码,我只想为可能不会最终转换为utc的其他用户提一下。
代码应为:

public static long parseToEpochMillis(String format, String dateText) {
    return new DateTimeFormatterBuilder()
            .appendPattern(format)
            .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
            .toFormatter(Locale.US) // So e.g. MMM parses "Feb", not some other language
            .withZone(ZoneId.systemDefault())
            .parse(dateText, ZonedDateTime::from)
            .toInstant()
            .toEpochMilli();
}

测试

public static void main(String[] args) {
    test("M/d/u", "7/4/2015");
    test("M/d/u H:mm:ss VV", "7/4/2015 1:23:45 America/Denver");
    test("M/d/u H:mm:ssXXXXX", "7/4/2015 1:23:45-08:00");
    test("M/d/u H:mm:ssX", "7/4/2015 1:23:45Z");
}
static void test(String format, String dateText) {
    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendPattern(format)
            .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
            .toFormatter(Locale.US)
            .withZone(ZoneId.systemDefault());
    ZonedDateTime dateTime = ZonedDateTime.parse(dateText, formatter);
    Instant instant = dateTime.toInstant();
    long epochMilli = instant.toEpochMilli();
    System.out.printf("%-45s -> %s -> %d%n", dateTime, instant, epochMilli);
}

输出

2015-07-04T00:00-04:00[America/New_York]      -> 2015-07-04T04:00:00Z -> 1435982400000
2015-07-04T01:23:45-06:00[America/Denver]     -> 2015-07-04T07:23:45Z -> 1435994625000
2015-07-04T05:23:45-04:00[America/New_York]   -> 2015-07-04T09:23:45Z -> 1436001825000
2015-07-03T21:23:45-04:00[America/New_York]   -> 2015-07-04T01:23:45Z -> 1435973025000

相关问题