为什么 SimpleDateFormat setTimeZone 不会为无效时区抛出错误
Why SimpleDateFormat setTimeZone doesn't throws error for invalid timezone
我正在使用 SimpleDateFormat 将时间的字符串类型转换为 unix 时间戳,但是当我将时区设置为非法值时,我仍然得到正确的结果,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);
由于getTimeZone方法,如果无法理解指定的时区,returns默认GMT
时区
the specified TimeZone, or the GMT zone if the given ID cannot be understood.
如果建议使用 TimeZone.getAvailableIDs 进行验证,并且可以轻松检查以验证输入时区是否有效
Arrays.stream(TimeZone.getAvailableIDs()).anyMatch(tz->tz.equals("fewfefewf"))
最终建议请使用 java-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);
java.time
我建议您使用 java.time,现代 Java 日期和时间 API,作为您的日期和时间工作。它的众多优点之一是,在许多情况下,它比 TimeZone
、SimpleDateFormat
和 Date
等旧 classes 提供更好的验证。这是我对你的代码的现代等价物的看法:
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 的 AM 或 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
class 来验证时区 ID 字符串。
Link: Oracle tutorial: Date Time 解释如何使用 java.time.
我正在使用 SimpleDateFormat 将时间的字符串类型转换为 unix 时间戳,但是当我将时区设置为非法值时,我仍然得到正确的结果,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);
由于getTimeZone方法,如果无法理解指定的时区,returns默认GMT
时区
the specified TimeZone, or the GMT zone if the given ID cannot be understood.
如果建议使用 TimeZone.getAvailableIDs 进行验证,并且可以轻松检查以验证输入时区是否有效
Arrays.stream(TimeZone.getAvailableIDs()).anyMatch(tz->tz.equals("fewfefewf"))
最终建议请使用 java-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);
java.time
我建议您使用 java.time,现代 Java 日期和时间 API,作为您的日期和时间工作。它的众多优点之一是,在许多情况下,它比 TimeZone
、SimpleDateFormat
和 Date
等旧 classes 提供更好的验证。这是我对你的代码的现代等价物的看法:
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 的 AM 或 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
class 来验证时区 ID 字符串。
Link: Oracle tutorial: Date Time 解释如何使用 java.time.