专栏名称: java一日一条
主要是讲解编程语言java,并且每天都推送一条关于java编程语言的信息
目录
相关文章推荐
芋道源码  ·  300 秒到 4 秒,如何将 MySQL ... ·  昨天  
芋道源码  ·  用 Spring AOP 优化 IN ... ·  3 天前  
芋道源码  ·  船新 IDEA 2025.1 要来了,新特性真香! ·  3 天前  
芋道源码  ·  DeepSeek 全面指南:95% ... ·  4 天前  
51好读  ›  专栏  ›  java一日一条

使用Joda-Time优雅的处理日期时间

java一日一条  · 公众号  · Java  · 2019-09-19 18:47

正文

在Java中处理日期和时间是很常见的需求,基础的工具类就是我们熟悉的Date和Calendar,然而这些工具类的api使用并不是很方便和强大,于是就诞生了 Joda-Time 这个专门处理日期时间的库。

由于Joda-Time很优秀,在Java 8出现前的很长时间内成为Java中日期时间处理的事实标准,用来弥补JDK的不足。在Java 8中引入的 java.time 包是一组新的处理日期时间的API,遵守 JSR 310 。值得一提的是,Joda-Time的作者 Stephen Colebourne 和Oracle一起共同参与了这些API的设计和实现。

值得注意的是,Java 8中的 java.time 包中提供的API和Joda-Time并不完全相同。比如,在Joda-Time中常用的 Interval (用来表示一对DateTime),在 JSR 310 中并不支持。因此,另一个名叫 Threeten 的第三方库用来弥补Java 8的不足。Threeten翻译成中文就是310的意思,表示这个库与 JSR 310 有关。它的作者同样是Joda-Time的作者 Stephen Colebourne

Threeten主要提供两种发行包: ThreeTen-Backport ThreeTen-Extra 。前者的目的在于对Java 6和Java 7的项目提供Java 8的date-time类的支持;后者的目的在于为Java 8的date-time类提供额外的增强功能(比如: Interval 等)。

由于刚接触Joda-Time,并且目前的工作环境还未涉及到Java 8。因此,关于Java 8的date-time和Threeten的API,将在以后合适的时候介绍。这篇文章关注Joda-Time的使用。

总之,作为一种解决某一问题领域的工具库,我认为有以下几个方面值得关注:

  • 功能是否全面,以能够满足生产需要,并用它解决这个问题领域中的绝大多数的问题

  • 是否是主流工具。用的人越多,意味着该库经受了更多生产实践的验证,效率安全等方面都已被证明是可靠的

  • 自己是否已经熟练掌握。会的多不如会的精,如果能够用一个工具快速熟练可靠地解决问题,在时间成本有限的情况下,就不用刻意追求学习其它可替代的库

引入MAVEN依赖

<dependency>    <groupId>joda-timegroupId>    <artifactId>joda-timeartifactId>    <version>2.9.2version>dependency>


核心类介绍

下面介绍5个最常用的date-time类:

  • Instant - 不可变的类,用来表示时间轴上一个瞬时的点

  • DateTime - 不可变的类,用来替换JDK的Calendar类

  • LocalDate - 不可变的类,表示一个本地的日期,而不包含时间部分(没有时区信息)

  • LocalTime - 不可变的类,表示一个本地的时间,而不包含日期部分(没有时区信息)

  • LocalDateTime - 不可变的类,表示一个本地的日期-时间(没有时区信息)


注意:不可变的类,表明了正如Java的String类型一样,其对象是不可变的。即,不论对它进行怎样的改变操作,返回的对象都是新对象。


Instant比较适合用来表示一个事件发生的时间戳。 不用去关心它使用的日历系统或者是所在的时区。
DateTime的主要目的是替换JDK中的Calendar类,用来处理那些时区信息比较重要的场景。
LocalDate比较适合表示出生日期这样的类型,因为不关心这一天中的时间部分。
LocalTime适合表示一个商店的每天开门/关门时间,因为不用关心日期部分。

DateTime类

作为Joda-Time很重要的一个类,详细地看一下它的用法。

构造一个DateTime实例

如果查看 Java Doc ,会发现DateTime有很多构造方法。这是为了使用者能够很方便的由各种表示日期时间的对象构造出DateTime实例。下面介绍一些常用的构造方法:

  • DateTime():这个无参的构造方法会创建一个在当前系统所在时区的当前时间,精确到毫秒

  • DateTime(int year, int monthOfYear, int dayOfMonth, int hourOfDay, int minuteOfHour, int secondOfMinute):这个构造方法方便快速地构造一个指定的时间,这里精确到秒,类似地其它构造方法也可以传入毫秒。

  • DateTime(long instant):这个构造方法创建出来的实例,是通过一个long类型的时间戳,它表示这个时间戳距 1970-01-01T00:00:00Z 的毫秒数。使用默认的时区。

  • DateTime(Object instant):这个构造方法可以通过一个Object对象构造一个实例。这个Object对象可以是这些类型:ReadableInstant, String, Calendar和Date。其中String的格式需要是 ISO8601 格式,详见: ISODateTimeFormat.dateTimeParser()

下面举几个例子:

访问DateTime实例

当你有一个DateTime实例的时候,就可以调用它的各种方法,获取需要的信息。

  • with开头的方法(比如:withYear):用来设置DateTime实例到某个时间,因为DateTime是不可变对象,所以没有提供setter方法可供使用,with方法也没有改变原有的对象,而是返回了设置后的一个副本对象。下面这个例子,将2000-02-29的年份设置为1997。值得注意的是,因为1997年没有2月29日,所以自动转为了28日。


  • plus/minus开头的方法(比如:plusDay, minusMonths):用来返回在DateTime实例上增加或减少一段时间后的实例。下面的例子:在当前的时刻加1天,得到了明天这个时刻的时间;在当前的时刻减1个月,得到了上个月这个时刻的时间。

注意,在增减时间的时候,想象成自己在翻日历,所有的计算都将符合历法,由Joda-Time自动完成,不会出现非法的日期(比如:3月31日加一个月后,并不会出现4月31日)。

  • 返回Property的方法:Property是DateTime中的属性,保存了一些有用的信息。Property对象中的一些方法在这里一并介绍。下面的例子展示了,我们可以通过不同Property中get开头的方法获取一些有用的信息:



有时我们需要对一个DateTime的某些属性进行置0操作。比如,我想得到当天的0点时刻。那么就需要用到Property中round开头的方法(roundFloorCopy)。如下面的例子所示:

其它:还有许多其它方法(比如dateTime.year().isLeap()来判断是不是闰年)。它们的详细含义,请参照 Java Doc ,现查现用,用需求驱动学习。

日历系统和时区

Joda-Time默认使用的是ISO的日历系统,而ISO的日历系统是世界上公历的事实标准。然而,值得注意的是,ISO日历系统在表示1583年之前的历史时间是不精确的。







请到「今天看啥」查看全文