一、前言
說到java的時間處理,我們一般用到的有java.util
包裏面的Date
和 Calendar
類裏面的方法。在使用過程中,或多或少也感覺到了其中的不方便。就促使我們一起找一些其他的方法來代替這些。
在本文中,小編就找來了Joda-time 這個時間處理類,來幫助我們解決這些他們所有的問題。
二、對比Date、Calendar 和 Joda-time
Date
在Java 1.0 中,對日期和時間處理只能依賴java.util.Date類。使用不是很方便,下面說一下:
- 易用性比較差
Date類,起始日期是從1900年,月份是從0開始的。當需要new Date的時候,就要從0開始計算。這樣寫代碼,邏輯很容易寫錯。
- 多個Date
初學者,剛接觸java的時候,發現有很多Date。java.util.Date,java.sql.Date。 java.util.Date 同時包含日期和時間,而 java.sql.Date 僅包含日期,java.sql.Time 包含時間。按照英文語義來說,Date 指日期,Time 指時間,而且還有重名類,因此 java.util.Date 命名定義就有問題。
- 格式化
對於格式化的時候,我們經常使用 java.text.DateFormat ,一般寫代碼時,我們習慣用 SimpleDateFormat。
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = dateFormat.format(date);
在上一篇博客中,小編向大家說明了,SimpleDateFormat對日期進行格式化,在併發的情況下,會出現錯誤。所以這種操作不是很優雅。
- 可變
Date是可變的
Calendar
java1.1 的時候有了Calender這個類,是爲了替換Date類的。其中也有一些問題。
-
起始日期
月份依舊是從0開始計算(不過,至少Calendar 類拿掉了由1900年開始計算年份這一設計)。 -
可變
Calendar類也是可變的,使用起來不安全。
三、使用Joda-time對比
附上幾個例子:
1、創建任意時間對象
//jdk
Calendar calendar = Calendar.getInstance();
calendar.set(2012, Calendar.NOVEMBER, 15, 18, 23, 55);
//Joda-time
DateTime dateTime = new DateTime(2012, 12, 15, 18, 23, 55);
2、計算兩日期相差的天數
//jdk
Calendar start = Calendar.getInstance();
start.set(2012, Calendar.NOVEMBER, 14);
Calendar end = Calendar.getInstance();
end.set(2012, Calendar.NOVEMBER, 15);
long startTim = start.getTimeInMillis();
long endTim = end.getTimeInMillis();
long diff = endTim - startTim;
int days = (int) (diff / 1000 / 3600 / 24);
//joda-time
LocalDate start = new LocalDate(2012, 12, 14);
LocalDate end = new LocalDate(2012, 12, 15);
int days = Days.daysBetween(start, end).getDays();
3、獲取18天之後的某天在下個月的當前周的第一天日期
//jdk
Calendar current = Calendar.getInstance();
current.add(Calendar.DAY_OF_MONTH, 18);
current.add(Calendar.MONTH, 1);
......
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = current.getTime();
String dateStr = dateFormat.format(date);
System.out.println(dateStr);
//joda-time
String dateStr = new DateTime().plusDays(18).plusMonths(1)
.dayOfWeek().withMinimumValue().toString("yyyy-MM-dd HH:mm:ss");
System.out.println(dateStr);
4、時間格式化
DateTimeFormatter format = DateTimeFormat .forPattern("yyyy-MM-dd HH:mm:ss");
//時間解析
DateTime dateTime = DateTime.parse("2012-12-21 23:22:45", format);
//時間格式化,輸出==> 2012/12/21 23:22:45 Fri
String string_u = dateTime.toString("yyyy/MM/dd HH:mm:ss EE");
System.out.println(string_u);
//格式化帶Locale,輸出==> 2012年12月21日 23:22:45 星期五
String string_c = dateTime.toString("yyyy年MM月dd日 HH:mm:ss EE", Locale.CHINESE);
System.out.println(string_c);
5、與JDK互操作
//通過jdk時間對象構造
Date date = new Date();
DateTime dateTime = new DateTime(date);
Calendar calendar = Calendar.getInstance();
dateTime = new DateTime(calendar);
// Joda-time 各種操作.....
dateTime = dateTime.plusDays(1) // 增加天
.plusYears(1)// 增加年
.plusMonths(1)// 增加月
.plusWeeks(1)// 增加星期
.minusMillis(1)// 減分鐘
.minusHours(1)// 減小時
.minusSeconds(1);// 減秒數
// 計算完轉換成jdk 對象
Date date2 = dateTime.toDate();
Calendar calendar2 = dateTime.toCalendar(Locale.CHINA);
四、提供一個封裝的時間處理類
package com.fddsh.demo.time;/**
* Created by William on 2019/4/9.
*/
import com.xiaoleilu.hutool.StrUtil;
import org.joda.time.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class JodaTimeUtil {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String SLASH_DATE_FORMAT = "yyyy/MM/dd";
public static final String NOT_SLASH_DATE_FORMAT = "yyyyMMdd";
public static final String CN_DATE_FORMAT = "yyyy'年'MM'月'dd'日'";
public static final String MONTH_DAY_YEAR_FORMAT = "M/d/yyyy";
public static final String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String SLASH_DATETIME_FORMAT = "yyyy/MM/dd HH:mm:ss";
public static final String NOT_SLASH_DATETIME_FORMAT = "yyyyMMdd HH:mm:ss";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
private static final ThreadLocal<SimpleDateFormat> DEFAULT_DATE_FORMATTER = new ThreadLocal<SimpleDateFormat>() {
@Override
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};
private static final ThreadLocal<SimpleDateFormat> SLASH_DATE_FORMATTER = new ThreadLocal<SimpleDateFormat>() {
@Override
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy/MM/dd");
}
};
private static final ThreadLocal<SimpleDateFormat> NOT_SLASH_DATE_FORMATTER = new ThreadLocal<SimpleDateFormat>() {
@Override
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd");
}
};
private static final ThreadLocal<SimpleDateFormat> CN_DATE_FORMATTER = new ThreadLocal<SimpleDateFormat>() {
@Override
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy'年'MM'月'dd'日'");
}
};
private static final ThreadLocal<SimpleDateFormat> MONTH_DAY_YEAR_FORMATTER = new ThreadLocal<SimpleDateFormat>() {
@Override
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat("M/d/yyyy");
}
};
private static final ThreadLocal<SimpleDateFormat> DEFAULT_DATETIME_FORMATTER = new ThreadLocal<SimpleDateFormat>() {
@Override
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
private static final ThreadLocal<SimpleDateFormat> SLASH_DATETIME_FORMATTER = new ThreadLocal<SimpleDateFormat>() {
@Override
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
}
};
private static final ThreadLocal<SimpleDateFormat> NOT_SLASH_DATETIME_FORMATTER = new ThreadLocal<SimpleDateFormat>() {
@Override
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd HH:mm:ss");
}
};
private static final ThreadLocal<SimpleDateFormat> DEFAULT_TIME_FORMATTER = new ThreadLocal<SimpleDateFormat>() {
@Override
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat("HH:mm:ss");
}
};
public static final Date getCurrentDate() {
return (new DateTime()).toDate();
}
public static final String getCurrentDefaultDateString() {
return (new DateTime()).toString("yyyy-MM-dd");
}
public static final String getCurrentNotSlashDateString() {
return (new DateTime()).toString("yyyyMMdd");
}
public static final String getCurrentDateTimeString() {
return (new DateTime()).toString("yyyy-MM-dd HH:mm:ss");
}
public static final String getCurrentTimeString() {
return (new DateTime()).toString("HH:mm:ss");
}
public static final Calendar getCurrentCalendar() {
return Calendar.getInstance();
}
public static final Calendar getCalendar(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar;
}
public static final Calendar getCalendar(String date) throws ParseException {
Calendar calendar = Calendar.getInstance();
calendar.setTime(parseDate(date));
return calendar;
}
public static final Calendar getCalendar(String date, String pattern) throws ParseException {
Calendar calendar = Calendar.getInstance();
calendar.setTime(parseDate(date, pattern));
return calendar;
}
public static final Date makeDate(int year, int month, int day) {
return (new LocalDate(year, month, day)).toDate();
}
public static final Date makeDateTime(int year, int month, int day, int hour, int minute, int second) {
return (new DateTime(year, month, day, hour, minute, second, 0)).toDate();
}
public static final Date parseDate(String date) {
DateFormat[] formatters = new DateFormat[]{(DateFormat) DEFAULT_DATETIME_FORMATTER.get(), (DateFormat) SLASH_DATETIME_FORMATTER.get(), (DateFormat) NOT_SLASH_DATETIME_FORMATTER.get(), (DateFormat) DEFAULT_TIME_FORMATTER.get(), (DateFormat) DEFAULT_DATE_FORMATTER.get(), (DateFormat) SLASH_DATE_FORMATTER.get(), (DateFormat) NOT_SLASH_DATE_FORMATTER.get(), (DateFormat) CN_DATE_FORMATTER.get(), (DateFormat) MONTH_DAY_YEAR_FORMATTER.get()};
DateFormat[] var2 = formatters;
int var3 = formatters.length;
int var4 = 0;
while (var4 < var3) {
DateFormat formatter = var2[var4];
try {
return formatter.parse(date);
} catch (ParseException var7) {
++var4;
}
}
return null;
}
// public static final <T extends Date> T parseDate(String date, Class<T> clz) throws ParseException, InstantiationException, IllegalAccessException {
// T t = (Date) clz.newInstance();
// t.setTime(parseDate(date).getTime());
// return t;
// }
public static final Date parseDate(String date, String pattern) throws ParseException {
DateFormat dateFormat = new SimpleDateFormat(pattern);
return dateFormat.parse(date);
}
public static final String formatDate(Date date) {
return (new DateTime(date)).toString("yyyy-MM-dd");
}
public static final String formatDateTime(Date date) {
return (new DateTime(date)).toString("yyyy-MM-dd HH:mm:ss");
}
public static final String formatTime(Date date) {
return (new DateTime(date)).toString("HH:mm:ss");
}
public static final String formatDate(Date date, String pattern) {
return (new DateTime(date)).toString(pattern);
}
public static final int getYearsBetween(Date a, Date b) {
return Years.yearsBetween(toJodaDateTime(a), toJodaDateTime(b)).getYears();
}
public static final int getYearsBetween(String a, String b) throws ParseException {
return Years.yearsBetween(toJodaDateTime(a), toJodaDateTime(b)).getYears();
}
public static final int getMonthsBetween(Date a, Date b) {
return Months.monthsBetween(toJodaDateTime(a), toJodaDateTime(b)).getMonths();
}
public static final int getMonthsBetween(String a, String b) throws ParseException {
return Months.monthsBetween(toJodaDateTime(a), toJodaDateTime(b)).getMonths();
}
public static final int getDaysBetween(Date a, Date b) {
return Days.daysBetween(toJodaDateTime(a), toJodaDateTime(b)).getDays();
}
public static final int getDaysBetween(String a, String b) throws ParseException {
return Days.daysBetween(toJodaDateTime(a), toJodaDateTime(b)).getDays();
}
public static final int getHoursBetween(Date a, Date b) {
return Hours.hoursBetween(toJodaDateTime(a), toJodaDateTime(b)).getHours();
}
public static final int getHoursBetween(String a, String b) throws ParseException {
return Hours.hoursBetween(toJodaDateTime(a), toJodaDateTime(b)).getHours();
}
public static final int getMinutesBetween(Date a, Date b) {
return Minutes.minutesBetween(toJodaDateTime(a), toJodaDateTime(b)).getMinutes();
}
public static final int getMinutesBetween(String a, String b) throws ParseException {
return Minutes.minutesBetween(toJodaDateTime(a), toJodaDateTime(b)).getMinutes();
}
public static final int getSecondsBetween(Date a, Date b) {
return Seconds.secondsBetween(toJodaDateTime(a), toJodaDateTime(b)).getSeconds();
}
public static final int getSecondsBetween(String a, String b) throws ParseException {
return Seconds.secondsBetween(toJodaDateTime(a), toJodaDateTime(b)).getSeconds();
}
public static final DateTime toJodaDateTime(Date date) {
return new DateTime(date);
}
public static final DateTime toJodaDateTime(String date) throws ParseException {
return toJodaDateTime(parseDate(date));
}
public static final Date plusYears(Date date, int years) {
return toJodaDateTime(date).plusYears(years).toDate();
}
public static final Date plusYears(String date, int years) throws ParseException {
return toJodaDateTime(date).plusYears(years).toDate();
}
public static final Date plusMonths(Date date, int months) {
return toJodaDateTime(date).plusMonths(months).toDate();
}
public static final Date plusMonths(String date, int months) throws ParseException {
return toJodaDateTime(date).plusMonths(months).toDate();
}
public static final Date plusDays(Date date, int days) {
return toJodaDateTime(date).plusDays(days).toDate();
}
public static final Date plusDays(String date, int days) throws ParseException {
return toJodaDateTime(date).plusDays(days).toDate();
}
public static final Date plusHours(Date date, int hours) {
return toJodaDateTime(date).plusHours(hours).toDate();
}
public static final Date plusHours(String date, int hours) throws ParseException {
return toJodaDateTime(date).plusHours(hours).toDate();
}
public static final Date plusMinutes(Date date, int minutes) {
return toJodaDateTime(date).plusMinutes(minutes).toDate();
}
public static final Date plusMinutes(String date, int minutes) throws ParseException {
return toJodaDateTime(date).plusMinutes(minutes).toDate();
}
public static final Date plusSeconds(Date date, int seconds) {
return toJodaDateTime(date).plusSeconds(seconds).toDate();
}
public static final Date plusSeconds(String date, int seconds) throws ParseException {
return toJodaDateTime(date).plusSeconds(seconds).toDate();
}
public static final boolean isBetween(Date a, Date b, Date date) {
if (a != null && b != null && date != null) {
Interval interval = new Interval(toJodaDateTime(a), toJodaDateTime(b));
return interval.contains(date.getTime()) || date.equals(b);
} else {
return false;
}
}
public static final boolean isBetween(String a, String b, String date) throws ParseException {
if (a != null && b != null && date != null) {
Interval interval = new Interval(toJodaDateTime(a), toJodaDateTime(b));
return interval.contains(toJodaDateTime(date)) || date.equals(b);
} else {
return false;
}
}
public static final long getMillisBetween(Date a, Date b) {
return (new Duration(toJodaDateTime(a), toJodaDateTime(b))).getMillis();
}
public static final long getMillisBetween(String a, String b) throws ParseException {
return (new Duration(toJodaDateTime(a), toJodaDateTime(b))).getMillis();
}
public static final Date getLater(Date a, Date b) {
return a.equals(b) ? null : (a.after(b) ? a : b);
}
public static final Date getEarlier(Date a, Date b) {
return a.equals(b) ? null : (a.before(b) ? a : b);
}
public static final Date getFirstDayOfMonth(Date date) {
return toJodaDateTime(date).dayOfMonth().withMinimumValue().toDate();
}
public static final Date getLastDayOfMonth(Date date) {
return toJodaDateTime(date).dayOfMonth().withMaximumValue().toDate();
}
public static final int getYear(Date date) {
return toJodaDateTime(date).getYear();
}
public static final int getYear(String date) throws ParseException {
return toJodaDateTime(date).getYear();
}
public static final int getMonth(Date date) {
return toJodaDateTime(date).getMonthOfYear();
}
public static final int getMonth(String date) throws ParseException {
return toJodaDateTime(date).getMonthOfYear();
}
public static final int getDayOfWeek(Date date) {
return toJodaDateTime(date).getDayOfWeek();
}
public static final int getDayOfWeek(String date) throws ParseException {
return toJodaDateTime(date).getDayOfWeek();
}
public static final int getDay(Date date) {
return toJodaDateTime(date).getDayOfMonth();
}
public static final int getDay(String date) throws ParseException {
return toJodaDateTime(date).getDayOfMonth();
}
public static final int getHour(Date date) {
return toJodaDateTime(date).getHourOfDay();
}
public static final int getHour(String date) throws ParseException {
return toJodaDateTime(date).getHourOfDay();
}
public static final int getMinute(Date date) {
return toJodaDateTime(date).getMinuteOfHour();
}
public static final int getMinute(String date) throws ParseException {
return toJodaDateTime(date).getMinuteOfHour();
}
public static final int getSecond(Date date) {
return toJodaDateTime(date).getSecondOfMinute();
}
public static final int getSecond(String date) throws ParseException {
return toJodaDateTime(date).getSecondOfMinute();
}
public static int age(Date birthDay, Date dateToCompare) {
Calendar cal = Calendar.getInstance();
cal.setTime(dateToCompare);
if (cal.before(birthDay)) {
throw new IllegalArgumentException(StrUtil.format("Birthday is after date {}!", new Object[]{formatDate(dateToCompare)}));
} else {
int year = cal.get(1);
int month = cal.get(2);
int dayOfMonth = cal.get(5);
cal.setTime(birthDay);
int age = year - cal.get(1);
int monthBirth = cal.get(2);
if (month == monthBirth) {
int dayOfMonthBirth = cal.get(5);
if (dayOfMonth < dayOfMonthBirth) {
--age;
}
} else if (month < monthBirth) {
--age;
}
return age;
}
}
public static List<String> getWeekly(int intervals) {
List<String> pastDaysList = new ArrayList();
for (int i = 1; i < intervals; ++i) {
pastDaysList.add(getPastDate(i));
}
return pastDaysList;
}
public static String getPastDate(int past) {
Calendar calendar = Calendar.getInstance();
calendar.set(6, calendar.get(6) - past);
Date today = calendar.getTime();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String result = format.format(today);
return result;
}
public static int getWeeksfrom1970() {
int days = getDaysBetween(parseDate("1970-01-01 00:00:00"), new Date());
days += 3;
return days / 7;
}
public static void main(String[] args) throws ParseException, InstantiationException, IllegalAccessException {
System.out.println(getDayOfWeek(new Date()));
}
static {
((SimpleDateFormat)DEFAULT_DATE_FORMATTER.get()).setLenient(false);
((SimpleDateFormat)SLASH_DATE_FORMATTER.get()).setLenient(false);
((SimpleDateFormat)NOT_SLASH_DATE_FORMATTER.get()).setLenient(false);
((SimpleDateFormat)CN_DATE_FORMATTER.get()).setLenient(false);
((SimpleDateFormat)MONTH_DAY_YEAR_FORMATTER.get()).setLenient(false);
((SimpleDateFormat)DEFAULT_DATETIME_FORMATTER.get()).setLenient(false);
((SimpleDateFormat)SLASH_DATETIME_FORMATTER.get()).setLenient(false);
((SimpleDateFormat)NOT_SLASH_DATETIME_FORMATTER.get()).setLenient(false);
((SimpleDateFormat)DEFAULT_TIME_FORMATTER.get()).setLenient(false);
}
}
五、小結
通過這次使用,要結合Java 8 來對比,java8中的java.time中的時間類,很多是借鑑了這裏的。所以我們還是要了解一下。