让时间处理简单化 【第三方扩展类库org.apache.commons.lang.time】

    JAVA的时间日期处理一直是一个比较复杂的问题,大多数程序员都不能很轻松的来处理这些问题。首先Java中关于时间的类,从 JDK 1.1 开始,Date的作用很有限,相应的功能已由Calendar与DateFormat代替。使用Calendar类实现日期和时间字段之间转换,使用 DateFormat 类来格式化和分析日期字符串。

     Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。

TimeZone : 表示时区偏移量。

Locale : 表示了特定的地理、政治和文化地区。需要 Locale 来执行其任务的操作称为语言环境敏感的操作,它使用 Locale 为用户量身定制信息。

SimpleDateFormat : 主要是用来格式化Date,用过之后就会发现,它其实不完善,对Calendar提供的支持很少.

     经历几个项目发现apache提供的第三方扩展类库,org.apache.commons.lang.time包比较好用,可以将程序中时间处理变的简单一点,提高你的开发效率,下面介绍下常用的方法和具体使用。

org.apache.commons.lang.time 包括以下几个类:

a. DateFormatUtils        【格式化Calendar与Date并依赖于 FastDateFormat

b. DateUtils                  【围绕Calendar与Date的实用方法】

c. DurationFormatUtils 【毫秒数格式化Calendar与Date】

d. FastDateFormat        【线程安全的SimpleDateFormat

e. StopWatch               【提供一个方便的定时的API 】

1. DateFormatUtils 和 FastDateFormat 

     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)

原来项目中是这样写的:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String nowDay = sdf.format(new Date());

现在可以这样写:

String nowDay = DateFormatUtils.format(nowDay,"yyyy-MM-dd HH:mm:ss");

DateFormatUtils预定义的日期格式有9种之多,基本能满足项目时间格式化的要求,当然也可以自己自定义格式:

复制代码
  public static final FastDateFormat ISO_DATETIME_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
  public static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ");
  public static final FastDateFormat ISO_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd");
  public static final FastDateFormat ISO_DATE_TIME_ZONE_FORMAT = FastDateFormat.getInstance("yyyy-MM-ddZZ");
  public static final FastDateFormat ISO_TIME_FORMAT = FastDateFormat.getInstance("'T'HH:mm:ss");
  public static final FastDateFormat ISO_TIME_TIME_ZONE_FORMAT = FastDateFormat.getInstance("'T'HH:mm:ssZZ");
  public static final FastDateFormat ISO_TIME_NO_T_FORMAT = FastDateFormat.getInstance("HH:mm:ss");
  public static final FastDateFormat ISO_TIME_NO_T_TIME_ZONE_FORMAT = FastDateFormat.getInstance("HH:mm:ssZZ");
复制代码

所以上面的也可以这样写:

DateFormatUtils.ISO_DATETIME_FORMAT.format(date);

   DateFormatUtils 预定义的日期格式,通过公有的静态final字段来暴露这些常量简化了类的使用,但是却有一些地方是需要注意的,在这方面FastDateFormat做得还是相当不错的。要使final字段真正的不可变,

a. 这些字段是基本类型的值(int,String等),

b. 指向一个不可变对象的引用。

c. 需要注意的特殊情况是,长度为零的数组总是可变的,要么通过不可变的Collection来包装,

     要么使数组变成私有的,并添加一个公有的方法,返回一个数组的备份,这在effective java上的Item 15上有详细的介绍。上面的final 字段代表一个不可变的FastDateFormat,然而要让FastDateFormat字段真正的不可变,

FastDateFormat内部必须遵循相应的规则才可以。

a. 不要提供能修改对象状态的方法

b. 确保类不会被继承

c. 让所有字段都成为static final字段

d. 确保所有可变的组件不能被访问

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

eg:

public static Date parseDate(String str, String parsePatterns[]);
String partterns[] = new String[5];
partterns[0] = "yyyy-MM-dd";
DateUtils.parseDate("2015-09-28", partterns);

     因parsePatterns可以包括多种pattern,只要满足其中的一种即可。如果使用SimpleDateFormat则先要通过SimpleDateFormat(String str)创建实例,然后通过applyPattern(String pattern)来变换不同的pattern。

2. DateUtils

     DateUtils提供了很多很方便的功能,减轻了使用Date的复杂性。把原来需用Calendar才能完成的功能统一集中了起来,也就是说没有对应的CalendarUtils类。在JDK中,Date与Calendar概念本身就有些混淆,只是为了保持兼容性才引入的Calendar。相对于Calendar提供的方法,DateUtils提供了更加合理的方法,

    对时间的单个字段操作变得更加的容易。如需要修改时间Date的某个字段,必须先获得Date对象实例,再传入Calendar,才能修改,如:

eg:

复制代码
//方法已经过时了
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的确做得很完善,现在可以这样写:

