Java日期时间处理
Author: lzj
1. 常用日期类
java.util.Date
代码中一般创建的就是这个类的对象,
需要注意的是: 这个类的部分方法已经 *@Deprecated* 了, 对应推荐使用下面说到的Calendar类的相关方法
常用方法:
- getTime() / setTime(long time)
- before(Date date) / after(Date date)
- compareTo(Date date)
java.sql.Date
java.sql.Time
java.sql.Timestamp
这三个类是java.util.Date的子类, 主要是为了针对SQL语句时使用
java.util.Calendar
Calendar是一个抽象类, 用来获取一个时间点的时间信息, 例如: 取每月第一天, 每月最后一天, 一年中的第几天等等都使用这个类
获取Calendar实例的方法:
Calendar c = Calendar.getInstance();
Calendar类的常用方法:
- getTime(), 返回一个Date对象, 一般是利用Calendar对象处理好时间信息, 然后调用getTime()方法返回Date对象
- getTimeInMillis(), 也可以调用这个方法返回long毫秒数
- get(int field), 返回参数指定日历字段的值
- set(int field, int value), 设置参数指定日历字段的值
- add(int field, int amount), 在指定的日历字段上加或减去参数值
- set方法还有三个重载, 可以直接设置年, 月, 日, 时, 分, 秒
关于参数field
Calendar提供了大量的静态常量, 分别表示不同的时间点含义
Date now = new Date(); // 示例代码运行时间: 2016-11-03 15:29:29
Calendar c = Calendar.getInstance();
c.setTime(now);
System.out.println(c.get(Calendar.YEAR)); // 2016
System.out.println(c.get(Calendar.MONTH)); // 10, 注意月份是从0开始的
System.out.println(c.get(Calendar.DATE)); // 3
System.out.println(c.get(Calendar.WEEK_OF_MONTH)); // 1, 本月第几周
System.out.println(c.get(Calendar.DAY_OF_WEEK)); // 5, 本周第几天, 从周日开始算
System.out.println(c.get(Calendar.HOUR_OF_DAY)); // 15, 24小时制
System.out.println(c.get(Calendar.MINUTE)); // 29
System.out.println(c.get(Calendar.SECOND)); //29
java.text.DateFormat 和 java.text.SimpleDateFormat
这两个类用来将日期对象格式化(format方法)为字符串, 或将字符串解析(parse方法)为日期对象
DateFormat是抽象类, 为SimpleDateFormat的父类, 编码时使用SimpleDateFormat实例化对象即可
Date currDate = new Date();
String strCurrDate = "2016-11-03 15:29:29";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(df.format(currDate));
System.out.println(df.parse(strCurrDate));
注意事项:
Calendar, DateFormat, SimpleDateFormat 为非线程安全类
2. DateUtils和DateFormatUtils
DateUtils和DateFormatUtils 属于Apache Commons项目的Lang包, 位于org.apache.commons.lang.time包目录下,
其作用就是处理日期时间信息.
DateUtils和DateFormatUtils的实现, 就是对Calendar, Date, SimpelDateFormat等基本日期时间类的综合使用, 熟悉了这些日期时间基本类的使用之后, 完全可以自己封闭属于自己的日期工具类.
2.1 DateUtils常用方法
add方法
- addYears(Date date, int amount)
- addMonths(Date date, int amount)
- addDays(Date date, int amount)
- addHours(Date date, int amount)
- addMinutes(Date date, int amount)
- addSeconds(Date date, int amount)
这组6个方法比较常用, 其作用就是在相应的日历字段上加减参数值, 并返回一个新的Date对象
其实现就是调用了Calendar类的setTime(Date date)
方法和add(int field, int amount)
方法
以addYears为例, 看下源码
public static Date addYears(Date date, int amount) {
return add(date, Calendar.YEAR, amount);
}
Deprecated
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();
}
这里DateUtils将add方法*@Deprecated*了, 并不是说这个方法不能使用了, 而是不再建议在外部调用这个方法,
对这个方法做了一次重构(以明确函数取代参数), 我们只需要使用重构后的具体方法就可以了.
重构手法: 以明确函数取代参数
针对参数的每一个可能值, 建立一个独立的函数, 详情见《重构 改善既有代码的设计》
set方法
- setYears(Date date, int amount)
- setMonths(Date date, int amount)
- setDays(Date date, int amount)
- setHours(Date date, int amount)
- setMinutes(Date date, int amount)
- setSeconds(Date date, int amount)
这6个方法作用是给日期对象的特定日历字段赋值, 对应的这个方法中使用的是Calendar类的set(int field, int value)
方法
舍入方法
- round(Date date, int field)
- round(Calendar date, int field)
- round(Object date, int field)
- truncate(Date date, int field)
- truncate(Calendar date, int field)
- truncate(Object date, int field)
这组方法主要是对日期时间对象进行"四舍五入"或"截断"操作
round()方法的三个重载实现的功能是四舍五入, 第2个参数field表示对此字段右侧的字段进行四舍五入操作
truncate()方法的三个重载实现的功能是截断, 第2个参数field表示对此字段右侧的字段进行截断
String strCurrDate = "2016-11-03 13:40:29";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = df.parse(strCurrDate);
System.out.println(DateUtils.round(date, Calendar.HOUR));
System.out.println(DateUtils.truncate(date, Calendar.HOUR));
// Thu Nov 03 14:00:00 CST 2016
// Thu Nov 03 13:00:00 CST 2016
比较方法
- isSameDay(Date date1, Date date2)
- isSameDay(Calendar cal1, Calendar cal2)
- isSameInstant(Date date1, Date date2)
- isSameInstant(Calendar cal1, Calendar cal2)
从方法名很容易识别这组方法的功能,
isSameDay的两个重载方法用于判断两个日期时间对象是否是同一天
isSameInstant的两个重载方法用于判断两个日期时间对象是否是同一个实例
getFragmentIn*系列方法
- getFragmentInDays(Date date, int fragment)
- getFragmentInHours(Date date, int fragment)
- ...
表示指定时间的天(小时)数, 关键参数是fragment, 为Calendar指定的时间常量字段值.
String strCurrDate = "2016-11-03 13:40:29";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = df.parse(strCurrDate);
System.out.println(DateUtils.getFragmentInDays(date, Calendar.YEAR)); // 308, 表示当年已经过去308天
System.out.println(DateUtils.getFragmentInDays(date, Calendar.MONTH)); // 3, 表示当月已经过去3天
System.out.println(DateUtils.getFragmentInHours(date, Calendar.MONTH)); // 85, 表示当月已经过去85小时
System.out.println(DateUtils.getFragmentInHours(date, Calendar.DATE)); // 13, 表示当天已经过去13小时
若传入的fragment参数的值不在Calendar类定义的日期常量字段值的范围内, 则抛出异常信息:
Exception in thread "main" java.lang.IllegalArgumentException: The fragment 123 is not supported
若传入的fragment参数的值不在语义范围内, 则返回0, 例如:
System.out.println(DateUtils.getFragmentInHours(date, Calendar.MINUTE)); // 0, 在当前分钟中, 取不出过去了多少小时
iterator方法
- iterator(Date focus, int rangeStyle)
- iterator(Calendar focus, int rangeStyle)
- iterator(Object focus, int rangeStyle)
DateUtils提供了迭代器方法, 这个方法会返回一个Iterator对象, Iterator对象中包含了指定范围(rangeStyle)的日期对象.
关于参数rangeStyle的取值, DateUtils提供了6个int型静态常量, 分别为:
/** A week range, starting on Sunday. */
public final static int RANGE_WEEK_SUNDAY = 1;
/** * A week range, starting on Monday. */
public final static int RANGE_WEEK_MONDAY = 2;
/** * A week range, starting on the day focused. */
public final static int RANGE_WEEK_RELATIVE = 3;
/** A week range, centered around the day focused. */
public final static int RANGE_WEEK_CENTER = 4;
/** A month range, the week starting on Sunday. */
public final static int RANGE_MONTH_SUNDAY = 5;
/** * A month range, the week starting on Monday. */
public final static int RANGE_MONTH_MONDAY = 6;
举个例子:
String strCurrDate = "2016-11-05";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Date date = df.parse(strCurrDate);
Iterator<Calendar> iter2 = DateUtils.iterator(date, DateUtils.RANGE_WEEK_RELATIVE);
while(iter2.hasNext()) {
Calendar c = iter2.next();
System.out.println(df.format(c.getTime()));
}
// 输出结果:
// 2016-11-05
// 2016-11-06
// 2016-11-07
// 2016-11-08
// 2016-11-09
// 2016-11-10
// 2016-11-11
parseDate方法
- parseDate(String str, String[] parsePatterns)
DateUtils只提供了一个解析日期的方法,
第一个参数为要解析的日期字符串
第二个参数为一个字符串数组, 数组中的元素为解析日期所需要的模式串
在方法实现中, 遍历数据parsePatterns以解析日期字符串, 解析成功即跳出遍历, 返回Date对象
2.2 DateFormatUtils常用方法
- format(long millis, String pattern)
- format(Date date, String pattern)
- format(Calendar calendar, String pattern)
就是format方法的三个重载, 很简单
DateUtils和DateFormatUtils除了使用简单方便之外, 还有个好处就是线程安全
因为在方法内部, 无论是Calendar对象还是DateFormat(DateFormatUtils类使用的是FastDateFormat)对象都是创建一个新的实例