为巴西发行Java 6夏令时

时间:2013-11-28 13:43:06

标签: java date

我一直面临着巴西夏令时在爪哇时代的奇怪问题。

夏令时的开始于2013年10月20日在巴西,所以现在我们距格林威治2小时。

我的问题是:我将日期存储在我的数据库Oracle上,如此10/20/2013 00:00:00,您可以看到,我们不存储小时,分钟和秒甚至时区。 当我们将这个日期加载到JAVA(java.sql.Date到java.util.Date)时,它会增加一个小时,如下所示:10/20/2013 01:00:00,但应该是10/20/2013 00:00 :00

有没有人遇到过这个问题?我检查了我的tzupdater并进行了更新。

我的JAVA版本是:java6_u45

2 个答案:

答案 0 :(得分:3)

java.util.Datejava.sql.Date不包含时区信息。他们只是在时间上代表了一个瞬间,即“从纪元传来的xy毫秒”。

java.sql.Date:“A  *毫秒值表示毫秒数  *已于1970年1月1日00:00:00.000 GMT通过。“

java.util.Date:“Date类旨在反映  *协调世界时(UTC)“

在sql端存储日期时间的数据类型是什么?

答案 1 :(得分:1)

  

我将日期存储在我的数据库Oracle上,如同您所看到的10/20/2013 00:00:00,我们不存储小时,分钟和秒甚至时区。

...

  

字段的数据类型是Oracle上的DATE

在两个问题上你是不正确的:

  • 存储10/20/2013 00:00:00之类的日期。您正在使用Oracle的DATE data type,这是一种专有的二进制格式,包含世纪,年,月,日,小时,分钟和秒的组件,但没有时区。
  • 确实存储时间组件。 Oracle中的DATE类型自动插入00:00:00 A.M. (午夜)如果你没有提供其他时间价值。

如果要在Oracle中使用DATE类型,则应始终在传递给Oracle之前将值转换为UTC / GMT。同样,当从Oracle中提取DATE值时,有意识地将值转换为所需的时区,因为Oracle知道Oracle正在向您发送UTC值。

如果您尝试在Oracle DATE类型中存储分区日期时间,则会遇到各种问题。其中一个问题是,在某些时区,在某些日子没有午夜,例如Daylight Savings Time(DST)。猜猜看...... 巴西是没有午夜的时区之一。 DST会在午夜到01:00时将时钟调到jump one hour forward。今年,这发生在2013年10月19日至20日。

由gyabraham the correct answer说,java.util.Datejava.sql.Date没有时区,所以你也必须使用java.util.Calendar。研究你的代码。

然后,一个问题是您尝试将日期值存储在日期时间数据类型中。然后抱怨时间组件的问题。这就像在真实/十进制数据类型中存储整数,然后抱怨你的数字有分数。

如果要存储日期,请使用日期类型。不幸的是,似乎甲骨文并没有提供这样的类型(但我不相信我,我是Postgres家伙,不知道甲骨文)。但是有一个非常简单的解决方法。这种解决方法假设您真正只想要日期,没有时间,这意味着不处理时区以及同一日期不会同时发生在同一日期的事实。解决方法是使用文本类型(如VARCHAR)来存储YYYY-MM-DD值。例如,2013-10-20。我建议将连字符包含在可读性中,除非你有大量的数据,从而证明它们的删除是正确的。通过订购年 - 月 - 日,值按字母顺序进行比较和排序。您可以通过查询大于/小于。

来搜索日期范围

但通常当人们认为他们想要一个仅限日期的价值时,他们就错了。该日期仅在某些未指定的时区有意义,可能是您当前的当地时区。但是当DubaiParis中有人要求提供昨天发票清单时,他们昨天是他们的还是昨天你的?每个都在不同的时间开始和结束。

最佳做法是将日期时间值存储在UTC(无时区偏移)。如果对于历史记录而言对您来说很重要,还会存储本地日期时间和时区信息。检索这些UTC日期时间时,显式转换为所需的时区。避免依赖于特定计算机的默认时区。进一步提示,避免使用3个字母的时区代码,因为它们不是标准化的,并且通常具有多种含义;请改用time zone names

停止使用java.util.Date/Calendar,因为它们非常糟糕。使用第三方Joda-Time库。花一些时间阅读他们的文档,并在StackOverflow.com上查看示例。将java.sql.Date值传入和传出Jo​​da-Time DateTime实例。稍后,在Java 8中,考虑转移到受{Joda-Time启发但完全重新构建的JSR 310: Date and Time API

最后,Joda-Time对这个非午夜问题有一个特定的解决方案:方法withTimeAtStartOfDay确定了当天适当的第一时刻。在Brazil on October 20th中,那将是01:00而不是00:00。

经验教训:

  • 请注意您的数据类型。
  • 阅读文档。
  • 要知道并非每个时区的每一天都有午夜。切勿将零填充到时间组件中并假设它是有效的并且意味着午夜。
  • 始终考虑时区。知道什么时区(或UTC)正在发挥作用;永远不要假设。
  • 全球存储,在本地思考。以UTC格式存储日期时间。尝试在UTC中执行大多数业务逻辑。仅在人类需要时(在演示文稿或业务逻辑中,例如“今天”发票)转换为时间划分日期时间。
  • 了解java.sql.Datejava.util.Date(子类)。没有时区信息。
  • 使用Joda-Time。仅在交换数据时使用java.util.Date/ Calendar类。或者,在Java 8中,使用新的JSR 310 java.time.*类。