java—在SimpleDataFormat上使用datetimeformatter

pqwbnv8z  于 2021-07-03  发布在  Java
关注(0)|答案(1)|浏览(341)

我正在重构一些代码,并试图区分解决了什么问题。功能 formatDateRfc1123 很明显,但是增加的代码有什么附加值呢?
在第一次提交中,这是一个函数,它可能会因为我不知道的原因而崩溃:

public static String formatDateRfc1123(final Date timestamp) {
    SimpleDateFormat formatRf1123 = new SimpleDateFormat(RFC_1123);
    formatRf1123.setTimeZone(GMT_ZONE);
    return formatRfc1123.format(timestamp);
}

后来,它被重构以解决崩溃:

public static String formatDateRfc1123(final Date timestamp, final int buildVersion) {
    if (buildVersion >= Build.VERSION_CODE_O) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(RFC_1123, US);
        Instant instant = Instant.ofEpochSecond(TimeUnit.MILLISECONDS.toSeconds(timestamp.getTime());
        ZoneId zoneId = ZoneId.of(GMT_ZONE.getID());
        ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, zoneId);
        return dateTimeFormatter.format(zonedDateTime);
    } else {
        SimpleDateFormat formatRf1123 = new SimpleDateFormat(RFC_1123);
        formatRf1123.setTimeZone(GMT_ZONE);
        return formatRfc1123.format(timestamp);
    }
}

有一个旧的用户故事链接到添加的代码,但它只链接到删除的fabric崩溃日志。所以,我只知道它可以崩溃,而不是什么异常被抛出什么值。
它可能崩溃的价值和sdk版本是什么?

c2e8gylq

c2e8gylq1#

代码的前三行使用 java.time 计算过于复杂,容易出错。我建议您使用开箱即用的常量来避免任何类型的歧义和错误。建议的方法如下:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // Test
        System.out.println(formatDateRfc1123(new Date()));
    }

    public static String formatDateRfc1123(final Date timestamp) {
        // Use the out-of-the-box formatter
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.RFC_1123_DATE_TIME.withLocale(Locale.US);

        // Use Date#toInstant to convert it into Instant
        Instant instant = timestamp.toInstant();

        // Use the out-of-the-box constant for UTC (or GMT)
        ZoneId zoneId = ZoneOffset.UTC;

        ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, zoneId);
        // ZonedDateTime zonedDateTime = instant.atZone(zoneId); //This is simpler

        return dateTimeFormatter.format(zonedDateTime);
    }
}

请注意,表示时区的三个字母字符串容易出错。你应该始终使用时区的全称,即。 Continent/City . 下面给出一个例子来说明这一点。

import java.time.ZoneId;

public class Main {
    public static void main(String[] args) {
        ZoneId zoneId = ZoneId.of("EDT");
        // ...
    }
}

输出:

Exception in thread "main" java.time.zone.ZoneRulesException: Unknown time-zone ID: EDT
    at java.base/java.time.zone.ZoneRulesProvider.getProvider(ZoneRulesProvider.java:279)
    at java.base/java.time.zone.ZoneRulesProvider.getRules(ZoneRulesProvider.java:234)
    at java.base/java.time.ZoneRegion.ofId(ZoneRegion.java:120)
    at java.base/java.time.ZoneId.of(ZoneId.java:408)
    at java.base/java.time.ZoneId.of(ZoneId.java:356)
    at Main.main(Main.java:5)

这个 SimpleDateFormat 甚至不会抛出异常并以utc(或gmt)静默地格式化日期时间。太危险了!

不正确:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
        sdf.setTimeZone(TimeZone.getTimeZone("EDT"));
        System.out.println(sdf.format(new Date()));
    }
}

输出:

2020-12-05T01:36:48Z

正确:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
        sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
        System.out.println(sdf.format(new Date()));
    }
}

输出:

2020-12-04T20:36:05-05:00

注意,api的日期时间 java.util 以及它们的格式化api, SimpleDateFormat 过时且容易出错。建议完全停止使用它们,并切换到现代日期时间api。在trail:date-time了解有关现代日期时间api的更多信息。
注意:如果您正在为一个android项目工作,并且您的android api级别仍然不符合java-8,请检查通过desugaring提供的java8+api以及如何在android项目中使用threetenabp。

相关问题