为什么SimpleDateFormat setTimeZone不会为无效时区引发错误

时间:2020-04-24 18:34:46

标签: java validation timezone datetime-parsing

我正在使用SimpleDateFormat将时间的字符串类型转换为unix时间戳,但是当我将timezone设置为非法值时,我仍然可以获得正确的结果,这是SimpleDateFormat.parse()方法的定义方式吗?如果我想进行单元测试以测试失败案例,该怎么办?

String str = "2016-06-21-10-19-22";

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
df.setTimeZone(TimeZone.getTimeZone("fewfefewf"));

Date date = df.parse(str);

long epoch = date.getTime();
System.out.println(epoch);

2 个答案:

答案 0 :(得分:1)

如果无法理解指定的TimeZone,是因为getTimeZone方法返回默认的GMT区域

指定的时区,如果无法理解给定的ID,则为GMT区域。

如果建议使用TimeZone.getAvailableIDs进行验证,则可以轻松检查输入时区是否有效

Arrays.stream(TimeZone.getAvailableIDs()).anyMatch(tz->tz.equals("fewfefewf"))

最后的建议是使用j ava-8 date time api类,并开始远离SimpleDateFormat

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"); // make sure you use H for hours in format

LocalDateTime dateTime = LocalDateTime.parse(str,formatter);

答案 1 :(得分:0)

java.time

我建议您使用java.time(现代的Java日期和时间API)进行日期和时间工作。它的许多优点之一是,在许多情况下,它比诸如TimeZoneSimpleDateFormatDate之类的旧类为您提供更好的验证。这是我的等效代码的镜头:

    String str = "2016-06-21-10-19-22";

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd-hh-mm-ss");

    ZonedDateTime dateTime = LocalDateTime.parse(str, dtf)
            .atZone(ZoneId.of("fewfefewf"));

    long epoch = dateTime.toInstant().toEpochMilli();
    System.out.println(epoch);

运行它会产生:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2016-06-21-10-19-22' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MicroOfSecond=0, MinuteOfHour=19, NanoOfSecond=0, MilliOfSecond=0, SecondOfMinute=22, HourOfAmPm=10},ISO resolved to 2016-06-21 of type java.time.format.Parsed
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
    at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
    at ovv.misc.MiscTest.<init>(MiscTest.java:72)
    at ovv.misc.MiscTest.main(MiscTest.java:61)
Caused by: java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: {MicroOfSecond=0, MinuteOfHour=19, NanoOfSecond=0, MilliOfSecond=0, SecondOfMinute=22, HourOfAmPm=10},ISO resolved to 2016-06-21 of type java.time.format.Parsed
    at java.base/java.time.LocalDateTime.from(LocalDateTime.java:461)
    at java.base/java.time.format.Parsed.query(Parsed.java:235)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
    ... 3 more
Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: {MicroOfSecond=0, MinuteOfHour=19, NanoOfSecond=0, MilliOfSecond=0, SecondOfMinute=22, HourOfAmPm=10},ISO resolved to 2016-06-21 of type java.time.format.Parsed
    at java.base/java.time.LocalTime.from(LocalTime.java:431)
    at java.base/java.time.LocalDateTime.from(LocalDateTime.java:457)
    ... 5 more

惊讶吗? java.time已经发现您没有问过的错误:在格式模式字符串中,您需要在00到23的一天中的大写HH使用小写hh来表示上午的时钟时间。或从01到12的PM。错误消息中要注意的详细信息是HourOfAmPm=10-这不是您想要的。让我们修复并再次运行:

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
Exception in thread "main" java.time.zone.ZoneRulesException: Unknown time-zone ID: fewfefewf
    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 ovv.misc.MiscTest.<init>(MiscTest.java:73)
    at ovv.misc.MiscTest.main(MiscTest.java:61)

我相信这就是您要的。如果我们也修复此错误,则代码可以完美运行:

    ZonedDateTime dateTime = LocalDateTime.parse(str, dtf)
            .atZone(ZoneId.of("America/Eirunepe"));

1466522362000

我设置了一个随机时区,但我认为您知道您想要哪个。

其他答案已经很好地说明了您的代码出了什么问题。我不知道如何说服旧的TimeZone类来验证时区ID字符串。

链接: Oracle tutorial: Date Time解释了如何使用java.time。