joda-time 時間處理工具

一、前言

      說到java的時間處理,我們一般用到的有java.util包裏面的DateCalendar 類裏面的方法。在使用過程中,或多或少也感覺到了其中的不方便。就促使我們一起找一些其他的方法來代替這些。

      在本文中,小編就找來了Joda-time 這個時間處理類,來幫助我們解決這些他們所有的問題。

二、對比Date、Calendar 和 Joda-time

Date

      在Java 1.0 中,對日期和時間處理只能依賴java.util.Date類。使用不是很方便,下面說一下:

  1. 易用性比較差

      Date類,起始日期是從1900年,月份是從0開始的。當需要new Date的時候,就要從0開始計算。這樣寫代碼,邏輯很容易寫錯。

  1. 多個Date

      初學者,剛接觸java的時候,發現有很多Date。java.util.Date,java.sql.Date。 java.util.Date 同時包含日期和時間,而 java.sql.Date 僅包含日期,java.sql.Time 包含時間。按照英文語義來說,Date 指日期,Time 指時間,而且還有重名類,因此 java.util.Date 命名定義就有問題。

  1. 格式化
          對於格式化的時候,我們經常使用 java.text.DateFormat ,一般寫代碼時,我們習慣用 SimpleDateFormat。
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = dateFormat.format(date);

      在上一篇博客中,小編向大家說明了,SimpleDateFormat對日期進行格式化,在併發的情況下,會出現錯誤。所以這種操作不是很優雅。

      SimpleDateFormat併發問題及優化

  1. 可變

      Date是可變的

在這裏插入圖片描述

Calendar

      java1.1 的時候有了Calender這個類,是爲了替換Date類的。其中也有一些問題。

  1. 起始日期
           月份依舊是從0開始計算(不過,至少Calendar 類拿掉了由1900年開始計算年份這一設計)。

  2. 可變
          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中的時間類,很多是借鑑了這裏的。所以我們還是要了解一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章