上期在《替代JDK日期的开源项目:joda-time》这篇文章中,我通过几个简单的示例,稍稍介绍了joda-time是做什么的,它有什么优势。在我们的日常开发中,我们更侧重日期的使用、计算,本章我将介绍joda-time的详细API的使用。
A.关于局部日期(Partial)
上篇文章中,我列举了一些API和例子介绍了日期对象的构建,但有时我们需要获取部分日期,也就是ReadablePartial的子类,比如说:LocalDate代表的是仅包含年月日信息的对象,而MonthDay代表的是仅有月日信息的对象,例如:
System.out.println(new LocalDate(2009, 9, 6));
System.out.println(new MonthDay(5, 8));
System.out.println(new MonthDay(5, 8));
上面的代码将输出:
2009-09-06
--05-08
DateMidnight:这个类封装某个时区(通常为默认时区)在特定年/月/日的午夜时分的时刻。它基本上类似于 DateTime,不同之处在于时间部分总是为与该对象关联的特定 DateTimeZone 时区的午夜时分。
// 下面输出:2013-05-29T00:00:00.000+08:00
System.out.println(new DateMidnight());
// 是否为同一天
System.out.println(DateTime.now().toDateMidnight().isEqual(new DateMidnight()));
B.关于年表(Chronology)
Joda-time的核心设计就是年表,从根本上将,年表是一种日历系统,是计算时间的方式,比如说我们中国计算日期的方式-农历就是一种年表,Joda-time中支持的年表有以下几种(详细介绍请看维基百科:http://zh.wikipedia.org/wiki/%E6%97%A5%E5%8E%86#.E6.97.A5.E6.9B.86):
ISO(默认,也就是我们日常理解中的日历模式)、GJ、Gregorian、Julian、Buddhist、Coptic、Ethiopic
C.关于时区(TimeZone)
时区是指地球上的相同的区域使用同一个时间定义,例如,北京的时区被指定为东八区,在这个范围内的地区都属于同一个时区,也就是使用相同时间。
// 东8区
DateTimeZone.setDefault(DateTimeZone.forID("Asia/Shanghai"));
System.out.println(DateTime.now());
// 东9区
DateTimeZone.setDefault(DateTimeZone.forID("Asia/Tokyo"));
System.out.println(DateTime.now());
// 西7区
DateTimeZone.setDefault(DateTimeZone.forID("America/Los_Angeles"));
System.out.println(DateTime.now());
DateTimeZone.setDefault(DateTimeZone.forID("Asia/Shanghai"));
System.out.println(DateTime.now());
// 东9区
DateTimeZone.setDefault(DateTimeZone.forID("Asia/Tokyo"));
System.out.println(DateTime.now());
// 西7区
DateTimeZone.setDefault(DateTimeZone.forID("America/Los_Angeles"));
System.out.println(DateTime.now());
上面代码将输出,我们可以看到不同时区的当前时间是不一样的:
2013-05-18T15:27:00.765+08:00
2013-05-18T16:27:00.812+09:00
2013-05-18T00:27:00.812-07:00
D.日期内的操作
1.日期的获取
// 获取当前分钟,获取其他单位如年月日等操作类似
System.out.println(DateTime.now().getMinuteOfHour());
System.out.println(DateTime.now().minuteOfHour().get());
System.out.println(DateTime.now().minuteOfHour().get());
System.out.println(DateTime.now().get(DateTimeFieldType.minuteOfHour()));
// 获取当月的日期的最大值
DateTime.now().dayOfMonth().getMaximumValue()
// 获取当前周是当年内第几周
System.out.println(DateTime.now().getWeekOfWeekyear());
// 获取当前周所在年份
System.out.println(DateTime.now().getWeekyear());
System.out.println(DateTime.now().getWeekyear());
2.日期数值的增减和设置
// 当前日期加3天
DateTime.now().plus(Period.days(3));
DateTime.now().plusDays(3);
DateTime.now().withFieldAdded(DurationFieldType.days(), 3);
DateTime.now().withFieldAdded(DurationFieldType.days(), 3);
// 设置当前月份为11月
DateTime.now().monthOfYear().setCopy(11);
// 设置当月的最后一天
DateTime.now().dayOfMonth().withMaximumValue();
3.日期的区间
Duration:这个类表示一个绝对的精确跨度,以毫秒为单位。这个类提供的要领可以用于通过规则的数学转换(比如1分钟 = 60秒,1天 = 24小时),将时间跨度转换为规则单位(比如秒、分和小时)。
您只在以下情况运用 Duration 的实例:您希望转换一个时间跨度,但是您并不关心这个时间跨度在何时发生,或者运用毫秒处理时间跨度比较方便。
Period:这个类表示与 Duration 相同的概念,但是以人们比较熟悉的单位表示,比如年、月、周。
您可以在以下情况运用 Period:您并不关心这段时期必须在何时发生,或者您更关心检索单个字段的能力,这些字段描述由 Period 封装的时间跨度。
Interval:这个类表示一个特定的时间跨度,将运用一个明确的时刻界定这段时间跨度的范围。Interval 为半开区间,这表示由 Interval 封装的时间跨度包括这段时间的起始时刻,但是不包含结束时刻。
可以在以下情况运用Interval:需要表示在时间连续区间中以特定的点开始和结束的一段时间跨度。
您只在以下情况运用 Duration 的实例:您希望转换一个时间跨度,但是您并不关心这个时间跨度在何时发生,或者运用毫秒处理时间跨度比较方便。
Period:这个类表示与 Duration 相同的概念,但是以人们比较熟悉的单位表示,比如年、月、周。
您可以在以下情况运用 Period:您并不关心这段时期必须在何时发生,或者您更关心检索单个字段的能力,这些字段描述由 Period 封装的时间跨度。
Interval:这个类表示一个特定的时间跨度,将运用一个明确的时刻界定这段时间跨度的范围。Interval 为半开区间,这表示由 Interval 封装的时间跨度包括这段时间的起始时刻,但是不包含结束时刻。
可以在以下情况运用Interval:需要表示在时间连续区间中以特定的点开始和结束的一段时间跨度。
LocalDate start = new LocalDate(2006, 6, 9);
LocalDate end1 = new LocalDate(2006, 6, 12);
LocalDate end1 = new LocalDate(2006, 6, 12);
assertEquals(3, Days.daysBetween(start, end1).getDays());
// Duration的方式将当前时间减去3000ms
System.out.println(DateTime.now().minus(new Duration(3000)));
// Period的方式将当前时间减去3000ms
System.out.println(DateTime.now().minus(new Period().withMillis(3000)));
// 基于Interval的区间获取
assertEquals(3, Days.daysIn(new Interval(start, end1)).getDays());
assertEquals(3, Days.daysIn(new Interval(start, end1)).getDays());
4.日期的比较
DateTime.now().isAfterNow();
DateTime.now().isBefore(new DateTime(2001,5,7, 0, 0));
5.综合示例
打印11月第3个周的周一的后3天的日期
DateTime.now().monthOfYear().setCopy(11) // 设置为11月
.dayOfMonth().withMinimumValue() // 11月的第一天
.plusWeeks(3) // 第一天加3周得到第3周
.dayOfWeek().withMinimumValue() // 第3周的第一天
.plusDays(3); // 第3周的第一天的后3天
由于篇幅有限,本章中只能列举几个重要的API,以做示例,建议可以下载编译joda-time源码,里面提供了详细的测试代码,源码地址:https://github.com/JodaOrg/joda-time
原创文章,请注明引用来源:CM4J