`

commons-lang(time应用)

阅读更多
JAVA的时间日期处理一直是一个比较复杂的问题,可以说大多数程序员都不能得心应手的处理这些问题,就算通过commons.lang.time包简化了,使用起来仍然有些麻烦,个人认为这可能是最复杂的一个子包。不过相对原始的JDK API,还是简化了不少,因此此子包也相当值得关注。

首先讨论一下关于时间的类,从 JDK 1.1 开始,Date的作用很有限,相应的功能已由Calendar与DateFormat代替。使用 Calendar 类实现日期和时间字段之间转换,使用 DateFormat 类来格式化和分析日期字符串。Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。TimeZone 表示时区偏移量。Locale 对象表示了特定的地理、政治和文化地区。需要 Locale 来执行其任务的操作称为语言环境敏感的操作,它使用 Locale 为用户量身定制信息。SimpleDateFormat的作用主要是用来格式化Date,用过之后就会发现,它其实很不完善,对Calendar提供的支持很少.

关于时间的类放在org.apache.commons.lang.time 包下面,它包括以下几个类:
DateUtils 包括一组围绕Calendar与Date的实用方法.
DateFormatUtils
DurationFormatUtils
FastDateFormat 一个快速线程安全的SimpleDateFormat版本
StopWatch 提供一个方便的定时的API

DateFormatUtils相对来说比较简单,它的方法全部都是static的,所以不需要用构造器创建新的实例,但它构造器却是public的,这并不是说我们应该在程序中使用它,官方文档已说明,它是为了与其它工具的集成的准备的。它包括的方法主要就是format。主要用途就是根据传入的pattern格式化Date或Calendar。也可以有一些附加的参数,如Locale,TimeZone。
比如这样:

format(java.util.Calendar calendar, java.lang.String pattern, java.util.TimeZone timeZone, java.util.Locale locale) 


当然DateFormatUtils还有一些预定义字段。对应的则是相应的FastDateFormat。
可以这样用:

DateFormatUtils.ISO_DATETIME_FORMAT.format(date)


通过公有的静态final字段来暴露这些常量简化了类的使用,但是却有一些地方是需要注意的,在这方面FastDateFormat做得还是相当不错的。要使final字段真正的不可变,要么这些字段是基本类型的值(int,String等),要么是指向一个不可变对象的引用。同时需要注意的特殊情况是,长度为零的数组总是可变的,要么通过不可变的Collection来包装,要么使数组变成私有的,并添加一个公有的方法,返回一个数组的备份,这在effective java上的Item 15上有详细的介绍。回到原来的话题上,DateFormatUtils内部定义了一些常量,如:


 public static final FastDateFormat ISO_DATE_FORMAT
            = FastDateFormat.getInstance("yyyy-MM-dd");


上面的final 字段代表一个不可变的FastDateFormat,然而要让FastDateFormat字段真正的不可变,FastDateFormat内部必须遵循相应的规则才可以。

不要提供能修改对象状态的方法
确保类不会被继承
让所有字段都成为static final字段
确保所有可变的组件不能被访问

详细介绍可参考Effective java第二版的Item 15。仔细查看,会发现FastDateFormat都遵循这些规则,而Effective java 2rd 的出版也在commons-lang 2.4 开发之后,这说明
commons-lang的代码质量还是相当值得肯定的。

其实DateFormateUtils内部细节实现完全依靠FastDateFormat,DateFormateUtils只是把一些常用的格式化功能单独组织起来,让日期时间的使用变得简单,毕竟大多数时候用户查看API时,如果有太多的方法,会给他们纷繁复杂的感觉。如果需要更加强大灵活的日期格式化功能,可以直接使用FastDateFormat,FastDateFormat这个类编写比较复杂,它有自己的一套解析规则,同时又使用了DateFormat类的一些规则,如Pattern。与SimpleDateFormat不同,FastDateFormat是线程安全,所以这个类在多线程的服务环境中特别有用。虽然它们都继承自java.text.Format,其实FastDateFormat相当于DateFormat与SimpleDateFormat的合并,只是功能更强大而已。如果是从DateFormat迁移到FastDateFormat的话,还是有一些地方需要注意的,比如,Date(String date)被DateFormat.parse(String s) 取代了,仔细查看,FastDateFormat并没有类似的方法,其实准确的说,把日期解析放在DateFormat本身就不太合理,不看文档的话,大多数人都会认为Date应该提供该功能。所以commons-lang把它放在了DateUtils 类中,对应方法则更加的强大:

parseDate(java.lang.String str, java.lang.String[] parsePatterns) 


因parsePatterns可以包括多种pattern,只要满足其中的一种即可。如果使用SimpleDateFormat,则先要通过SimpleDateFormat(String str)创建实例,然后通过applyPattern(String pattern)来变换不同的pattern。DateUtils提供了很多很方便的功能,减轻了使用Date的复杂性。把原来需用Calendar才能完成的功能统一集中了起来,也就是说没有对应的CalendarUtils类。在JDK中,Date与Calendar概念本身就有些混淆,只是为了保持兼容性才引入的Calendar。相对于Calendar提供的方法,DateUtils提供了更加合理的方法,对时间的单个字段操作变得更加的容易。如需要修改时间Date的某个字段,必须先获得Date对象实例,再传入Calendar,才能修改,如:

	public static Date add(Date date, int calendarField, int amount) {
        if (date == null) {
            throw new IllegalArgumentException("The date must not be null");
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(calendarField, amount);
        return c.getTime();
    }

在这方面commons-lang的确做得很完善,如:

	public static Date addMinutes(Date date, int amount) {
        return add(date, Calendar.MINUTE, amount);
    }

方法名也非常的直观,使用也更加方便了。

但有一些方法不是很好理解,如:

public static long getFragmentInSeconds(Date date,int fragment)


这个方法的作用是:返回一个指定时间的秒数。关键的是参数fragment,它的作用非常重要。它的值必须是Calendar的时间常量字段。如Calendar.MONTH ,需要注意的是,小时必须用24小时制的,即Calendar.HOUR_OF_DAY ,而不能用Calendar.HOUR字段。如果使用
Calendar.HOUR_OF_DAY 则时间2009-09-29 17:02:37 会返回157 (2*60+37),即所有大于等于fragment单位的字段将被忽略。

相对于这些增强已有功能的类,还有一些对常用功能进行补充的类,如DurationFormatUtils ,这个类主要的作用就是处理时间的片断,主要包括两种方法:
formatDuration和formatPeriod。如:

formatDuration(long durationMillis, java.lang.String format) 


通过传入一个毫秒数与日期格式(如:yyyy-MM-dd HH:mm:ss),它会返回一个对应日期的字符串形式。当然Date类本身有一个与这类似的方法,即Date(String s)方法,用于创建一个Date实例,但它只是创建一个Date实例,如果要转换成相应的String,还要经过一些步骤才行。需要注意的是,此日期片断能表示的最大单位为天,用法也很简单:

String pattern = "yyyy-MM-dd HH:mm:ss";
long durationMillis = (10+20*60+13*3600+4*24*3600) * 1000;
String formatDate = DurationFormatUtils.formatDuration(durationMillis,
				pattern);
System.out.println(formatDate);



需要注意的是日期格式的小时必须用HH,而不能用hh 。
下面介绍一下formatPeriod方法:

public static java.lang.String formatPeriod(long startMillis,
                                            long endMillis,
                                            java.lang.String format)

用于计算两个时间之间的片断,然后转化成相应的日期字符串类型,即能表示的最大单位,如下例所示:
String[] parsePatterns = {"yyyy-MM-dd HH:mm:ss"};
String str = "2009-09-29 15:30:12";
String str2 = "2010-09-30 15:40:18";
Date date = DateUtils.parseDate(str, parsePatterns);
Date date2 = DateUtils.parseDate(str2, parsePatterns);
long durationMillis = DateUtils.getFragmentInMilliseconds(date, Calendar.YEAR);
long durationMillis2 =DateUtils.getFragmentInMilliseconds(date2,Calendar.YEAR);

String s =	DurationFormatUtils.formatPeriod(durationMillis, durationMillis2, 										"yyyy-MM-dd HH:mm:ss")

其中s的值为:0000-00-01 00:10:06

上述两种方法功能有些相似,本人一直以为底层用了同样的实现方法,因为看上去只要把两个时间点计算成毫秒,相后相减就与第一个方法一样了,实际不然。它们的底层完全不一样,各用各的实现方式,没有任何交差,根本原来就在于它们能表示的最大单位不一样,如下例如示:

String[] parsePatterns = {"yyyy-MM-dd HH:mm:ss"};
		String str = "2009-05-29 15:30:12";
		String str2 = "2011-09-30 14:40:18";
		Date date = DateUtils.parseDate(str, parsePatterns);
		Date date2 = DateUtils.parseDate(str2, parsePatterns);
long durationMillis = DateUtils.getFragmentInMilliseconds(date, Calendar.YEAR);
long durationMillis2 =DateUtils.getFragmentInMilliseconds(date2,Calendar.YEAR);
		System.out.println(DurationFormatUtils.formatPeriod(durationMillis, 
											durationMillis2, "yyyy-MM-dd HH:mm:ss"));
		System.out.println(DurationFormatUtils.formatDuration(durationMillis2-											durationMillis,"yyyy-MM-dd HH:mm:ss"));


结果为:

0000-04-01 23:10:06
0000-00-123 23:10:06


time包还有一个StopWatch的类,此类主要作用是用来记时,有start,split,suspend之类的方法,平时能用到的地方不多。
分享到:
评论
1 楼 hanlongjie 2016-02-23  
 

相关推荐

    miaosha:SpringBoot构建电商基础秒杀项目

    SpringBoot构建电商基础秒杀项目 项目简介 通过SpringBoot快速搭建的前后端分离的电商基础秒杀项目...org.apache.commons:commons-lang3 org.hibernate:hibernate-validator joda-time:joda-time junit:junit org.spri

    t淘淘商城项目 商城项目 视频和源码教程 详细

    <commons-lang3.version>3.3.2</commons-lang3.version> <commons-io.version>1.3.2</commons-io.version> <commons-net.version>3.3</commons-net.version> <pagehelper.version>3.4.2-fix ...

    xultimate-toolkit:基于JavaEE应用程序参考架构的Spring框架

    xultimate-toolkit The X-Ultimate Toolkit provides ...封装commons-lang3,添加CompareToBuilderUtils、EqualsBuilderUtils、HashCodeBuilderUtils、ToStringBuilderUtils。 添加MapBuilder、ListBuilder、SetBuilder

    Java开发实战1200例(第1卷).(清华出版.李钟尉.陈丹丹).part3

    10.1 Commons Lang组件简介 273 实例216 数组元素的增加 273 实例217 数组元素的删除 274 实例218 生成随机字符串 275 实例219 序列化与反序列化 276 实例220 分数的常见运算 277 实例221 整数取值范围判断 279 10.2...

    Spring-Reference_zh_CN(Spring中文参考手册)

    6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点实施 7.2.3. AspectJ切入点表达式 7.2.4. 便利的切入...

    spring chm文档

    6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点实施 7.2.3. AspectJ切入点表达式 7.2.4. ...

    jsp探针 ver0.1

    Class.forName("org.apache.commons.lang.SystemUtils"); supportCommonLang = true; } catch (ClassNotFoundException ex) { } try { Class.forName("org.apache.regexp.RE"); supportJakartaRegExp = true; } ...

    Spring中文帮助文档

    2.3.4. 对AspectJ装载时织入(AspectJ load-time weaving)的支持 2.4. 中间层 2.4.1. 在XML里更为简单的声明性事务配置 2.4.2. 对Websphere 事务管理的完整支持 2.4.3. JPA 2.4.4. 异步的JMS 2.4.5. JDBC ...

    Spring API

    2.3.4. 对AspectJ装载时织入(AspectJ load-time weaving)的支持 2.4. 中间层 2.4.1. 在XML里更为简单的声明性事务配置 2.4.2. 对Websphere 事务管理的完整支持 2.4.3. JPA 2.4.4. 异步的JMS 2.4.5. JDBC ...

    Spring 2.0 开发参考手册

    6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点实施 7.2.3. AspectJ切入点表达式 7.2.4. ...

    DWR.xml配置文件说明书(含源码)

    import org.apache.commons.validator.EmailValidator; return EmailValidator.getInstance(); ... 4 Signatures in dwr.xml Signatures部分用于配置Collections中装载对象元素的类型.举个例子来说:下面的...

Global site tag (gtag.js) - Google Analytics