eg: 

  View Code

     方法名也非常的直观,使用也更加方便了。但有一些方法不是很好理解,就像下面这个函数:

eg:

复制代码
 1 public static long getFragmentInSeconds(Date date,int fragment)
 2 
 3 这个方法的作用是:返回一个指定时间的秒数。关键的是参数fragment,它的作用非常重要。它的值必须是Calendar的时间常量字段。如Calendar.MONTH ,
 4 
 5 需要注意的是,小时必须用24小时制的,即Calendar.HOUR_OF_DAY ,而不能用Calendar.HOUR字段。
 6 /*
 7 * 如现在是2014-10-23 13:27:00,那么
 8 * DateUtils.getFragmentInDays(new Date(), Calendar.MONTH)返回23,表示从当月起已经过去23天了,
 9 * DateUtils.getFragmentInDays(new Date(), Calendar.YEAR)返回296,表示从当年起已经过去296天了,
10 * DateUtils.getFragmentInHours(new Date(), Calendar.DATE)返回13,表示从今天起已经过去13个小时了
11 */
复制代码

   当然在DateUtils也有一些一看就知道是做什么的函数,我在这里列一下,不具体给例子了:

复制代码
@Description: 判断是否是同一天
public static boolean isSameDay(Calendar cal1, Calendar cal2)

@Description: Date 转 Calendar
public static Calendar toCalendar(Date date);

@Description:  从日期特定字段开始四舍五入
public static Calendar round(Calendar date, int field);

* @Description: 格式化截取日期,从给定字段开始
public static Date truncate(Date date, int field);

@Description: 从日期特定字段开始向上舍入
public static Date ceiling(Date date, int field);

eg :
    假设当前时间 2015-09-14
    
    ceiling(new Date(),Calendar.MONTH); 输出 2015-10-01

    round(new Date(), Calendar.MONTH);  输出 2015-09-01
    
    假设当前时间 2015-09-16,超过半月,上面输出结果是一致的

@Description: 比较日历对应字段是否相等
public static boolean truncatedEquals(Calendar cal1, Calendar cal2, int field);
复制代码

3. DurationFormatUtils 和 StopWatch 

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

eg:

复制代码
 1 formatDuration(long durationMillis, java.lang.String format)
 2  
 4 通过传入一个毫秒数与日期格式(如:yyyy-MM-dd HH:mm:ss),它会返回一个对应日期的字符串形式。
 5 
 6 当然Date类本身有一个与这类似的方法,即Date(String s)方法,用于创建一个Date实例,但它只是创建一个Date实例,如果要转换成相应的String,还要经过一些步骤才行。
 7 
 8 需要注意的是,此日期片断能表示的最大单位为天,用法也很简单:
 9 11 String pattern = "yyyy-MM-dd HH:mm:ss"; 
12 long durationMillis = (10+20*60+13*3600+4*24*3600) * 1000; 
13 String formatDate = DurationFormatUtils.formatDuration(durationMillis, pattern); 
14 System.out.println(formatDate);
复制代码

     需要注意的是日期格式的小时必须用HH,而不能用hh 。 
     formatPeriod方法用于计算两个时间之间的片断,然后转化成相应的日期字符串类型,即能表示的最大单位

复制代码
 1 public static java.lang.String formatPeriod(long startMillis, long endMillis, java.lang.String format)
 2 
 3 
 4 String[] parsePatterns = {"yyyy-MM-dd HH:mm:ss"}; 
 5 String str = "2009-09-29 15:30:12"; 
 6 String str2 = "2010-09-30 15:40:18"; 
 7 Date date = DateUtils.parseDate(str, parsePatterns); 
 8 Date date2 = DateUtils.parseDate(str2, parsePatterns); 
 9 long durationMillis = DateUtils.getFragmentInMilliseconds(date, Calendar.YEAR); 
10 long durationMillis2 =DateUtils.getFragmentInMilliseconds(date2,Calendar.YEAR); 
11 
12 String s = DurationFormatUtils.formatPeriod(durationMillis, durationMillis2,"yyyy-MM-dd HH:mm:ss")
13 
14 其中s的值为:0000-00-01 00:10:06
复制代码

    StopWatch 是一个计时器,具体举个简单的例子:

复制代码
         StopWatch stWatch = new StopWatch();
         stWatch.start();
         /**
          * 从周日开始,获取一周的 Calendar 对象
          */
         Iterator<?> itr = iterator(new Date(),RANGE_MONTH_MONDAY);
          while (itr.hasNext()) {
              Calendar gCal = (Calendar) itr.next();
              System.out.println(formatDateObject(gCal.getTime(),"yyyy-MM-dd HH:mm:ss"));
          }
          stWatch.stop();
          System.out.println("花费时间 >>" + stWatch.getTime() + ",毫秒");
复制代码

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值