Java时间处理第三方包:Joda-Time





Joda-Time provides a quality replacement for the Java date and time classes.

Joda-Time is the de facto standard date and time library for Java prior to Java SE 8. Users are now asked to migrate to java.time

——http://www.joda.org/joda-time/

JDK在8之前的版本,对日期时间的处理相当麻烦,有些方法设计非常反人类。而Joda-Time使用起来不仅方便,而且可读性强。虽然JDK 8引用了新的时间处理类,而且参与设计的人也正是Joda-Time的作者,但是由于各种原因,很多项目还是使用的JDK7,使用Joda-Time还是一个不错的选择。

Joda-Time体验



对比之前JDK的处理方式,使用了Joda-Time之后,代码整个神清气爽了很多。接下来就用一些简单的例子来对比一下JDk和Joda-Time的的使用。

依赖

只需要引用一个包。

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.9.4</version>
</dependency>

创建日期

JDK的日期是Date:

Date date = new Date();

Joda-Time的日期是DateTime:

DateTime dateTime = new DateTime();

DateTime在创建的时候还可以轻松的指定特定的日期和时间:

DateTime dateTime2 = new DateTime(2016, 10, 01, 8, 00, 00);

日期格式化

JDK使用的是SimpleDateFormat来进行日期的格式化:

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

乍看之下用起来也不麻烦,但是SimpleDateFormat是非线程安全的。也就是说,如果在并发环境下,必须对SimpleDateFormat对象做同步处理,比如用synchronized,比如用ThreadLocal;或者每次都new一个新的SimpleDateFormat对象,缺点显而易见,就是浪费资源。(详见【Java北京】20160914推送文章:关于SimpleDateFormat时间格式化线程安全问题)

而Joda-Time中的DateTime本身就有格式化的方法,对象直接调用即可:

DateTime dateTime = new DateTime();
String dateTimeStr = dateTime.toString("yyyy-MM-dd HH:mm:ss");

当然,如果要用转换器,Joda-Time也提供了DateTimeFormatter:

DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
String dateTimeStr2 = dtf.print(dateTime);

而且DateTimeFormatter是不可变的,所以是线程安全的。

SimpleDateFormat和DateTimeFormatter都可以将字符串转换成日期:

String dateStr = "2016-10-01";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
   Date date = sdf.parse(dateStr);
} catch (ParseException e) {
   e.printStackTrace();
}

DateTimeFormatter dtf = DateTimeFormat.forPattern(“yyyy-MM-dd”);
dtf.parseDateTime(dateStr);

日期计算

个人在Joda-Time使用中,最喜欢的是它的日期计算。

比如要得到40天前的日期,在JDK中,计算日期相当复杂,必须借助日历Calendar来完成:

Date today = new Date();

Calendar calendar = Calendar.getInstance();

calendar.setTime(today);

calendar.add(Calendar.DAY_OF_MONTH, -40);

Date beforeDay = calendar.getTime();

System.out.println(beforeDay);

Joda-Time中,日期自带日期计算功能,非常直观:

DateTime todayDateTime = new DateTime();

DateTime beforeDateTime = todayDateTime.minusDays(40);

System.out.println(beforeDateTime);

如果要计算两个日期相差的天数,使用JDK是这样实现的:

int diffDays = (int)(today.getTime() - beforeDay.getTime())/(24 * 60 * 60 * 1000);

Joda-Time提供了相关的方法来处理:

int diffDays2 = Days.daysBetween(beforeDateTime, todayDateTime).getDays();

s除了天数,月数、年数计算起来都非常方便,比如月数:

int diffMonths = Months.monthsBetween(beforeDateTime2, todayDateTime).getMonths();



兼容JDK日期

Joda-Time另一个使用起来非常方便的地方就是与JDK日期类的互相转换。因为很多现成的接口可能是用JDk的日期作为入参或者出参,如果Joda-Time不能兼容,那很多方便就不复存在了。

//Date to DateTime

Date date = new Date();

DateTime dateTime = new DateTime(date);

//DateTime to Date
Date date2 = dateTime.toDate();

//Calendar to DateTime
Calendar calendar = Calendar.getInstance();
DateTime dateTime2 = new DateTime(calendar);

//DateTime to Calendar
Calendar calendar2 = dateTime2.toCalendar(Locale.CHINA);

下面是实战中使用样例
package com.xxx.utils;

import org.joda.time.DateTime;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.util.Date;

public class DateUtil {

	public static DateTimeFormatter format = DateTimeFormat.forPattern("yyyyMMddHHmmss");

	// 向下取整5分钟
	public static String roundFloor5Min(Long timestamp) {
		if(timestamp == null) {
			timestamp = System.currentTimeMillis();
		}

		DateTime dt = new DateTime(timestamp);
		return dt.toString("yyyyMMddHH") + String.format("%02d", dt.getMinuteOfHour() / 5 * 5);
	}

