我一直面临着巴西夏令时在爪哇时代的奇怪问题。
夏令时的开始于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
答案 0 :(得分:3)
java.util.Date
和java.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类型,则应始终在传递给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.Date和java.sql.Date没有时区,所以你也必须使用java.util.Calendar。研究你的代码。
然后,一个问题是您尝试将日期值存储在日期时间数据类型中。然后抱怨时间组件的问题。这就像在真实/十进制数据类型中存储整数,然后抱怨你的数字有分数。
如果要存储日期,请使用日期类型。不幸的是,似乎甲骨文并没有提供这样的类型(但我不相信我,我是Postgres家伙,不知道甲骨文)。但是有一个非常简单的解决方法。这种解决方法假设您真正只想要日期,没有时间,这意味着不处理时区以及同一日期不会同时发生在同一日期的事实。解决方法是使用文本类型(如VARCHAR)来存储YYYY-MM-DD值。例如,2013-10-20。我建议将连字符包含在可读性中,除非你有大量的数据,从而证明它们的删除是正确的。通过订购年 - 月 - 日,值按字母顺序进行比较和排序。您可以通过查询大于/小于。
来搜索日期范围但通常当人们认为他们想要一个仅限日期的价值时,他们就错了。该日期仅在某些未指定的时区有意义,可能是您当前的当地时区。但是当Dubai或Paris中有人要求提供昨天发票清单时,他们昨天是他们的还是昨天你的?每个都在不同的时间开始和结束。
最佳做法是将日期时间值存储在UTC(无时区偏移)。如果对于历史记录而言对您来说很重要,还会存储本地日期时间和时区信息。检索这些UTC日期时间时,显式转换为所需的时区。避免依赖于特定计算机的默认时区。进一步提示,避免使用3个字母的时区代码,因为它们不是标准化的,并且通常具有多种含义;请改用time zone names。
停止使用java.util.Date/Calendar,因为它们非常糟糕。使用第三方Joda-Time库。花一些时间阅读他们的文档,并在StackOverflow.com上查看示例。将java.sql.Date值传入和传出Joda-Time DateTime实例。稍后,在Java 8中,考虑转移到受{Joda-Time启发但完全重新构建的JSR 310: Date and Time API。
最后,Joda-Time对这个非午夜问题有一个特定的解决方案:方法withTimeAtStartOfDay
确定了当天适当的第一时刻。在Brazil on October 20th中,那将是01:00而不是00:00。
经验教训: