资讯专栏INFORMATION COLUMN

JodaTime开源时间/日期库

frolc / 2755人阅读

摘要:开源时间日期库是很好的替代,另外中也推出了新的库,设计理念与相似。令时间和日期值变得易于管理操作和理解。格式化一个日期时间的具体域包括个年月日时分秒毫秒星期,分别用不同字母表示。

此前Java处理时间日期所使用的 Date 和 Calendar 被诟病不已,Calendar 的主要问题对象可变,而像时间和日期这样的类应该是不可变的,另外其概念模型也有不明确的地方,月份计算从0开始等等。

JodaTime开源时间/日期库是很好的替代,另外Java8中也推出了新的java.time库,设计理念与JodaTime相似。

Joda-Time 令时间和日期值变得易于管理、操作和理解。易于使用是 Joda 的主要设计目标。Joda-Time主类 DateTime 和JDK旧有类 Date 和 Calendar之间可以互相转换。从而保证了与JDK框架的兼容。

1.JodaTime中的时间日期概念 1.1 Instant

"盖将自其变者而观之,则天地曾不能以一瞬",Instant 就代表时间轴上的"一瞬",为保持和JDK一致,时间轴起点亦在1970年,单位为ms。

Instant类的作用就围绕着时间轴上的绝对时间(long类型),提供了构造,修改,加减等方法。另外它也是DateTime类的构建方式之一

DateTime dateTime = new DateTime(new Instant());
DateTime dateTime = new Instant().toDateTime();
1.2 Interval

Interval代表一个Instant到下一个Instant的时间间隔,这个间隔是半开闭集合。即包括起始的一瞬,但并不包含结束的一瞬。

Instant表示时间轴上的一点,Interval则表示时间轴上一段区间。

1.3 Duration

Duration指用ms计量的一段持续时间。Duration虽然与Interval看似类似,但Duration的概念相对孤立,仅表示时间区间长度,与时间轴上的位置没有关系。

Duration 可以参与两个Instant之间的运算。

$$instant + duration = instant$$

1.4 Period

Period表示用具体域(如年/月/日/时/分/秒/毫秒/星期)计量的一段时间,如3天,2小时等。这亦是与时间轴无关的一个概念,与Duration的不同只是在计量方式上。Duration与时区和历法无关,Period则与之相关。

Period概念之所以重要,可以想象在某年1月和7月的基础上分别加 数值为1月的Period,则二者所需的具体时间ms值是不相同的。Period 是描述时间间隔长度的另一种方式。

由上可见Period是与Duration同级别的概念,亦可以参与Instant的运算。
$$instant + period = instant$$

另外也可以由 Interval 获得相应的Period和Duration。

DateTime now,then;
Interval interval = new Interval(now,then);
Period period = interval.toPeriod();
Duration duration = interval.toDuration();
1.5 Chronology

Chronology代表历法,负责具体时间日期的计算,虽然作用上居于核心位置,但在Api上却容易被忽视。
使用者往往不需要指定具体的历法,感受不到其存在。历法类是单例实现,默认实现是 ISOChronology。

1.6 TimeZone

代表时区。可以用来构建历法类。

DateTimeZone zone = DateTimeZone.forID("Europe/London");
1.7 Partial

Partial表示日期时间的一部分,是本地化时间,与时区无关。
例如一个TimeDate指定为2015年11月9日11时11分11秒,则在时间轴上为确定一点;若省略掉年份时间信息,只取11月9日,则在时间轴上则对应多点,表示历年来11月9日这一天的任意时间点。其实现类有下列几种:

LocalDate

LocalTime

LocalDateTime

YearMonth

MonthDay

由概念可知 为Partial指定其缺失域和时区信息,可以将其在时间轴上的位置确定下来。
$$partial + missing fields + time zone = instant$$

1.8 格式化

一个日期时间的具体域包括8个:年/月/日/时/分/秒/毫秒 + 星期,分别用不同字母表示。

对于DateTime/LocalDate可以采用直接构造格式化

