日期时间处理是一个烂摊子
在answer by Teo第一段是非常有见地的和正确的:在Java中的日期时间处理是一个烂摊子。所有其他语言的Ditto &我知道的开发环境。日期时间的工作是困难和棘手的,尤其是容易出错和令人沮丧的,因为我们认为它是直观的日期时间。但是,当涉及到数据类型,数据库,序列化,本地化,跨时区调整以及计算机编程随附的所有其他手续时,“直观地”不会削减它。
不幸的是,计算机行业基本上选择了忽略日期时间工作的这个问题。正如统一码需要很长时间才能被发明,因为明显的需求,业界也一直在解决日期处理问题上下功夫。
不依赖于计数纪元以来
但我必须和它的结论不同意。使用自数计数并不是最好的解决方案。使用count-since-epoch本质上是令人困惑,容易出错和不兼容的。
我们做数学,而不是使用位创建数字数据类型。我们创建字符串类来处理处理文本的细节,而不是纯粹的八位字节。我们也应该创建数据类型和类来处理日期时间值。
早期的Java团队(和他们之前的IBM & Taligent)尝试使用java.util.Date和java.util.Calendar及相关类。不幸的是,这种尝试是不够的。虽然日期时间本质上是令人困惑的,但这些课程更加混淆了。
乔达时间
据我所知,Joda-Time项目是采取的日期时间彻底,可靠和成功的方式,第一个项目。即便如此,Joda-Time的创造者并不完全满意。他们继续在Java 8中创建java.time package,并将其扩展为threeten-extra project。 Joda-Time和java.time共享相似的概念,但是不同,每个都有一些优点。
数据库问题
具体来说,java.util.Date & .Calendar类缺乏日期仅值,而时间的日和时区。他们缺乏没有日期和时区的时间价值。在Java 8之前,Java团队添加了被称为java.sql.Date
和java.sql.Time
类的攻击,这些类是伪装成仅限日期的日期时间值。 Joda-Time和java.time均提供LocalDate
和LocalTime
类。
另一个具体问题是java.util.Date的分辨率为毫秒,但数据库通常使用微秒或纳秒。为了消除这种差距,Java早期团队创建了另一个黑客类别java.sql.Timestamp
。虽然技术上是一个java.util.Date子类,但它也可以跟踪小数秒到纳秒分辨率。所以在进入和退出这种类型时,您可能会失去或获得更精细的秒数粒度,而不会意识到这一事实。所以这可能意味着你期望的平等值不是。
混淆的另一个来源是SQL数据类型TIMESTAMP WITH TIME ZONE
。由于时区信息是而不是存储,该名称是一个误称。将名称设想为TIMESTAMP WITH RESPECT FOR TIME ZONE
,因为在将日期时间值转换为UTC时,会使用任何传递的时区偏移信息。
具有纳秒级分辨率的java.time包具有一些特定功能,可以更好地与数据库进行日期时间数据通信。
我可以写更多,但是这些信息可以从搜索StackOverflow中搜索诸如joda,java.time,sql timestamp和JDBC等单词。
使用Joda-Time和JDBC的例子Postgres。 Joda-Time使用immutable objects为thread-safety。因此,我们不是修改一个实例(“mutate”),而是根据原始值创建一个新实例。
String sql = "SELECT now();";
…
java.sql.Timestamp now = myResultSet.getTimestamp(1);
DateTime dateTimeUtc = new DateTime(now , DateTimeZone.UTC);
DateTime dateTimeMontréal = dateTimeUtc.withZone(DateTimeZone.forID("America/Montreal"));
专注于UTC
在此之前,我还以为在时间戳UTC是按照惯例始终。为什么人们会想要一个本地化时间戳而不是本地化表示呢?这不会让每个人都感到困惑吗?
确实。 SQL标准定义了一个TIMESTAMP WITHOUT TIME ZONE
,它忽略并删除任何包含的时区数据。我无法想象这有用。这位Postgres专家David E. Wheeler,says as much in recommending总是使用TIMESTAMP WITH TIME ZONE
。 Wheeler引用了一个狭义的技术例外(分区),甚至在将数据保存到数据库之前将所有值转换为UTC。
最佳做法是在调整到本地化时区以便呈现给用户时以UTC来处理和存储数据。您可能有时想记住其本地时区中的原始日期时间数据;如果是这样,除了转换为UTC之外,还要保存该值。
准则
的第一步,以更好的日期时间处理是避免java.util.Date & .Calendar,使用乔达时间和/或java.time,专注于UTC,学习的行为你特定的JDBC驱动程序和特定的数据库(尽管SQL标准,数据库在日期时间处理方面差别很大)。