在巴西夏令时期间的日期解析异常

问题描述 投票:2回答:3

进入巴西DST时间段时,时钟向前1小时。 2014年,夏令时开始于19/10,因此时间19/10/2014 00:00:00变为19/10/2015的01:00:00。 “不存在”之间的时间间隔。

因此,当使用时区America / Sao_Paulo解析日期“ 19/10/2014 00:45:00”时,将引发解析异常:java.text.ParseException:无法解析的日期:“ 19/10/2014 00:45:00“。

String date = "19/10/2014 00:59:00";
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
sdf.setLenient(false);
sdf.setTimeZone("America/Sao_Paulo");

Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("America/Sao_Paulo"));
calendar.setTime(sdf.parse(date));

America / Sao_Paulo时区应该支持DST更改。该问题的预期解决方案是什么?我必须在DST周期开始和结束时手动更改jvm时区吗?当前,DST周期开始时,“修复”会将jvm时区更改为GMT-2。

注:此问题起源于使用spring开发的应用程序。日期示例从字符串转换为java.util.Calendar时抛出异常。在上面的示例代码中,我将lenient设置为false以便能够重现该错误。

java timezone dst
3个回答
0
投票

java.util.Calendar表示时间的瞬间。那一刻必须存在。当当地时间值落入DST的弹簧间隙时,这些值将不表示为真实的时间点。换句话说,在巴西配置正确的时钟在2014年10月19日永远不会显示00:45:00。因此例外。有关视觉表示,请参见the DST tag wiki

由于正在解析用户输入,因此我建议将字符串解析为LocalDateTime而不是Calendar。对于Java 7,可以从Joda-Time中获得。对于Java 8,它内置在新的java.time程序包中。

一旦将其作为java.time,您就可以决定从那里去哪里。如果时间无效(落在弹簧向前过渡的间隙中)或模棱两可(由于后退过渡),则可以检测到这些情况并决定如何在应用程序中处理它们。


0
投票

tl; dr

使用java.time可以将LocalDateTime转换从00:45调整为01:45。

DST

2014-10-19T01:45-02:00 [美国/圣保罗]

java.time

现代方法使用了几年前的java.time类,该类取代了现在已经成为旧式的可怕的日期时间类。

您的输入字符串缺少时区或UTC偏移量的指示符。因此解析为LocalDateTime.parse( "19/10/2014 00:45:00" , DateTimeFormatter.ofPattern( "dd/MM/uuuu HH:mm:ss" ) // Returns a `DateTimeFormatter` object. ) // Returns a `LocalDateTime` object. .atZone( ZoneId.of( "America/Sao_Paulo" ) // Returns a `ZoneId` object. ) // Returns a `ZonedDateTime` object. .toString() // Returns a `String` object holding text in standard ISO 8601 format extended to append the name of the time zone in square brackets.

LocalDateTime

A String input = "19/10/2014 00:45:00"; DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu HH:mm:ss" ); LocalDateTime ldt = LocalDateTime.parse( input , f ); 只是一个带有日期的日期。因此,此类无法表示时刻,是时间线上的[[not点。要确定时刻,我们必须将LocalDateTime放在时区的上下文中,从而产生LocalDateTime对象。

ZonedDateTime
转储到控制台。

ZoneId z = ZoneId.of( "America/Sao_Paulo" ); ZonedDateTime zdt = ldt.atZone( z );

运行时。

ldt = 2014-10-19T00:45

zdt = 2014-10-19T01:45-02:00 [美国/圣保罗]

我们可以看到

java.time

进行了必要的调整。当天的00:45更改为01:45。 请务必了解

java.time

在此调整中使用的逻辑。学习Javadoc。只有您可以决定这种调整是否适合您的业务逻辑。

-1
投票
日期是源自用户输入还是存储的信息?请注意,将GMT-3设置为JVM与“ America / Sao_Paulo”不同。我不相信GMT会遵守夏令时。来回切换JVM设置似乎不是一个好的解决方案。如果只是存储信息,则可以提前1小时或向后更新值,不确定此处是哪种情况。设置GMT-3时区是我看到的唯一导致美国/圣保罗时区的日期无效的解释。
© www.soinside.com 2019 - 2024. All rights reserved.