DateTime dt = new DateTime();
String a = dt.toString();
String b = dt.toString("dd:MM:yy");
String c = dt.toString("EEE", Locale.FRENCH);

当然这不过是个障眼法,真实的格式化工作由DateTimeFormatter完成,标准格式类由ISODateTimeFormat提供。

DateTimeFormatter fmt = ISODateTimeFormat.dateTime();

如果要自定义格式化,需要创建DateTimeFormatter类

DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMddEE");
DateTimeFormatter germanFmt = fmt.withLocale(Locale.GERMAN);

now.toString(fmt);

更详细的流式构造

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
        .appendDayOfMonth(2)
        .appendLiteral("-")
        .appendMonthOfYearShortText()
        .appendLiteral("-")
        .appendTwoDigitYear(1956)  // pivot = 1956
        .toFormatter();
1.9 不可变性

Joda 类具有不可变性,因此它们的实例无法被修改。不可变类的一个优点就是它们是线程安全的。

2 DateTime使用 2.1 构造方法

DateTime 是Joda-Time的核心类,代表时间日期值,其构造方法多样,即可以使用各种对象构造,亦可以使用基本类型构造,核心在于能够确定在时间轴上的位置。可以参与构造的对象包括:

Date - a JDK instant

Calendar - a JDK calendar

String - in ISO8601 format

Long - in milliseconds

any Joda-Time date-time class

int[]

Joda-Time支持Date/Calendar构造,保证了与JDK的兼容.

2.2.获取具体信息和属性使用

有了DateTime对象可以用get方法获取从年到毫秒数的具体信息。以年为示例如下:

int year = dateTime.getYear();
int yearincenture = dateTime.getYearOfCentury();
int yearofera = dateTime.getYearOfEra();

DateTime还分别提供了一个内部类 Property,Property的功能更加强大。DateTime的属性有多种类型,并支持修改。

Property p = now.year(); //年份
boolean isleap = p.isLeap(); //判断是否是闰年
String name = p.getAsText();

Property p = now.monthOfYear();//当年中的月份
p.setCopy(6); //将月份改为六月

Property p = now.dayOfMonth(); //当月中的天数
p.setCopy(9); //将天数改为当月9号

Property p = now.dayOfWeek();  //当星期的天数
p.setCopy(1); //将天数改为星期1
2.3.日期计算和不可变性(immutable)

DateTime对时间日期的计算主要针对7种域提供 with/plus/minus 三种方法。

DateTime dt = dateTime.plusYears(1);

陷阱:因为不可变性,DateTime修改之后得到的是一个新DateTime对象,这一点可以通过hashcode来验证,因此必须给这个新对象赋一个引用。

2.4历法和时区

Joda-Time支持多种历法和时区,其中默认历法是ISO标准历法,默认时区与JDK相同。Joda-Time使用插件化(pluggable)机制,其中时区类被设计成历法类的一个依赖。

Chronology类表示对历法抽象

DateTimeZone类表示对时区的抽象

//1.指定历法和时区
DateTimeZone zone = DateTimeZone.forID("Asia/Tokyo");
Chronology gregorianJuian =GJChronology.getInstance(zone);
DateTime daTime = new DateTime(gregorianJuian);

通过DateTimeZone.getAvailableIDs()可以获取全部时区名称.

2.5 本地时间

LocalDate可以通过DateTime获取,亦可以自行构建。

LocalDate localDate= dateTime.toLocalDate();

LocalDate localDate = new LocalDate(2009, 9, 6);
3. 时间处理示例 3.1 获取当前日期和年月日
LocalDate now = new LocalDate();
//DateTime now = new DateTime();

now.toString();
int year = now.getYear();
int month = now.getMonthOfYear();
int day = now.getDayOfWeek();
3.2 获取某个特定的日期
LocalDate now = new LocalDate(2015,11,9);
DateTime now = new DateTime(2015,11,9,7,15);
3.3 判断两个日期的关系
LocalDate now = new LocalDate(2015,11,9);
LocalDate then = new LocalDate(2015,11,9);
now.isEqual(then);
now.isBefore(then);
now.isAfter(then);
3.4 修改/添加/减少日期
LocalDate now = new LocalDate();
then = now.plusYears(1);
then = now.minusYears(1);
then = now.withYear(2016);
3.5 检查重复日期,如生日
MonthDay birth = new MonthDay(11,9);