	// 偏移 n 天
	public static String getPlusDaysStr(Long timestamp, Integer amount){
		if(timestamp == null) {
			timestamp = System.currentTimeMillis();
		}

		DateTime dt = new DateTime(timestamp);
		return dt.plusDays(amount).toString("yyyyMMdd");
	}

	// 偏移 n 小时
	public static Date getPlusHours(String format14, Integer n) {
		DateTime dt = null;
		if (format14 == null) {
			dt = new DateTime();
		} else {
			dt = format.parseDateTime(format14);
		}

		return dt.plusHours(n).toDate();
	}

	public static String getPlusHoursStr12(String format12, Integer n){
		return new DateTime(getPlusHours(format12+"00", n)).toString("yyyyMMddHHmm");
	}

	// 偏移 n 分钟
	public static Date getPlusMinutes(String format14, Integer n) {
		DateTime dt = null;
		if (format14 == null) {
			dt = new DateTime();
		} else {
			dt = format.parseDateTime(format14);
		}

		return dt.plusMinutes(n).toDate();
	}

	public static String getPlusMinutesStr(String format14, Integer n) {
		return new DateTime(getPlusMinutes(format14, n)).toString("yyyyMMddHHmm");
	}

	// 字符串转Date
	public static Date getDate(String format14) {
		DateTime dt = format.parseDateTime(format14);
		return dt.toDate();
	}

	public static Date getDate12(String format12) {
		return getDate(format12+"00");
	}

	// 延迟分钟 = ceil节点 - 统计时间
	public static Long minusMinute(String ceilTime, String statisTime) {
		DateTime ceilDT = format.parseDateTime(ceilTime+"00");
		DateTime statisDT = format.parseDateTime(statisTime+"00");
		Period p = new Period(statisDT, ceilDT, PeriodType.minutes());
		return new Long(p.getMinutes());
	}

	public static void main(String[] args) {
//		System.out.println(roundFloor5Min(null));
//		System.out.println(roundFloor5Min(System.currentTimeMillis()));
		System.out.println(roundFloor5Min(DateUtil.getPlusMinutes(null, -10).getTime()));
//		System.out.println(getPlusDaysStr(null, 1));
//		System.out.println(getPlusHoursStr12("201812051515", -3));
//		System.out.println(getPlusMinutesStr("20181205151500", -3));
//		System.out.println(getDate12("201812051515"));
//		System.out.println(minusMinute("201812051515", "201812041515"));
	}

}


Joda-Time provides a quality replacement for the Java date and time classes.

Joda-Time is the de facto standard date and time library for Java prior to Java SE 8. Users are now asked to migrate to java.time

——http://www.joda.org/joda-time/

JDK在8之前的版本,对日期时间的处理相当麻烦,有些方法设计非常反人类。而Joda-Time使用起来不仅方便,而且可读性强。虽然JDK 8引用了新的时间处理类,而且参与设计的人也正是Joda-Time的作者,但是由于各种原因,很多项目还是使用的JDK7,使用Joda-Time还是一个不错的选择。

Joda-Time体验



对比之前JDK的处理方式,使用了Joda-Time之后,代码整个神清气爽了很多。接下来就用一些简单的例子来对比一下JDk和Joda-Time的的使用。

依赖

只需要引用一个包。

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.9.4</version>
</dependency>

创建日期

JDK的日期是Date:

Date date = new Date();

Joda-Time的日期是DateTime:

DateTime dateTime = new DateTime();

DateTime在创建的时候还可以轻松的指定特定的日期和时间:

DateTime dateTime2 = new DateTime(2016, 10, 01, 8, 00, 00);

日期格式化

JDK使用的是SimpleDateFormat来进行日期的格式化:

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

乍看之下用起来也不麻烦,但是SimpleDateFormat是非线程安全的。也就是说,如果在并发环境下,必须对SimpleDateFormat对象做同步处理,比如用synchronized,比如用ThreadLocal;或者每次都new一个新的SimpleDateFormat对象,缺点显而易见,就是浪费资源。(详见【Java北京】20160914推送文章:关于SimpleDateFormat时间格式化线程安全问题)

而Joda-Time中的DateTime本身就有格式化的方法,对象直接调用即可:

DateTime dateTime = new DateTime();
String dateTimeStr = dateTime.toString("yyyy-MM-dd HH:mm:ss");

当然,如果要用转换器,Joda-Time也提供了DateTimeFormatter:

DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
String dateTimeStr2 = dtf.print(dateTime);

而且DateTimeFormatter是不可变的,所以是线程安全的。

SimpleDateFormat和DateTimeFormatter都可以将字符串转换成日期:

String dateStr = "2016-10-01";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
   Date date = sdf.parse(dateStr);
} catch (ParseException e) {
   e.printStackTrace();
}