Java日期时间处理

时间:2021-12-10 23:38:28

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.DateFormatjava.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)对象都是创建一个新的实例