任何企业应用程序都须要处理时间问题。应用程序须要知道当前的时间点和下一个时间点,有时它们还必须计算这两个时间点之间的路径。使用 JDK 完成这项任务将很是痛苦和繁琐。如今来看看 Joda Time,一个面向 Java™ 平台的易于使用的开源时间/日期库。正如您在本文中了解的那样,Joda-Time 轻松化解了处理日期和时间的痛苦和繁琐。java
在编写企业应用程序时,我经常须要处理日期。而且在个人最新项目中 — 保险行业 — 纠正日期计算尤为重要。使用 java.util.Calendar
让我有些不安。若是您也曾使用这个类处理过日期/时间值,那么您就知道它使用起来有多麻烦。所以当我接触到 Joda-Time — 面向 Java 应用程序的日期/时间库的替代选择 — 我决定研究一下。其结果是:我很庆幸我这么作了。算法
Joda-Time 令时间和日期值变得易于管理、操做和理解。事实上,易于使用是 Joda 的主要设计目标。其余目标包括可扩展性、完整的特性集以及对多种日历系统的支持。而且 Joda 与 JDK 是百分之百可互操做的,所以您无需替换全部 Java 代码,只须要替换执行日期/时间计算的那部分代码。安全
Joda 其实是涵盖众多用于 Java 语言的替代 API 的大型项目,所以从技术上讲,使用 Joda 和 Joda-Time 名称表示相同的意思是一种误称。但在撰写本文之际,Joda-Time API 目前彷佛是惟一处于活跃开发状态下的 Joda API。考虑到 Joda 大型项目的当前状态,我想将 Joda-Time 简称为 Joda 应该没什么问题。框架
为何要使用 Joda?考虑建立一个用时间表示的某个随意的时刻 — 好比,2000 年 1 月 1 日 0 时 0 分。我如何建立一个用时间表示这个瞬间的 JDK 对象?使用 java.util.Date
?事实上这是行不通的,由于自 JDK 1.1 以后的每一个 Java 版本的 Javadoc 都声明应当使用 java.util.Calendar
。Date
中不同意使用的构造函数的数量严重限制了您建立此类对象的途径。函数
然而,Date
确实有一个构造函数,您能够用来建立用时间表示某个瞬间的对象(除 “如今” 之外)。该方法使用距离 1970 年 1 月 1 日子时格林威治标准时间(也称为 epoch)以来的毫秒数做为一个参数,对时区进行校订。考虑到 Y2K 对软件开发企业的重要性,您可能会认为我已经记住了这个值 — 可是我没有。Date
也不过如此。工具
那么 Calendar
又如何呢?我将使用下面的方式建立必需的实例:spa
Calendar calendar = Calendar.getInstance(); calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0); |
使用 Joda,代码应该相似以下所示:插件
DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0); |
Joda 使用如下概念,它们能够应用到任何日期/时间库:线程
我将针对 Joda 依次讨论每个概念。设计
我在本文讨论的 Joda 类具备不可变性,所以它们的实例没法被修改。(不可变类的一个优势就是它们是线程安全的)。我将向您展现的用于处理日期计算的 API 方法所有返回一个对应 Joda 类的新实例,同时保持原始实例不变。当您经过一个 API 方法操做 Joda 类时,您必须捕捉该方法的返回值,由于您正在处理的实例不能被修改。您可能对这种模式很熟悉;好比,这正是 java.lang.String
的各类操做方法的工做方式。
Instant
表示时间上的某个精确的时刻,使用从 epoch 开始计算的毫秒表示。这必定义与 JDK 相同,这就是为何任何 Joda Instant
子类均可以与 JDK Date
和 Calendar
类兼容的缘由。
更通用一点的定义是:一个瞬间 就是指时间线上只出现一次且惟一的一个时间点,而且这种日期结构只能以一种有意义的方式出现一次。
一个局部时间,正如我将在本文中将其称为局部时间片断同样,它指的是时间的一部分片断。瞬间性指定了与 epoch 相对的时间上的一个精确时刻,与此相反,局部时间片断指的是在时间上能够来回 “移动” 的一个时刻,这样它即可以应用于多个实例。好比,6 月 2 日 能够应用于任意一年的 6 月份(使用 Gregorian 日历)的次日的任意瞬间。一样,11:06 p.m. 能够应用于任意一年的任意一天,而且天天只能使用一次。即便它们没有指定一个时间上的精确时刻,局部时间片断仍然是有用的。
我喜欢将局部时间片断看做一个重复周期中的一点,这样的话,若是我正在考虑的日期构建能够以一种有意义的方式出现屡次(即重复的),那么它就是一个局部时间。
Joda 本质 — 以及其设计核心 — 的关键就是年表(它的含义由一个同名抽象类捕捉)。从根本上讲,年表是一种日历系统 — 一种计算时间的特殊方式 — 而且是一种在其中执行日历算法的框架。受 Joda 支持的年表的例子包括:
Joda-Time 1.6 支持 8 种年表,每一种均可以做为特定日历系统的计算引擎。
时区是值一个相对于英国格林威治的地理位置,用于计算时间。要了解事件发生的精确时间,还必须知道发生此事件的位置。任何严格的时间计算都必须涉及时区(或相对于 GMT),除非在同一个时区内发生了相对时间计算(即时这样时区也很重要,若是事件对于位于另外一个时区的各方存在利益关系的话)。
DateTimeZone
是 Joda 库用于封装位置概念的类。许多日期和时间计算均可以在不涉及时区的状况下完成,可是仍然须要了解 DateTimeZone
如何影响 Joda 的操做。默认时间,即从运行代码的机器的系统时钟检索到的时间,在大部分状况下被使用。
谈到日期处理,Joda 是一种使人惊奇的高效工具。不管您是计算日期、打印日期,或是解析日期,Joda 都将是工具箱中的便捷工具。在本文中,我首先介绍了 Joda,它能够做为 JDK 日期/时间库的替代选择。而后介绍了一些 Joda 概念,以及如何使用 Joda 执行日期计算和格式化。
Joda-Time 衍生了一些相关的项目,您可能会发现这些项目颇有用。如今出现了一个针对 Grails Web 开发框架的 Joda-Time 插件。joda-time-jpox 项目的目标就是添加一些必需的映射,以使用 DataNucleus 持久化引擎持久化 Joda-Time 对象。而且,一个针对 Google Web Toolkit(也称为 Goda-Time)的 Joda-Time 实现目前正在开发当中