LocalDate now = new LocalDate();
MonthDay today = new MonthDay(now);

birth.isEqual(today);
3.6 获取1周/月/日后的日期
then = now.plusWeeks(1);
then = now.plusMonths(1);
then = now.plusDays(1);
3.7 两个日期之间包含多少天,多少个月
Period period = new Period(now,then);
System.out.println(period.getDays());
System.out.println(period.getYears());
System.out.println(period.getMonths());
3.8 获得上个月最后一天
LocalDate now = new LocalDate();
LocalDate lastDayOfPreviousMonth = now.minusMonths(1).
            dayOfMonth().withMaximumValue();

dayOfMonth方法返回了属性(property)。

3.9 计算 11 月中第一个星期一
DateTime now = new DateTime();
now = now.monthOfYear().setCopy(11)
        .dayOfMonth().withMinimumValue()//获得当月1号
        .plusDays(6)
        .dayOfWeek().setCopy(1);//获得星期一

当得到本月1号后,使用dayOfWeek()将获得1号所在的星期,直接使用setCopy(1)指定有可能会回到上个月月末的星期1.

因此使用plusDays(6)作预处理,即使用1当月7号所在星期的星期1。

3.10 计算五年后的第二个月的最后一天:
DateTime now = new DateTime();
DateTime then = now.plusYears(5)
        .monthOfYear()
        .setCopy(2)
        .dayOfMonth()
        .withMaximumValue();

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64739.html

相关文章

  • Spring新功能

    摘要:新特性重要功能升级为了解决各种环境下如开发测试和生产选择不同配置的问题,引入了环境功能。这个消息模块支持的功能,同时提供了基于模板的方式发布消息是第一批支持特性的框架,比如它所支持的表达式。 Spring 3.1新特性 重要功能升级 为了解决各种环境下(如开发、测试和生产)选择不同配置的问题,Spring 3.1引入了环境profile功能。借助于profile,就能根据应用部署在什...

    baiy 评论0 收藏0
  • 12个值得关注的顶级可视化JS 涉及图表、动画、时间处理,表格操作

    摘要:本文是译文,原文是我在原文的基础上加了百度的图表库,这个也是毫不逊色其他图表库的。更新记录图表类数据驱动文档通常被称为最强大的开源可视化库。是迄今为止最好的图表库。在顶级功能支持,使任何元素可拖动,可旋转或可滑动滚动和快速性能的能力。 本文是译文,原文是https://da-14.com/blog/top-11...我在原文的基础上加了百度的Echats图表库,这个也是毫不逊色其他图表...

    JinB 评论0 收藏0
  • iView 近期的更新,以及那些“不为人知”的故事

    摘要:如图所示还有其它很多项的更新,比如新增属性,可以设置面板展开时默认显示的日期。目前最新版本支持键盘可访问性的组件有。期待你的加入下个版本预告下个版本计划重构组件,以全面支持表单组件的键盘可访问性,敬请期待。 在过去的两个多月里,iView 陆续发布了 2.9.0 和 2.10.0 两个重要版本。这两个版本总共有 255 个 commit,超过 40 项更新。来看一下,iView 具体都...

    UsherChen 评论0 收藏0
  • 推荐轻量高效无依赖的开源JS插件和

    摘要:弹出层是一个轻量级的库用于管理工具提示和弹窗效果。一个带有的跨浏览器富文本编辑器。由制作,适用于每天写作的富文本编辑器。轻量的操作库。是一个快速简单轻量级的浏览器功能检测库。它没有任何的依赖,并且压缩后仅有。极小跨平台的全屏插件。 在这里维持一个持续更新的地方 图片 baguetteBox.js - 是一个简单易用的响应式图像灯箱效果脚本。demo Lightgallery.js -...

    AlphaWallet 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<