Java日期时间API系列26—–Jdk8中java.time包中的新的日期时间API类,YearMonth类的源码,转换和应用。

Java8中为年月新增了类YearMonth,可以用来表示卡片过期时间等问题。

1.YearMonth

默认格式为:2007-12

1.1 部分源码

*
 * @implSpec
 * This class is immutable and thread-safe.
 *
 * @since 1.8
 */
public final class YearMonth
        implements Temporal, TemporalAdjuster, Comparable, Serializable {

    /**
     * Serialization version.
     */
    private static final long serialVersionUID = 4183400860270640070L;
    /**
     * Parser.
     */
    private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
        .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
        .appendLiteral('-')
        .appendValue(MONTH_OF_YEAR, 2)
        .toFormatter();

    /**
     * The year.
     */
    private final int year;
    /**
     * The month-of-year, not null.
     */
    private final int month;

通过源码可以看出使用final修饰YearMonth,YearMonth是线程安全类,同时实现了Temporal, TemporalAdjuster, Comparable, Serializable接口,有属性读取,设置和加减等功能。

 

 

 1.2 创建和基本使用

        YearMonth yearMonth = YearMonth.now();
        YearMonth yearMonth2 = YearMonth.of(2020, 4);
        
        System.out.println(yearMonth);
        System.out.println(yearMonth2);
        YearMonth yearMonth3 = YearMonth.parse("2020-05");
        System.out.println(yearMonth3);
        
        YearMonth yearMonth4 = yearMonth3.plusMonths(1);
        System.out.println(yearMonth4);

输出:

2020-03
2020-04
2020-05
2020-06

 

2.应用

2.1 转换

如Date转YearMonth,YearMonth转Date等
    /**
     * Date转YearMonth
     * @param date
     * @return
     */
    public static YearMonth toYearMonth(Date date){
        LocalDate localDate = toLocalDate(date);
        return YearMonth.of(localDate.getYear(), localDate.getMonthValue());
    }
    
    /**
     * LocalDateTime转YearMonth
     * @param localDateTime
     * @return
     */
    public static YearMonth toYearMonth(LocalDateTime localDateTime){
        LocalDate localDate = toLocalDate(localDateTime);
        return YearMonth.of(localDate.getYear(), localDate.getMonthValue());
    }
    
    /**
     * LocalDate转YearMonth
     * @param localDate
     * @return
     */
    public static YearMonth toYearMonth(LocalDate localDate){
        Objects.requireNonNull(localDate, "localDate");
        return YearMonth.of(localDate.getYear(), localDate.getMonthValue());
    }
    
    /**
     * Instant转YearMonth
     * @param instant
     * @return
     */
    public static YearMonth toYearMonth(Instant instant){
        LocalDate localDate = toLocalDate(instant);
        return YearMonth.of(localDate.getYear(), localDate.getMonthValue());
    }
    
    /**
     * ZonedDateTime转YearMonth
     * @param zonedDateTime
     * @return
     */
    public static YearMonth toYearMonth(ZonedDateTime zonedDateTime){
        LocalDate localDate = toLocalDate(zonedDateTime);
        return YearMonth.of(localDate.getYear(), localDate.getMonthValue());
    }

    /**
     * YearMonth转Date
     * 注意dayOfMonth范围:1到31之间,最大值根据月份确定特殊情况,如2月闰年29,非闰年28
     * 如果要转换为当月最后一天,可以使用下面方法:toDateEndOfMonth(YearMonth)
     * @param yearMonth
     * @param dayOfMonth
     * @return
     */
    public static Date toDate(YearMonth yearMonth, int dayOfMonth) {
        Objects.requireNonNull(yearMonth, "yearMonth");
        return toDate(yearMonth.atDay(dayOfMonth));
    }
    
    /**
     * YearMonth转Date,转换为当月第一天
     * @param yearMonth
     * @return
     */
    public static Date toDateStartOfMonth(YearMonth yearMonth) {
        return toDate(yearMonth, 1);
    }
    
    /**
     * YearMonth转Date,转换为当月最后一天
     * @param yearMonth
     * @return
     */
    public static Date toDateEndOfMonth(YearMonth yearMonth) {
        Objects.requireNonNull(yearMonth, "yearMonth");
        return toDate(yearMonth.atEndOfMonth());
    }

    /**
     * YearMonth转LocalDate
     * 注意dayOfMonth范围:1到31之间,最大值根据月份确定特殊情况,如2月闰年29,非闰年28
     * 如果要转换为当月最后一天,可以使用下面方法:toLocalDateEndOfMonth(YearMonth)
     * @param yearMonth
     * @param dayOfMonth
     * @return
     */
    public static LocalDate toLocalDate(YearMonth yearMonth, int dayOfMonth) {
        Objects.requireNonNull(yearMonth, "yearMonth");
        return yearMonth.atDay(dayOfMonth);
    }
    
    /**
     * YearMonth转LocalDate,转换为当月第一天
     * @param yearMonth
     * @return
     */
    public static LocalDate toLocalDateStartOfMonth(YearMonth yearMonth) {
        return toLocalDate(yearMonth, 1);
    }
    
    /**
     * YearMonth转LocalDate,转换为当月最后一天
     * @param yearMonth
     * @return
     */
    public static LocalDate toLocalDateEndOfMonth(YearMonth yearMonth) {
        Objects.requireNonNull(yearMonth, "yearMonth");
        return yearMonth.atEndOfMonth();
    }

 

测试代码:

    @Test
    public void yearMonthConverterTest(){
        System.out.println("===================yearMonthConverterTest=====================");
        Date date = new Date();
        System.out.println(date);
        YearMonth yearMonth = DateTimeConverterUtil.toYearMonth(date);
        System.out.println(yearMonth);
        
        Date date1 = DateTimeConverterUtil.toDate(yearMonth, 15);
        //转换为当月第一天
        Date date2 = DateTimeConverterUtil.toDateStartOfMonth(yearMonth);
        //转换为当月最后一天
        Date date3 = DateTimeConverterUtil.toDateEndOfMonth(yearMonth);
        System.out.println(date1);
        System.out.println(date2);
        System.out.println(date3);
        
        LocalDate LocalDate1 = DateTimeConverterUtil.toLocalDate(yearMonth, 15);
        //转换为当月第一天
        LocalDate LocalDate2 = DateTimeConverterUtil.toLocalDateStartOfMonth(yearMonth);
        //转换为当月最后一天
        LocalDate LocalDate3 = DateTimeConverterUtil.toLocalDateEndOfMonth(yearMonth);
        System.out.println(LocalDate1);
        System.out.println(LocalDate2);
        System.out.println(LocalDate3);
    }

 

输出:

===================yearMonthConverterTest=====================
Fri Mar 20 23:41:41 CST 2020
2020-03
Sun Mar 15 00:00:00 CST 2020
Sun Mar 01 00:00:00 CST 2020
Tue Mar 31 00:00:00 CST 2020
2020-03-15
2020-03-01
2020-03-31

 

2.2 计算

获取起始日期中间的日期列表,获取指定月份的日期列表,判断是否过期等等

    /**
     * 获取指定区间的时间列表,包含起始
     * @param startInclusive
     * @param endInclusive
     * @return
     */
    public static List getLocalDateTimeList(LocalDateTime startInclusive, LocalDateTime endInclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endInclusive, "endInclusive");
        if(startInclusive.isAfter(endInclusive)){
            throw new DateTimeException("startInclusive must before or equal endInclusive!");
        }
        List localDateTimeList = new ArrayList();
        long days = betweenTotalDays(startInclusive, endInclusive)+1;
        for(long i=0; i){
            localDateTimeList.add(startInclusive.plusDays(i));
        }
        return localDateTimeList;
    }
    
    /**
     * 获取指定区间的时间列表,包含起始
     * @param startInclusive
     * @param endInclusive
     * @return
     */
    public static List getLocalDateList(LocalDate startInclusive, LocalDate endInclusive){
        return getLocalDateTimeList(DateTimeConverterUtil.toLocalDateTime(startInclusive),
                DateTimeConverterUtil.toLocalDateTime(endInclusive)).stream()
                        .map(localDateTime -> localDateTime.toLocalDate()).collect(Collectors.toList());
    }
    
    /**
     * 获取指定区间的时间列表,包含起始
     * @param startInclusive
     * @param endInclusive
     * @return
     */
    public static List getDateList(Date startInclusive, Date endInclusive){
        return getLocalDateTimeList(DateTimeConverterUtil.toLocalDateTime(startInclusive),
                DateTimeConverterUtil.toLocalDateTime(endInclusive)).stream()
                        .map(localDateTime -> DateTimeConverterUtil.toDate(localDateTime)).collect(Collectors.toList());
    }
    
    /**
     *  获取指定年月的所有日期列表
     * @param YearMonth
     * @return
     */
    public static List getLocalDateList(YearMonth yearMonth){
        Objects.requireNonNull(yearMonth, "yearMonth");
        List localDateList = new ArrayList();
        long days = yearMonth.lengthOfMonth();
        LocalDate localDate = DateTimeConverterUtil.toLocalDateStartOfMonth(yearMonth);
        for(long i=0; i){
            localDateList.add(plusDays(localDate, i));
        }
        return localDateList;
    }
    
    /**
     *  获取指定年月的所有日期列表
     * @param yearMonthStr yyyy-MM
     * @return
     */
    public static List getLocalDateList(String yearMonthStr){
        Objects.requireNonNull(yearMonthStr, "yearMonthStr");
        YearMonth yearMonth = YearMonth.parse(yearMonthStr);
        return getLocalDateList(yearMonth);
    }
    
    /**
     *  获取指定年月的所有日期列表
     * @param yearMonth
     * @return
     */
    public static List getLocalDateTimeList(YearMonth yearMonth){
        return getLocalDateList(yearMonth).stream()
                .map(localDate -> DateTimeConverterUtil.toLocalDateTime(localDate)).collect(Collectors.toList());
    }    
    
    /**
     *  获取指定年月的所有日期列表
     * @param yearMonthStr yyyy-MM
     * @return
     */
    public static List getLocalDateTimeList(String yearMonthStr){
        return getLocalDateList(yearMonthStr).stream()
                .map(localDate -> DateTimeConverterUtil.toLocalDateTime(localDate)).collect(Collectors.toList());
    }
    
    /**
     * 获取指定年月的所有日期列表
     * @param yearMonthStr yyyy-MM
     * @return
     */
    public static List getDateList(String yearMonthStr){
        return getLocalDateList(yearMonthStr).stream().map(localDate -> DateTimeConverterUtil.toDate(localDate))
                .collect(Collectors.toList());
    }
    
    /**
     * 判断是否过期,(输入年月小于当前年月)
     * @param yearMonth
     * @return
     */
    public static boolean isExpiry(YearMonth yearMonth){
        Objects.requireNonNull(yearMonth, "yearMonth");
        if(yearMonth.isBefore(YearMonth.now())){
            return true;
        }
        return false;
    }
    
    /**
     * 判断是否过期,(输入年月小于当前年月)
     * @param yearMonthStr yyyy-MM
     * @return
     */
    public static boolean isExpiry(String yearMonthStr){
        Objects.requireNonNull(yearMonthStr, "yearMonthStr");
        YearMonth yearMonth = YearMonth.parse(yearMonthStr);
        return isExpiry(yearMonth);
    }

 

测试代码:

    /**
     * yearMonth测试
     */
    @Test
    public void yearMonthTest(){
        //是否过期
        System.out.println(DateTimeCalculatorUtil.isExpiry("2020-03"));
        
        //获取指定年月的所有日期列表
        List dateList = DateTimeCalculatorUtil.getDateList("2020-03");
        dateList.stream().forEach(date->{
            System.out.println(DateTimeFormatterUtil.formatToDateStr(date));
        });
        
        System.out.println("========================");

        //获取指定区间的时间列表,包含起始
        List dateList2 = DateTimeCalculatorUtil.getDateList(dateList.get(0), dateList.get(dateList.size()-1));
        dateList2.stream().forEach(date->{
            System.out.println(DateTimeFormatterUtil.formatToDateStr(date));
        });
        
    }

 

输出:

false
2020-03-01
2020-03-02
2020-03-03
2020-03-04
2020-03-05
2020-03-06
2020-03-07
2020-03-08
2020-03-09
2020-03-10
2020-03-11
2020-03-12
2020-03-13
2020-03-14
2020-03-15
2020-03-16
2020-03-17
2020-03-18
2020-03-19
2020-03-20
2020-03-21
2020-03-22
2020-03-23
2020-03-24
2020-03-25
2020-03-26
2020-03-27
2020-03-28
2020-03-29
2020-03-30
2020-03-31
========================
2020-03-01
2020-03-02
2020-03-03
2020-03-04
2020-03-05
2020-03-06
2020-03-07
2020-03-08
2020-03-09
2020-03-10
2020-03-11
2020-03-12
2020-03-13
2020-03-14
2020-03-15
2020-03-16
2020-03-17
2020-03-18
2020-03-19
2020-03-20
2020-03-21
2020-03-22
2020-03-23
2020-03-24
2020-03-25
2020-03-26
2020-03-27
2020-03-28
2020-03-29
2020-03-30
2020-03-31

 

源代码地址:https://github.com/xkzhangsan/xk-time

 

Java日期时间API系列25—–Jdk8中java.time包中的新的日期时间API类,使用MonthDay计算十二星座。

  通过Java日期时间API系列24—–Jdk8中java.time包中的新的日期时间API类,MonthDay类源码和应用,对比相同月日时间。对MonthDay简单做了说明和应用。十二星座是根据公历生日类计算属于哪个星座(白羊座、金牛座、双子座、巨蟹座、狮子座、处女座、天秤座、天蝎座、射手座、摩羯座、水瓶座、双鱼座)。

1.十二星座名称枚举

package com.xkzhangsan.time.enums;

import static com.xkzhangsan.time.constants.Constant.MONTHDAY_FORMAT_PRE;

import java.time.MonthDay;
import java.util.Objects;

/**
 * 星座名称枚举,包含英文全称,中文全称,时间范围
 * 
 * @ClassName: ConstellationNameEnum
 * @Description: ConstellationNameEnum
 * @author xkzhangsan
 * @date 2020年02-29
 */
public enum ConstellationNameEnum {
    
    Aries(1, "白羊座", "03-21", "04-19"),
    Taurus(2, "金牛座", "04-20", "05-20"),
    Gemini(3, "双子座", "05-21", "06-21"),
    Cancer(4, "巨蟹座", "06-22", "07-22"),
    Leo(5, "狮子座", "07-23", "08-22"),
    Virgo(6, "处女座", "08-23", "09-22"),
    Libra(7, "天秤座", "09-23", "10-23"), 
    Scorpio(8, "天蝎座", "10-24", "11-22"),
    Sagittarius(9, "射手座", "11-23", "12-21"),
    Capricorn(10, "摩羯座", "12-22", "01-19"),
    Aquarius(11, "水瓶座", "01-20", "02-18"),
    Pisces(12, "双鱼座", "02-19", "03-20"),;
    
    /**
     * 序号
     */
    private int code;
    
    /**
     * 中文名称
     */
    private String nameCn;
    
    /**
     * 开始时间
     */
    private String startDate;
    
    /**
     * 结束时间
     */
    private String endDate;

    

    private ConstellationNameEnum(int code, String nameCn, String startDate, String endDate) {
        this.code = code;
        this.nameCn = nameCn;
        this.startDate = startDate;
        this.endDate = endDate;
    }
    
    /**
     * 根据日期查询星座名称枚举
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static ConstellationNameEnum getConstellationNameEnumByMonthDay(String monthDayStr){
        Objects.requireNonNull(monthDayStr, "monthDayStr");
        MonthDay monthDay = MonthDay.parse(MONTHDAY_FORMAT_PRE + monthDayStr);
        for(ConstellationNameEnum constellationNameEnum : ConstellationNameEnum.values()){
            MonthDay monthDayStart = MonthDay.parse(MONTHDAY_FORMAT_PRE + constellationNameEnum.getStartDate());
            MonthDay monthDayEnd = MonthDay.parse(MONTHDAY_FORMAT_PRE + constellationNameEnum.getEndDate());
            if (monthDay.equals(monthDayStart) || monthDay.equals(monthDayEnd)
                    || (monthDay.isAfter(monthDayStart) && monthDay.isBefore(monthDayEnd))) {
                return constellationNameEnum;
            }
        }
        return null;
    }

    /**
     * 根据日期查询星座中文名称
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static String getNameCnByMonthDay(String monthDayStr){
        ConstellationNameEnum constellationNameEnum = getConstellationNameEnumByMonthDay(monthDayStr);
        return constellationNameEnum != null ? constellationNameEnum.getNameCn() : null;
    }
    
    /**
     * 根据日期查询星座英文名称
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static String getNameEnByMonthDay(String monthDayStr){
        ConstellationNameEnum constellationNameEnum = getConstellationNameEnumByMonthDay(monthDayStr);
        return constellationNameEnum != null ? constellationNameEnum.name() : null;
    }
    

    public int getCode() {
        return code;
    }

    public String getNameCn() {
        return nameCn;
    }

    public String getStartDate() {
        return startDate;
    }

    public String getEndDate() {
        return endDate;
    }

}

主要的方法为:public static ConstellationNameEnum getConstellationNameEnumByMonthDay(String monthDayStr),通过对输入的月日字符串和枚举中的起始时间对比得出星座。

星座名称和时间范围来自百度百科

2. 应用

    /**
     * 根据日期查询星座中文名称
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static String getConstellationNameCn(String monthDayStr){
        return ConstellationNameEnum.getNameCnByMonthDay(monthDayStr);
    }
    
    /**
     * 根据日期查询星座中文名称
     * @param date
     * @return
     */
    public static String getConstellationNameCn(Date date){
        String monthDayStr = DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.MM_DD_FMT);
        return ConstellationNameEnum.getNameCnByMonthDay(monthDayStr);
    }
    
    /**
     * 根据日期查询星座英文名称
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static String getConstellationNameEn(String monthDayStr){
        return ConstellationNameEnum.getNameEnByMonthDay(monthDayStr);
    }    

 

测试代码:

    /**
     * 星座计算测试
     */
    @Test
    public void constellationTest(){
        System.out.println(DateTimeCalculatorUtil.getConstellationNameCn("02-29"));
        System.out.println(DateTimeCalculatorUtil.getConstellationNameEn("02-29"));
        
        //2020-05-01 的星座
        System.out.println(DateTimeCalculatorUtil.getConstellationNameCn(DateTimeCalculatorUtil.getDate(2020, 5, 1)));
    }

 

输出:

双鱼座
Pisces
金牛座

 

 

源代码地址:https://github.com/xkzhangsan/xk-time

 

Java日期时间API系列24—–Jdk8中java.time包中的新的日期时间API类,MonthDay类源码和应用,对比相同月日时间。

  Java8中为月日新增了类MonthDay,可以用来处理生日,节日、纪念日和星座等周期性问题。

1.MonthDay

  特别需要注意的:它的默认打印格式会带前缀”–” ,比如–12-03,同样的默认解析格式也需要加前缀。

1.1 部分源码

 

 * @implSpec
 * This class is immutable and thread-safe.
 *
 * @since 1.8
 */
public final class MonthDay
        implements TemporalAccessor, TemporalAdjuster, Comparable, Serializable {

    /**
     * Serialization version.
     */
    private static final long serialVersionUID = -939150713474957432L;
    /**
     * Parser.
     */
    private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
        .appendLiteral("--")
        .appendValue(MONTH_OF_YEAR, 2)
        .appendLiteral('-')
        .appendValue(DAY_OF_MONTH, 2)
        .toFormatter();

    /**
     * The month-of-year, not null.
     */
    private final int month;
    /**
     * The day-of-month.
     */
    private final int day;

通过源码可以看出使用final修饰MonthDay,MonthDay是线程安全类,同时实现了TemporalAccessor, TemporalAdjuster, Comparable, Serializable接口,有属性读取和设置等功能,但由于没有年部分,闰年2月29日的原因,没有加减功能。

 

 

 1.2 创建方式

     MonthDay monthDay1 = MonthDay.now();
        System.out.println(monthDay1);
        
        MonthDay monthDay2 = MonthDay.of(12, 3);
        System.out.println(monthDay2);

输出:

--02-29
--12-03

 

1.3 解析

System.out.println(MonthDay.parse("--12-03"));

 

2. 应用

对比相同月日和推算等

2.1 应用代码

    /**
     * 相同月日比较判断,用于生日,节日等周期性的日期比较判断。
     * @param localDate1
     * @param monthDay
     * @return
     */
    public static boolean isSameMonthDay(LocalDate localDate1, MonthDay monthDay){
        Objects.requireNonNull(localDate1, "localDate1");
        Objects.requireNonNull(monthDay, "monthDay");
        return MonthDay.of(localDate1.getMonthValue(), localDate1.getDayOfMonth()).equals(monthDay);
    }
    
    /**
     * 相同月日比较判断,用于生日,节日等周期性的日期比较判断。
     * @param localDate1
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static boolean isSameMonthDay(LocalDate localDate1, String monthDayStr){
        Objects.requireNonNull(monthDayStr, "monthDayStr");
        return isSameMonthDay(localDate1, MonthDay.parse(MONTHDAY_FORMAT_PRE + monthDayStr));
    }
    
    /**
     * 相同月日比较判断,用于生日,节日等周期性的日期比较判断。
     * @param localDate1
     * @param localDate2
     * @return
     */
    public static boolean isSameMonthDay(LocalDate localDate1, LocalDate localDate2){
        Objects.requireNonNull(localDate2, "localDate2");
        return isSameMonthDay(localDate1, MonthDay.of(localDate2.getMonthValue(), localDate2.getDayOfMonth()));
    }
    
    /**
     * 相同月日比较判断,用于生日,节日等周期性的日期比较判断。
     * @param date
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static boolean isSameMonthDay(Date date, String monthDayStr){
        return isSameMonthDay(DateTimeConverterUtil.toLocalDate(date), monthDayStr);
    }
    
    /**
     * 相同月日比较判断,用于生日,节日等周期性的日期比较判断。
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isSameMonthDay(Date date1, Date date2){
        Objects.requireNonNull(date1, "date1");
        Objects.requireNonNull(date2, "date2");
        return isSameMonthDay(DateTimeConverterUtil.toLocalDate(date1), DateTimeConverterUtil.toLocalDate(date2));
    }
    
    /**
     * 相同月日比较判断,与当前日期对比,用于生日,节日等周期性的日期比较判断
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static boolean isSameMonthDayOfNow(String monthDayStr){
        return isSameMonthDay(LocalDate.now(), monthDayStr);
    }
    
    /**
     * 下个固定月日相差天数,用于生日,节日等周期性的日期推算
     * @param localDate1
     * @param month
     * @param dayOfMonth
     * @return
     */
    public static long betweenNextSameMonthDay(LocalDate localDate1, int month, int dayOfMonth) {
        Objects.requireNonNull(localDate1, "localDate1");
        MonthDay monthDay1 = MonthDay.of(localDate1.getMonthValue(), localDate1.getDayOfMonth());
        MonthDay monthDay2 = MonthDay.of(month, dayOfMonth);
        
        // localDate1 月日 小于 month dayOfMonth
        if (monthDay1.compareTo(monthDay2) == -1) {
            return betweenTotalDays(localDate1.atStartOfDay(),
                    localDate1.withMonth(month).withDayOfMonth(dayOfMonth).atStartOfDay());
        } else {
            // 闰年2月29
            MonthDay leapMonthDay = MonthDay.of(2, 29);
            if (leapMonthDay.equals(monthDay2)) {
                LocalDate nextLeapYear = nextLeapYear(localDate1);
                return betweenTotalDays(localDate1.atStartOfDay(),
                        nextLeapYear.withMonth(month).withDayOfMonth(dayOfMonth).atStartOfDay());
            } else {
                LocalDate next = localDate1.plusYears(1);
                return betweenTotalDays(localDate1.atStartOfDay(),
                        next.withMonth(month).withDayOfMonth(dayOfMonth).atStartOfDay());
            }
        }
    }
    
    /**
     * 下个固定月日相差天数,用于生日,节日等周期性的日期推算
     * @param localDate
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static long betweenNextSameMonthDay(LocalDate localDate, String monthDayStr) {
        Objects.requireNonNull(monthDayStr, "monthDayStr");
        MonthDay monthDay2 = MonthDay.parse(MONTHDAY_FORMAT_PRE + monthDayStr);
        return betweenNextSameMonthDay(localDate, monthDay2.getMonthValue(), monthDay2.getDayOfMonth());
    }
    
    /**
     * 下个固定月日相差天数,用于生日,节日等周期性的日期推算
     * @param date
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static long betweenNextSameMonthDay(Date date, String monthDayStr) {
        Objects.requireNonNull(monthDayStr, "monthDayStr");
        MonthDay monthDay2 = MonthDay.parse(MONTHDAY_FORMAT_PRE + monthDayStr);
        return betweenNextSameMonthDay(DateTimeConverterUtil.toLocalDate(date), monthDay2.getMonthValue(),
                monthDay2.getDayOfMonth());
    }
    
    /**
     * 下个固定月日相差天数,与当前日期对比,用于生日,节日等周期性的日期推算
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static long betweenNextSameMonthDayOfNow(String monthDayStr) {
        Objects.requireNonNull(monthDayStr, "monthDayStr");
        MonthDay monthDay2 = MonthDay.parse(MONTHDAY_FORMAT_PRE + monthDayStr);
        return betweenNextSameMonthDay(LocalDate.now(), monthDay2.getMonthValue(),
                monthDay2.getDayOfMonth());
    }
    
    /**
     * 下个固定月日相差日期,用于生日,节日等周期性的日期推算
     * @param localDate
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static LocalDate nextSameMonthDay(LocalDate localDate, String monthDayStr){
        return localDate.plusDays(betweenNextSameMonthDay(localDate, monthDayStr));
    }
    
    /**
     * 下个固定月日相差日期,用于生日,节日等周期性的日期推算
     * @param date
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static Date nextSameMonthDay(Date date, String monthDayStr){
        return DateTimeConverterUtil.toDate(nextSameMonthDay(DateTimeConverterUtil.toLocalDate(date), monthDayStr));
    }
    
    /**
     * 下个固定月日相差日期,与当前日期对比,用于生日,节日等周期性的日期推算
     * @param monthDayStr MM-dd格式
     * @return
     */
    public static Date nextSameMonthDayOfNow(String monthDayStr){
        return nextSameMonthDay(new Date(), monthDayStr);
    }

 

2.2 测试代码

    /**
     * 相同月日对比
     */
    @Test
    public void sameMonthDayTest(){
        Date date = DateTimeCalculatorUtil.getDate(2020, 2, 29);
        System.out.println(date);
        
        //date的月日部分是否和02-29相等
        System.out.println(DateTimeCalculatorUtil.isSameMonthDay(date, "02-29"));
        //date的月日部分是否和new Date()的月日部分相等
        System.out.println(DateTimeCalculatorUtil.isSameMonthDay(date, new Date()));
        //当前时间月日部分是否和02-29相等
        System.out.println(DateTimeCalculatorUtil.isSameMonthDayOfNow("02-29"));
        
        //date的月日部分和下一个03-05相差天数
        System.out.println(DateTimeCalculatorUtil.betweenNextSameMonthDay(date, "03-05"));
        //当前时间月日部分和下一个03-05相差天数
        System.out.println(DateTimeCalculatorUtil.betweenNextSameMonthDayOfNow("03-05"));
        
        //date为准,下一个02-14的日期
        System.out.println(DateTimeCalculatorUtil.nextSameMonthDay(date, "02-14"));
        //date为准,下一个03-05的日期
        System.out.println(DateTimeCalculatorUtil.nextSameMonthDay(date, "03-05"));
        //date为准,下一个02-29的日期 ,02-29 只有闰年有。
        System.out.println(DateTimeCalculatorUtil.nextSameMonthDay(date, "02-29"));
        //当前时间为准,下一个02-29的日期  ,02-29 只有闰年有。
        System.out.println(DateTimeCalculatorUtil.nextSameMonthDayOfNow("02-29"));
    }

 

2.3 输出

Sat Feb 29 00:00:00 CST 2020
true
true
true
5
5
Sun Feb 14 00:00:00 CST 2021
Thu Mar 05 00:00:00 CST 2020
Thu Feb 29 00:00:00 CST 2024
Thu Feb 29 00:00:00 CST 2024

 

源代码地址:https://github.com/xkzhangsan/xk-time

 

Java日期时间API系列23—–Jdk8中java.time包中的新的日期时间API类,获取准确开始时间00:00:00,获取准确结束时间23:59:59等

  有时候,往往需要统计某个时间区间的销量等问题,这就需要准确的起始时间,获取准确开始时间00:00:00,获取准确结束时间23:59:59。下面增加了一一些方法,获取当天起始时间,昨天起始时间,当前月第一天开始时间,当前月最后一天结束时间,上个月第一天开始时间,上个月最后一天结束时间,某个指定月的起始结束时间等等。其中月份最后一天往往因为月份不同和闰年而不同。

1  下面是方法:

    /**
     * 一天开始时间 00:00:00
     * @return
     */
    public static LocalTime startTimeOfDay(){
        return LocalTime.of(0, 0, 0);
    }
    
    /**
     * 一天开始时间 23:59:59
     * @return
     */
    public static LocalTime endTimeOfDay(){
        return LocalTime.of(23, 59, 59);
    }
    
    /**
     * 昨天起始时间 即:昨天日期+00:00:00
     * @return
     */
    public static Date startTimeOfYesterday(){
        return DateTimeConverterUtil.toDate(LocalDate.now().minusDays(1).atTime(startTimeOfDay()));
    }
    
    /**
     * 昨天结束时间即:昨天日期+23:59:59
     * @return
     */
    public static Date endTimeOfYesterday(){
        return DateTimeConverterUtil.toDate(LocalDate.now().minusDays(1).atTime(endTimeOfDay()));
    }
    
    /**
     * 今天起始时间 即:今天日期+00:00:00
     * @return
     */
    public static Date startTimeOfToday(){
        return DateTimeConverterUtil.toDate(LocalDate.now().atTime(startTimeOfDay()));
    }
    
    /**
     * 今天结束时间即:今天日期+23:59:59
     * @return
     */
    public static Date endTimeOfToday(){
        return DateTimeConverterUtil.toDate(LocalDate.now().atTime(endTimeOfDay()));
    }
    
    /**
     * 上个月第一天起始时间 即:上个月第一天日期+00:00:00
     * @return
     */
    public static Date startTimeOfLastMonth(){
        return DateTimeConverterUtil.toDate(firstDayOfMonth(LocalDate.now().minusMonths(1)).atTime(startTimeOfDay()));
    }
    
    /**
     * 上个月最后一天结束时间 即:上个月最后一天日期+23:59:59
     * @return
     */
    public static Date endTimeOfLastMonth(){
        return DateTimeConverterUtil.toDate(lastDayOfMonth(LocalDate.now().minusMonths(1)).atTime(endTimeOfDay()));
    }
    
    /**
     * 当月第一天起始时间 即:当月第一天日期+00:00:00
     * @return
     */
    public static Date startTimeOfMonth(){
        return DateTimeConverterUtil.toDate(firstDayOfMonth(LocalDate.now()).atTime(startTimeOfDay()));
    }
    
    /**
     * 当月最后一天结束时间即:当月最后一天日期+23:59:59
     * @return
     */
    public static Date endTimeOfMonth(){
        return DateTimeConverterUtil.toDate(lastDayOfMonth(LocalDate.now()).atTime(endTimeOfDay()));
    }
    
    /**
     * 获date起始时间
     * @param date
     * @return
     */
    public static Date startTimeOfDate(Date date){
        return DateTimeConverterUtil.toDate(DateTimeConverterUtil.toLocalDate(date).atTime(startTimeOfDay()));
    }
    
    /**
     * 获取date结束时间
     * @param date
     * @return
     */
    public static Date endTimeOfDate(Date date){
        return DateTimeConverterUtil.toDate(DateTimeConverterUtil.toLocalDate(date).atTime(endTimeOfDay()));
    }

    /**
     * 获取指定年月的第一天起始时间
     * @param year
     * @param month
     * @return
     */
    public static Date startTimeOfSpecialMonth(int year, int month){
        return DateTimeConverterUtil.toDate(LocalDate.of(year, month, 1).atTime(startTimeOfDay()));
    }
    
    /**
     * 获取指定年月的最后一天结束时间
     * @param year
     * @param month
     * @return
     */
    public static Date endTimeOfSpecialMonth(int year, int month){
        return DateTimeConverterUtil.toDate(lastDayOfMonth(LocalDate.of(year, month, 1)).atTime(endTimeOfDay()));
    }

 

2. 测试代码:

    /**
     * 获取准确的起始时间方法测试
     * 比如startTimeOfMonth() 当月起始时间 当月第一天日期+00:00:00
     *       endTimeOfMonth() 当月最后一天日期+23:59:59
     */
    @Test
    public void dateStartTimeAndEndTimeTest(){
        //当天
        System.out.println(DateTimeFormatterUtil.formatToDateTimeStr(DateTimeCalculatorUtil.startTimeOfToday()));
        System.out.println(DateTimeFormatterUtil.formatToDateTimeStr(DateTimeCalculatorUtil.endTimeOfToday()));
        
        //当月
        System.out.println(DateTimeFormatterUtil.formatToDateTimeStr(DateTimeCalculatorUtil.startTimeOfMonth()));
        System.out.println(DateTimeFormatterUtil.formatToDateTimeStr(DateTimeCalculatorUtil.endTimeOfMonth()));
        
        //指定年月
        System.out.println(DateTimeFormatterUtil.formatToDateTimeStr(DateTimeCalculatorUtil.startTimeOfSpecialMonth(2019, 10)));
        System.out.println(DateTimeFormatterUtil.formatToDateTimeStr(DateTimeCalculatorUtil.endTimeOfSpecialMonth(2019, 10)));
    }

 

3. 输出:

2020-02-27 00:00:00
2020-02-27 23:59:59
2020-02-01 00:00:00
2020-02-29 23:59:59
2019-10-01 00:00:00
2019-10-31 23:59:59

 

源代码地址:https://github.com/xkzhangsan/xk-time

Java日期时间API系列22—–Jdk8中java.time包中的新的日期时间API类,Month月份和DayOfWeek星期的计算。

  Java8中为月份和星期新增的了,Month和DayOfWeek,来处理月份和星期的特殊问题,这2个类都是枚举类,对Month、DayOfWeek源码说明和简单应用,月份英文,月份英文简称,月份中文,星期英文,星期英文简称,星期中文等。

1.Month

1.1 部分源码:

 * @implSpec
 * This is an immutable and thread-safe enum.
 *
 * @since 1.8
 */
public enum Month implements TemporalAccessor, TemporalAdjuster {

    /**
     * The singleton instance for the month of January with 31 days.
     * This has the numeric value of {@code 1}.
     */
    JANUARY,
    /**
     * The singleton instance for the month of February with 28 days, or 29 in a leap year.
     * This has the numeric value of {@code 2}.
     */
    FEBRUARY,
    /**
     * The singleton instance for the month of March with 31 days.
     * This has the numeric value of {@code 3}.
     */
    MARCH,
    /**
     * The singleton instance for the month of April with 30 days.
     * This has the numeric value of {@code 4}.
     */
    APRIL,

从中可以看出包含了12个月,因为实现了TemporalAccessor和TemporalAdjuster接口,它既有了属性读取和设置,又有加减等功能如下:

 

 

 

 2.应用

为了方便中文环境应用,加一个月份名称的枚举。

package com.xkzhangsan.time.enums;

/**
 * 月份名称枚举,包含英文全称,英文检查,中文全称
 * 
 * @ClassName: MonthNameEnum
 * @Description: MonthNameEnum
 * @author xkzhangsan
 * @date 2020年02月27日
 */
public enum MonthNameEnum {
    
    Jan(1, "January", "一月", "一"),
    Feb(2, "February", "二月", "二"),
    Mar(3, "March", "三月", "三"),
    Apr(4, "April", "四月", "四"),
    May(5, "May", "五月", "五"),
    Jun(6, "June", "六月", "六"),
    Jul(7, "July", "七月", "七"), 
    Aug(8, "August", "八月", "八"),
    Sep(9, "September", "九月", "九"),
    Oct(10, "October", "十月", "十"),
    Nov(11, "November", "十一月", "十一"),
    Dec(12, "December", "十二月", "十二"),;
    
    /**
     * 序号
     */
    private int code;
    
    /**
     * 英文全称
     */
    private String fullNameEn;
    
    /**
     * 中文全称
     */
    private String fullNameCn;
    
    /**
     * 中文简称
     */
    private String shortNameCn;

    
    private MonthNameEnum(int code, String fullNameEn, String fullNameCn, String shortNameCn) {
        this.code = code;
        this.fullNameEn = fullNameEn;
        this.fullNameCn = fullNameCn;
        this.shortNameCn = shortNameCn;
    }

    /**
     * 根据code查询月份名称枚举
     * @param code
     * @return
     */
    public static MonthNameEnum getByCode(int code){
        if(code >=1 && code <= 12){
            for(MonthNameEnum monthNameEnum : MonthNameEnum.values()){
                if(monthNameEnum.getCode() == code){
                    return monthNameEnum;
                }
            }
        }
        return null;
    }
    
    /**
     * 根据code查询月份英文简称
     * @param code
     * @return
     */
    public static String getShortNameEnByCode(int code){
        MonthNameEnum monthNameEnum = getByCode(code);
        return monthNameEnum != null ? monthNameEnum.name() : null;
    }
    
    /**
     * 根据code查询月份英文全称
     * @param code
     * @return
     */
    public static String getFullNameEnByCode(int code){
        MonthNameEnum monthNameEnum = getByCode(code);
        return monthNameEnum != null ? monthNameEnum.getFullNameEn() : null;
    }
    
    /**
     * 根据code查询月份中文全称
     * @param code
     * @return
     */
    public static String getFullNameCnByCode(int code){
        MonthNameEnum monthNameEnum = getByCode(code);
        return monthNameEnum != null ? monthNameEnum.getFullNameCn() : null;
    }
    
    /**
     * 根据code查询月份中文
     * @param code
     * @return
     */
    public static String getShortNameCnByCode(int code){
        MonthNameEnum monthNameEnum = getByCode(code);
        return monthNameEnum != null ? monthNameEnum.getShortNameCn() : null;
    }

    public int getCode() {
        return code;
    }

    public String getFullNameEn() {
        return fullNameEn;
    }

    public String getFullNameCn() {
        return fullNameCn;
    }

    public String getShortNameCn() {
        return shortNameCn;
    }

}

 

应用代码

    /**
     * 获取月, 比如 1
     * @param date
     * @return
     */
    public static int getMonth(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).getMonthValue();
    }
    
    /**
     * 获取月, 比如 1
     * @param instant
     * @return
     */
    public static int getMonth(Instant instant){
        return DateTimeConverterUtil.toLocalDateTime(instant).getMonthValue();
    }
    
    /**
     * 获取月, 比如 1
     * LocalDateTime LocalDate ZonedDateTime 可以直接getMonthValue()
     * @param localDateTime
     * @return
     */
    public static int getMonth(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.getMonthValue();
    }
    
    
    
    /**
     * 获取月英文全称, 比如 January
     * January, February, March, April, May, June, July, August, September, October,
     * November and December
     * @param date
     * @return
     */
    public static String getMonthEnLong(Date date){
        return MonthNameEnum.getFullNameEnByCode(getMonth(date));
    }
    
    /**
     * 获取月英文全称, 比如 January
     * January, February, March, April, May, June, July, August, September, October,
     * November and December
     * @param instant
     * @return
     */
    public static String getMonthEnLong(Instant instant){
        return MonthNameEnum.getFullNameEnByCode(getMonth(instant));
    }
    
    /**
     * 获取月英文全称, 比如 January
     * January, February, March, April, May, June, July, August, September, October,
     * November and December
     * LocalDateTime LocalDate ZonedDateTime 可以直接.getMonth().toString()
     * @param localDateTime
     * @return
     */
    public static String getMonthEnLong(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return MonthNameEnum.getFullNameEnByCode(getMonth(localDateTime));
    }
    
    /**
     * 获取月英文简称, 比如 Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
     * @param date
     * @return
     */
    public static String getMonthEnShort(Date date){
        return MonthNameEnum.getShortNameEnByCode(getMonth(date));
    }
    
    /**
     * 获取月英文简称, 比如 Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
     * @param instant
     * @return
     */
    public static String getMonthEnShort(Instant instant){
        return MonthNameEnum.getShortNameEnByCode(getMonth(instant));
    }
    
    /**
     * 获取月英文简称, 比如 Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
     * @param localDateTime
     * @return
     */
    public static String getMonthEnShort(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return MonthNameEnum.getShortNameEnByCode(getMonth(localDateTime));
    }
    
    /**
     * 获取月份中文全称, 比如一月
     * @param date
     * @return
     */
    public static String getMonthCnLong(Date date){
        return MonthNameEnum.getFullNameCnByCode(getMonth(date));
    }
    
    /**
     * 获取月份中文全称, 比如一月
     * @param instant
     * @return
     */
    public static String getMonthCnLong(Instant instant){
        return MonthNameEnum.getFullNameCnByCode(getMonth(instant));
    }
    
    /**
     * 获取月份中文全称, 比如一月
     * @param localDateTime
     * @return
     */
    public static String getMonthCnLong(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return MonthNameEnum.getFullNameCnByCode(getMonth(localDateTime));
    }
    
    /**
     * 获取月份中文全称, 比如一
     * @param date
     * @return
     */
    public static String getMonthCnShort(Date date){
        return MonthNameEnum.getShortNameCnByCode(getMonth(date));
    }
    
    /**
     * 获取月份中文全称, 比如一
     * @param instant
     * @return
     */
    public static String getMonthCnShort(Instant instant){
        return MonthNameEnum.getShortNameCnByCode(getMonth(instant));
    }
    
    /**
     * 获取月份中文全称, 比如一
     * @param localDateTime
     * @return
     */
    public static String getMonthCnShort(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return MonthNameEnum.getShortNameCnByCode(getMonth(localDateTime));
    }

测试代码:

    /**
     * 获取月份信息,包括英文全称简称,中文等
     */
    @Test
    public void dateGetMonthTest(){
        Date date = new Date();
        System.out.println(date);
        
        System.out.println(DateTimeCalculatorUtil.getMonth(date));
        System.out.println(DateTimeCalculatorUtil.getMonthEnLong(date));
        System.out.println(DateTimeCalculatorUtil.getMonthEnShort(date));
        System.out.println(DateTimeCalculatorUtil.getMonthCnLong(date));
        System.out.println(DateTimeCalculatorUtil.getMonthCnShort(date));
    }

 

输出结果:

Thu Feb 27 16:01:59 CST 2020
2
February
Feb
二月
二

 

2.DayOfWeek

2.1  部分源码

 * @implSpec
 * This is an immutable and thread-safe enum.
 *
 * @since 1.8
 */
public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {

    /**
     * The singleton instance for the day-of-week of Monday.
     * This has the numeric value of {@code 1}.
     */
    MONDAY,
    /**
     * The singleton instance for the day-of-week of Tuesday.
     * This has the numeric value of {@code 2}.
     */
    TUESDAY,
    /**
     * The singleton instance for the day-of-week of Wednesday.
     * This has the numeric value of {@code 3}.
     */
    WEDNESDAY,
    /**
     * The singleton instance for the day-of-week of Thursday.
     * This has the numeric value of {@code 4}.
     */
    THURSDAY,
    /**
     * The singleton instance for the day-of-week of Friday.
     * This has the numeric value of {@code 5}.
     */
    FRIDAY,
    /**
     * The singleton instance for the day-of-week of Saturday.
     * This has the numeric value of {@code 6}.
     */
    SATURDAY,
    /**
     * The singleton instance for the day-of-week of Sunday.
     * This has the numeric value of {@code 7}.
     */
    SUNDAY;

从中可以看出包含了星期一到星期日,因为实现了TemporalAccessor和TemporalAdjuster接口,它它既有了属性读取和设置,又有加减等功能如下:

 

 

 2.2 应用

为了方便中文环境应用,加一个星期名称的枚举。

package com.xkzhangsan.time.enums;

/**
 * 星期名称枚举,包含英文全称,英文检查,中文
 * Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday
 * @ClassName: WeekNameEnum
 * @Description: WeekNameEnum
 * @author xkzhangsan
 * @date 2020年02月27日
 */
public enum WeekNameEnum {
    
    Mon(1, "Monday", "星期一"),
    Tue(2, "Tuesday", "星期二"),
    Wed(3, "Wednesday", "星期三"),
    Thu(4, "Thursday", "星期四"),
    Fri(5, "Friday", "星期五"),
    Sat(6, "Saturday", "星期六"),
    Sun(7, "Sunday", "星期日"),;
    
    /**
     * 序号
     */
    private int code;
    
    /**
     * 英文全称
     */
    private String fullNameEn;
    
    /**
     * 中文
     */
    private String nameCn;
    

    private WeekNameEnum(int code, String fullNameEn, String nameCn) {
        this.code = code;
        this.fullNameEn = fullNameEn;
        this.nameCn = nameCn;
    }

    /**
     * 根据code查询星期名称枚举
     * @param code
     * @return
     */
    public static WeekNameEnum getByCode(int code){
        if(code >=1 && code <= 12){
            for(WeekNameEnum monthNameEnum : WeekNameEnum.values()){
                if(monthNameEnum.getCode() == code){
                    return monthNameEnum;
                }
            }
        }
        return null;
    }
    
    /**
     * 根据code查询星期英文简称
     * @param code
     * @return
     */
    public static String getShortNameEnByCode(int code){
        WeekNameEnum monthNameEnum = getByCode(code);
        return monthNameEnum != null ? monthNameEnum.name() : null;
    }
    
    /**
     * 根据code查询星期英文全称
     * @param code
     * @return
     */
    public static String getFullNameEnByCode(int code){
        WeekNameEnum monthNameEnum = getByCode(code);
        return monthNameEnum != null ? monthNameEnum.getFullNameEn() : null;
    }
    
    /**
     * 根据code查询星期中文名称
     * @param code
     * @return
     */
    public static String getNameCnByCode(int code){
        WeekNameEnum monthNameEnum = getByCode(code);
        return monthNameEnum != null ? monthNameEnum.getNameCn() : null;
    }

    public int getCode() {
        return code;
    }

    public String getFullNameEn() {
        return fullNameEn;
    }

    public String getNameCn() {
        return nameCn;
    }


}

 

应用代码:

    /**
     * 获取星期值 1-7,星期一到星期日
     * @param date
     * @return
     */
    public static int getDayOfWeek(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).getDayOfWeek().getValue();
    }
    
    /**
     * 获取星期值 1-7,星期一到星期日
     * @param localDateTime
     * @return
     */
    public static int getDayOfWeek(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.getDayOfWeek().getValue();
    }
    
    /**
     * 获取星期值 1-7,星期一到星期日
     * @param localDate
     * @return
     */
    public static int getDayOfWeek(LocalDate localDate){
        Objects.requireNonNull(localDate, "localDate");
        return localDate.getDayOfWeek().getValue();
    }    
    
    /**
     * 获取星期值 1-7,星期一到星期日
     * @param instant
     * @return
     */
    public static int getDayOfWeek(Instant instant){
        return DateTimeConverterUtil.toLocalDateTime(instant).getDayOfWeek().getValue();
    }
    
    /**
     * 获取星期英文全称,比如Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday
     * @param date
     * @return
     */
    public static String getDayOfWeekEnLong(Date date){
        return WeekNameEnum.getFullNameEnByCode(getDayOfWeek(date));
    }
    
    /**
     * 获取星期英文全称,比如Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday
     * @param localDateTime
     * @return
     */
    public static String getDayOfWeekEnLong(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return WeekNameEnum.getFullNameEnByCode(getDayOfWeek(localDateTime));
    }
    
    /**
     * 获取星期英文全称,比如Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday
     * @param localDate
     * @return
     */
    public static String getDayOfWeekEnLong(LocalDate localDate){
        Objects.requireNonNull(localDate, "localDate");
        return WeekNameEnum.getFullNameEnByCode(getDayOfWeek(localDate));
    }    
    
    /**
     * 获取星期英文全称,比如Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday
     * @param instant
     * @return
     */
    public static String getDayOfWeekEnLong(Instant instant){
        return WeekNameEnum.getFullNameEnByCode(getDayOfWeek(instant));
    }
    
    /**
     * 获取星期英文简称,比如Mon
     * @param date
     * @return
     */
    public static String getDayOfWeekEnShort(Date date){
        return WeekNameEnum.getShortNameEnByCode(getDayOfWeek(date));
    }
    
    /**
     * 获取星期英文简称,比如Mon
     * @param localDateTime
     * @return
     */
    public static String getDayOfWeekEnShort(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return WeekNameEnum.getShortNameEnByCode(getDayOfWeek(localDateTime));
    }
    
    /**
     * 获取星期英文简称,比如Mon
     * @param localDate
     * @return
     */
    public static String getDayOfWeekEnShort(LocalDate localDate){
        Objects.requireNonNull(localDate, "localDate");
        return WeekNameEnum.getShortNameEnByCode(getDayOfWeek(localDate));
    }    
    
    /**
     * 获取星期英文简称,比如Mon
     * @param instant
     * @return
     */
    public static String getDayOfWeekEnShort(Instant instant){
        return WeekNameEnum.getShortNameEnByCode(getDayOfWeek(instant));
    }    
    
    
    /**
     * 获取星期中文,比如星期一
     * @param date
     * @return
     */
    public static String getDayOfWeekCn(Date date){
        return WeekNameEnum.getNameCnByCode(getDayOfWeek(date));
    }
    
    /**
     * 获取星期中文,比如星期一
     * @param localDateTime
     * @return
     */
    public static String getDayOfWeekCn(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return WeekNameEnum.getNameCnByCode(getDayOfWeek(localDateTime));
    }
    
    /**
     * 获取星期中文,比如星期一
     * @param localDate
     * @return
     */
    public static String getDayOfWeekCn(LocalDate localDate){
        Objects.requireNonNull(localDate, "localDate");
        return WeekNameEnum.getNameCnByCode(getDayOfWeek(localDate));
    }    
    
    /**
     * 获取星期中文,比如星期一
     * @param instant
     * @return
     */
    public static String getDayOfWeekCn(Instant instant){
        return WeekNameEnum.getNameCnByCode(getDayOfWeek(instant));
    }

 

测试代码:

    /**
     * 获取星期信息,包括英文全称简称,中文等
     */
    @Test
    public void dateGetWeekTest(){
        Date date = new Date();
        System.out.println(date);
        
        System.out.println(DateTimeCalculatorUtil.getDayOfWeek(date));
        System.out.println(DateTimeCalculatorUtil.getDayOfWeekEnLong(date));
        System.out.println(DateTimeCalculatorUtil.getDayOfWeekEnShort(date));
        System.out.println(DateTimeCalculatorUtil.getDayOfWeekCn(date));
    }

 

输出:

Thu Feb 27 16:09:00 CST 2020
4
Thursday
Thu
星期四

 

源代码地址:https://github.com/xkzhangsan/xk-time

Java日期时间API系列21—–Jdk8中java.time包中的新的日期时间API类,xk-time时间转换,计算,格式化,解析的工具

  通过工作之余,对Java8中java.time包源码的不断学习,使用和总结,开发了xk-time,初步完成,欢迎试用和提出建议!

xk-time

xk-time is a datetime converter calculator and formatter tool set, based on java8 date and time API, thread safe, easy to use.

时间转换,计算,格式化,解析的工具,使用java8,线程安全,简单易用,多达20几种常用日期格式化模板。

0.为什么要开发这个工具?

原因1:常见的DateUtil,往往将时间转换,计算,格式化,解析等功能都放在同一个类中,导致类功能复杂,方法太多,查找不方便。

xk-time工具包,将上面功能按照时间转换,时间计算,时间格式化解析分成3个工具类:DateTimeConverterUtil,DateTimeCalculatorUtil,DateTimeFormatterUtil,每个类只做一个种功能,方便使用。

原因2:java8以前的Date API设计不太好,往往会有线程安全问题

使用java8api,Instant、LocalDate、LocalDateTime、LocalTime、ZonedDateTime等都是线程安全的类,而且增加了更丰富的方法,在此基础上开发相关工具类,线程安全,让使用更方便。

1.依赖

  
  com.github.xkzhangsan    
  xk-time       
  0.0.2    
    

2.日期转换 DateTimeConverterUtil

包含Date、LocalDate、LocalDateTime、LocalTime、Instant和ZonedDateTime的互相转换
注意,ZonedDateTime相关的转换,尤其是其他时间转ZonedDateTime,要注意时间和对应时区一致。

3.日期计算工具类 DateTimeCalculatorUtil

包括:
(1)获取时间属性方法,get* 比如getYear(Date date) 获取年部分。
(2)获取时间加操作方法,plus* 比如plusYears(Date date, long amountToAdd) 当前时间年增加amountToAdd值。
(3)获取时间减操作方法,minus* 比如minusYears(Date date, long amountToAdd) 当前时间年减少amountToAdd值。
(4)获取时间修改属性方法,with* 比如withYear(Date date, long newValue) 修改当前时间年值为newValue。
(5)获取比较2个时间方法,between* 比如betweenYears(Date startInclusive, Date endExclusive) 比较2个时间,获取年部分。
(6)其他常用方法,比如isLeapYear(Date date) 判断是否闰年。
(7)时区转换计算方法,transform*,比如transform(ZonedDateTime zonedDateTime, String zoneId)
(8)比较2个时间大小和相等方法,compare*,比如compare(Date date1, Date date2)

4.日期格式化和解析DateTimeFormatterUtil

包含常用日期格式如:
yyyy-MM-dd
HH:mm:ss
yyyy-MM-dd HH:mm:ss
yyyy-MM-dd’T’HH:mm:ssZ等等

注意:格式化和解析ZonedDateTime 时区时间时,只能使用ISO开头 的Formatter,如ISO_DATE_FMT和YYYY_MM_DD_T_HH_MM_SS_Z_FMT
因为,其他Formatter都绑定的是系统默认时区: private static final ZoneId ZONE = ZoneId.systemDefault();

如果需要使用其他Formatter,可以使用withZone方法重新设置时区,比如:
YYYY_MM_DD_HH_MM_SS_SSS_FMT.withZone(ZoneId.of(“Europe/Paris”)

 

源码地址:https://github.com/xkzhangsan/xk-time

Java日期时间API系列13—–Jdk8中java.time包中的新的日期时间API类,时间类转换,Date转LocalDateTime,LocalDateTime转Date等

  从前面的系列博客中可以看出Jdk8中java.time包中的新的日期时间API类设计的很好,但Date由于使用仍非常广泛,这就涉及到Date转LocalDateTime,LocalDateTime转Date。下面是时间类互相转换大全,包含Instant、LocalDate、LocalDateTime、LocalTime、ZonedDateTime和Date的相互转换,时间转换大全,下面是一个工具类,仅供参考:

具体包含:

LocalDateTime转Date,LocalDate转Date,LocalTime转Date,Instant转Date,epochMilli毫秒转Date,ZonedDateTime转Date,Date转LocalDateTime,LocalDate转LocalDateTime,LocalTime转LocalDateTime,Instant转LocalDateTime,epochMilli毫秒转LocalDateTime,temporal转LocalDateTime,ZonedDateTime转LocalDateTime,Date转LocalDate,LocalDateTime转LocalDate,Instant转LocalDate,temporal转LocalDate,ZonedDateTime转LocalDate,Date转LocalTime,LocalDateTime转LocalTime,Instant转LocalTime,temporal转LocalTime,ZonedDateTime转LocalTime,Date转Instant,LocalDateTime转Instant,LocalDate转Instant,LocalTime转Instant,epochMilli毫秒转Instant,temporal转Instant,ZonedDateTime转Instant,Date转毫秒值,LocalDateTime转毫秒值,LocalDate转毫秒值,Instant转毫秒值,ZonedDateTime转毫秒值,Date转ZonedDateTime,LocalDateTime转ZonedDateTime,LocalDate转ZonedDateTime,LocalTime转ZonedDateTime,Instant转ZonedDateTime,epochMilli毫秒转ZonedDateTime,temporal转ZonedDateTime.

 

package com.xkzhangsan.time.converter;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.Objects;

/**
 * 日期转换
 * 包含Date、LocalDate、LocalDateTime、LocalTime、Instant和ZonedDateTime的互相转换
 * 
 * 注意,ZonedDateTime相关的转换,尤其是其他时间转ZonedDateTime,要注意时间和对应时区一致。
* @ClassName: DateTimeConverterUtil 
* @Description: DateTime Converter
* @author xkzhangsan
* @date 2019年12月1日
*
 */
public class DateTimeConverterUtil {
    
    private DateTimeConverterUtil(){
    }

    /**
     * LocalDateTime转Date
     * @param localDateTime
     * @return
     */
    public static Date toDate(LocalDateTime localDateTime) {
        Objects.requireNonNull(localDateTime, "localDateTime");
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * LocalDate转Date
     * @param localDate
     * @return
     */
    public static Date toDate(LocalDate localDate) {
        Objects.requireNonNull(localDate, "localDate");
        return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }
    
    /**
     * LocalTime转Date
     * 以当天的日期+LocalTime组成新的LocalDateTime转换为Date
     * @param localTime
     * @return
     */
    public static Date toDate(LocalTime localTime) {
        Objects.requireNonNull(localTime, "localTime");
        return Date.from(LocalDate.now().atTime(localTime).atZone(ZoneId.systemDefault()).toInstant());
    }    

    /**
     * Instant转Date
     * @param instant
     * @return
     */
    public static Date toDate(Instant instant) {
        return Date.from(instant);
    }
    
    /**
     * epochMilli毫秒转Date
     * @param epochMilli
     * @return
     */
    public static Date toDate(long epochMilli){
        Objects.requireNonNull(epochMilli, "epochMilli");
        return new Date(epochMilli);
    }
    
    /**
     * ZonedDateTime转Date
     * 注意时间对应的时区和默认时区差异
     * @param zonedDateTime
     * @return
     */
    public static Date toDate(ZonedDateTime zonedDateTime) {
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * Date转LocalDateTime
     * @param date
     * @return
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        Objects.requireNonNull(date, "date");
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * LocalDate转LocalDateTime
     * @param localDate
     * @return
     */
    public static LocalDateTime toLocalDateTime(LocalDate localDate) {
        Objects.requireNonNull(localDate, "localDate");
        return localDate.atStartOfDay();
    }
    
    /**
     * LocalTime转LocalDateTime
     * 以当天的日期+LocalTime组成新的LocalDateTime
     * @param localTime
     * @return
     */
    public static LocalDateTime toLocalDateTime(LocalTime localTime) {
        Objects.requireNonNull(localTime, "localTime");
        return LocalDate.now().atTime(localTime);
    }

    /**
     * Instant转LocalDateTime
     * @param instant
     * @return
     */
    public static LocalDateTime toLocalDateTime(Instant instant) {
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }
    
    /**
     * epochMilli毫秒转LocalDateTime
     * @param epochMilli
     * @return
     */
    public static LocalDateTime toLocalDateTime(long epochMilli) {
        Objects.requireNonNull(epochMilli, "epochMilli");
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMilli), ZoneId.systemDefault());
    }
    
    /**
     * temporal转LocalDateTime
     * @param temporal
     * @return
     */
    public static LocalDateTime toLocalDateTime(TemporalAccessor temporal) {
        return LocalDateTime.from(temporal);
    }
    
    /**
     * ZonedDateTime转LocalDateTime
     * 注意时间对应的时区和默认时区差异
     * @param zonedDateTime
     * @return
     */
    public static LocalDateTime toLocalDateTime(ZonedDateTime zonedDateTime) {
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        return zonedDateTime.toLocalDateTime();
    }

    /**
     * Date转LocalDate
     * @param date
     * @return
     */
    public static LocalDate toLocalDate(Date date) {
        return toLocalDateTime(date).toLocalDate();
    }

    /**
     * LocalDateTime转LocalDate
     * @param localDateTime
     * @return
     */
    public static LocalDate toLocalDate(LocalDateTime localDateTime) {
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.toLocalDate();
    }

    /**
     * Instant转LocalDate
     * @param instant
     * @return
     */
    public static LocalDate toLocalDate(Instant instant) {
        return toLocalDateTime(instant).toLocalDate();
    }
    
    /**
     * temporal转LocalDate
     * @param temporal
     * @return
     */
    public static LocalDate toLocalDate(TemporalAccessor temporal) {
        return LocalDate.from(temporal);
    }
    
    /**
     * ZonedDateTime转LocalDate
     * 注意时间对应的时区和默认时区差异
     * @param zonedDateTime
     * @return
     */
    public static LocalDate toLocalDate(ZonedDateTime zonedDateTime) {
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        return zonedDateTime.toLocalDate();
    }

    /**
     * Date转LocalTime
     * @param date
     * @return
     */
    public static LocalTime toLocalTime(Date date) {
        return toLocalDateTime(date).toLocalTime();
    }

    /**
     * LocalDateTime转LocalTime
     * @param localDateTime
     * @return
     */
    public static LocalTime toLocalTime(LocalDateTime localDateTime) {
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.toLocalTime();
    }

    /**
     * Instant转LocalTime
     * @param instant
     * @return
     */
    public static LocalTime toLocalTime(Instant instant) {
        return toLocalDateTime(instant).toLocalTime();
    }
    
    /**
     * temporal转LocalTime
     * @param temporal
     * @return
     */
    public static LocalTime toLocalTime(TemporalAccessor temporal) {
        return LocalTime.from(temporal);
    }
    
    /**
     * ZonedDateTime转LocalTime
     * 注意时间对应的时区和默认时区差异
     * @param zonedDateTime
     * @return
     */
    public static LocalTime toLocalTime(ZonedDateTime zonedDateTime) {
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        return zonedDateTime.toLocalTime();
    }

    /**
     * Date转Instant
     * @param date
     * @return
     */
    public static Instant toInstant(Date date) {
        Objects.requireNonNull(date, "date");
        return date.toInstant();
    }

    /**
     * LocalDateTime转Instant
     * @param localDateTime
     * @return
     */
    public static Instant toInstant(LocalDateTime localDateTime) {
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.atZone(ZoneId.systemDefault()).toInstant();
    }

    /**
     * LocalDate转Instant
     * @param localDate
     * @return
     */
    public static Instant toInstant(LocalDate localDate) {
        return toLocalDateTime(localDate).atZone(ZoneId.systemDefault()).toInstant();
    }
    
    /**
     * LocalTime转Instant
     * 以当天的日期+LocalTime组成新的LocalDateTime转换为Instant
     * @param localTime
     * @return
     */
    public static Instant toInstant(LocalTime localTime) {
        return toLocalDateTime(localTime).atZone(ZoneId.systemDefault()).toInstant();
    }
    
    /**
     * epochMilli毫秒转Instant
     * @param epochMilli
     * @return
     */
    public static Instant toInstant(long epochMilli) {
        Objects.requireNonNull(epochMilli, "epochMilli");
        return Instant.ofEpochMilli(epochMilli);
    }
    
    /**
     * temporal转Instant
     * @param temporal
     * @return
     */
    public static Instant toInstant(TemporalAccessor temporal) {
        return Instant.from(temporal);
    }
    
    /**
     * ZonedDateTime转Instant
     * 注意时间对应的时区和默认时区差异
     * @param zonedDateTime
     * @return
     */
    public static Instant toInstant(ZonedDateTime zonedDateTime) {
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        return zonedDateTime.toInstant();
    }
    
    /**
     * Date转毫秒值
     * 从1970-01-01T00:00:00Z开始的毫秒值
     * @param date
     * @return
     */
    public static long toEpochMilli(Date date){
        Objects.requireNonNull(date, "date");
        return date.getTime();
    }
    
    /**
     * LocalDateTime转毫秒值
     * 从1970-01-01T00:00:00Z开始的毫秒值
     * @param localDateTime
     * @return
     */
    public static long toEpochMilli(LocalDateTime localDateTime){
        return toInstant(localDateTime).toEpochMilli();
    }
    
    /**
     * LocalDate转毫秒值
     * 从1970-01-01T00:00:00Z开始的毫秒值
     * @param localDate
     * @return
     */
    public static long toEpochMilli(LocalDate localDate){
        return toInstant(localDate).toEpochMilli();
    }
    
    /**
     * Instant转毫秒值
     * 从1970-01-01T00:00:00Z开始的毫秒值
     * @param instant
     * @return
     */
    public static long toEpochMilli(Instant instant){
        Objects.requireNonNull(instant, "instant");
        return instant.toEpochMilli();
    }
    
    /**
     * ZonedDateTime转毫秒值,注意时间对应的时区和默认时区差异
     * 从1970-01-01T00:00:00Z开始的毫秒值
     * @param zonedDateTime
     * @return
     */
    public static long toEpochMilli(ZonedDateTime zonedDateTime) {
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        return zonedDateTime.toInstant().toEpochMilli();
    }
    
    /**
     * Date转ZonedDateTime,时区为系统默认时区
     * @param date
     * @return
     */
    public static ZonedDateTime toZonedDateTime(Date date) {
        Objects.requireNonNull(date, "date");
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime()
                .atZone(ZoneId.systemDefault());
    }
    
    /**
     * LocalDateTime转ZonedDateTime,时区为系统默认时区
     * @param localDateTime
     * @return
     */
    public static ZonedDateTime toZonedDateTime(LocalDateTime localDateTime) {
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.atZone(ZoneId.systemDefault());
    }

/**
* LocalDateTime转ZonedDateTime,时区为zoneId对应时区
* 注意,需要保证localDateTime和zoneId是对应的,不然会出现错误
*
* @param localDateTime
* @param zoneId
* @return
*/
public static ZonedDateTime toZonedDateTime(LocalDateTime localDateTime, String zoneId) {
  Objects.requireNonNull(localDateTime, “localDateTime”);
  Objects.requireNonNull(zoneId, “zoneId”);
  return localDateTime.atZone(ZoneId.of(zoneId));
}

/**
     * LocalDate转ZonedDateTime,时区为系统默认时区
     * @param localDate
     * @return such as 2020-02-19T00:00+08:00[Asia/Shanghai]
     */
    public static ZonedDateTime toZonedDateTime(LocalDate localDate) {
        Objects.requireNonNull(localDate, "localDate");
        return localDate.atStartOfDay().atZone(ZoneId.systemDefault());
    }
    
    /**
     * LocalTime转ZonedDateTime
     * 以当天的日期+LocalTime组成新的ZonedDateTime,时区为系统默认时区
     * @param localTime
     * @return
     */
    public static ZonedDateTime toZonedDateTime(LocalTime localTime) {
        Objects.requireNonNull(localTime, "localTime");
        return LocalDate.now().atTime(localTime).atZone(ZoneId.systemDefault());
    }

    /**
     * Instant转ZonedDateTime,时区为系统默认时区
     * @param instant
     * @return
     */
    public static ZonedDateTime toZonedDateTime(Instant instant) {
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).atZone(ZoneId.systemDefault());
    }
    
    /**
     * epochMilli毫秒转ZonedDateTime,时区为系统默认时区
     * @param epochMilli
     * @return
     */
    public static ZonedDateTime toZonedDateTime(long epochMilli) {
        Objects.requireNonNull(epochMilli, "epochMilli");
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMilli), ZoneId.systemDefault())
                .atZone(ZoneId.systemDefault());
    }
    
    /**
     * temporal转ZonedDateTime,时区为系统默认时区
     * @param temporal
     * @return
     */
    public static ZonedDateTime toZonedDateTime(TemporalAccessor temporal) {
        return LocalDateTime.from(temporal).atZone(ZoneId.systemDefault());
    }    

}

 

 测试代码

package com.xkzhangsan.time.test;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.Date;

import org.junit.Test;

import com.xkzhangsan.time.converter.DateTimeConverterUtil;

public class ConverterTest {
    
    @Test
    public void dateConverterTest(){
        System.out.println("===================dateConverterTest=====================");
        Date date = new Date();
        System.out.println(DateTimeConverterUtil.toLocalDateTime(date));
        System.out.println(DateTimeConverterUtil.toLocalDate(date));
        System.out.println(DateTimeConverterUtil.toLocalTime(date));
        System.out.println(DateTimeConverterUtil.toInstant(date));
    }
    
    @Test
    public void localDateTimeConverterTest(){
        System.out.println("===================localDateTimeConverterTest=====================");
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);
        System.out.println(DateTimeConverterUtil.toDate(ldt));
        System.out.println(DateTimeConverterUtil.toLocalDate(ldt));
        System.out.println(DateTimeConverterUtil.toLocalTime(ldt));
        System.out.println(DateTimeConverterUtil.toInstant(ldt));
        System.out.println(DateTimeConverterUtil.toZonedDateTime(ldt));
    }
    
    @Test
    public void localDateConverterTest(){
        System.out.println("===================localDateConverterTest=====================");
        LocalDate ld = LocalDate.now();
        System.out.println(ld);
        System.out.println(DateTimeConverterUtil.toDate(ld));
        System.out.println(DateTimeConverterUtil.toLocalDateTime(ld));
        System.out.println(DateTimeConverterUtil.toInstant(ld));
    }
    
    @Test
    public void localTimeConverterTest(){
        System.out.println("===================localTimeConverterTest=====================");
        LocalTime lt = LocalTime.now();
        System.out.println(lt);
        System.out.println(DateTimeConverterUtil.toDate(lt));
        System.out.println(DateTimeConverterUtil.toLocalDateTime(lt));
        System.out.println(DateTimeConverterUtil.toLocalTime(lt));
        System.out.println(DateTimeConverterUtil.toInstant(lt));
    }    

    
    @Test
    public void instantConverterTest(){
        System.out.println("===================instantConverterTest=====================");
        Instant instant = Instant.now();
        System.out.println(instant);
        System.out.println(DateTimeConverterUtil.toDate(instant));
        System.out.println(DateTimeConverterUtil.toLocalDateTime(instant));
        System.out.println(DateTimeConverterUtil.toLocalDate(instant));
    }
    
    @Test
    public void zonedDateTimeConverterTest(){
        System.out.println("===================zonedDateTimeConverterTest=====================");
        System.out.println("===================ToOther=====================");
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        System.out.println(zonedDateTime);
        System.out.println(DateTimeConverterUtil.toDate(zonedDateTime));
        System.out.println(DateTimeConverterUtil.toLocalDateTime(zonedDateTime));
        System.out.println(DateTimeConverterUtil.toLocalDate(zonedDateTime));
        System.out.println(DateTimeConverterUtil.toLocalTime(zonedDateTime));
        System.out.println(DateTimeConverterUtil.toInstant(zonedDateTime));
        System.out.println("===================toZonedDateTime=====================");
        System.out.println(zonedDateTime);
        System.out.println(DateTimeConverterUtil.toZonedDateTime(new Date()));
        System.out.println(DateTimeConverterUtil.toZonedDateTime(LocalDateTime.now()));
        System.out.println(DateTimeConverterUtil.toZonedDateTime(LocalDate.now()));
        System.out.println(DateTimeConverterUtil.toZonedDateTime(LocalTime.now()));
        System.out.println(DateTimeConverterUtil.toZonedDateTime(Instant.now()));
    }    
}

 

输出:

===================dateConverterTest=====================
2020-02-19T16:10:04.366
2020-02-19
16:10:04.366
2020-02-19T08:10:04.366Z
===================localTimeConverterTest=====================
16:10:04.458
Wed Feb 19 16:10:04 CST 2020
2020-02-19T16:10:04.458
16:10:04.458
2020-02-19T08:10:04.458Z
===================localDateConverterTest=====================
2020-02-19
Wed Feb 19 00:00:00 CST 2020
2020-02-19T00:00
2020-02-18T16:00:00Z
===================zonedDateTimeConverterTest=====================
===================ToOther=====================
2020-02-19T16:10:04.464+08:00[Asia/Shanghai]
Wed Feb 19 16:10:04 CST 2020
2020-02-19T16:10:04.464
2020-02-19
16:10:04.464
2020-02-19T08:10:04.464Z
===================toZonedDateTime=====================
2020-02-19T16:10:04.464+08:00[Asia/Shanghai]
2020-02-19T16:10:04.465+08:00[Asia/Shanghai]
2020-02-19T16:10:04.465+08:00[Asia/Shanghai]
2020-02-19T00:00+08:00[Asia/Shanghai]
2020-02-19T16:10:04.466+08:00[Asia/Shanghai]
2020-02-19T16:10:04.466+08:00[Asia/Shanghai]
===================localDateTimeConverterTest=====================
2020-02-19T16:10:04.466
Wed Feb 19 16:10:04 CST 2020
2020-02-19
16:10:04.466
2020-02-19T08:10:04.466Z
2020-02-19T16:10:04.466+08:00[Asia/Shanghai]
===================instantConverterTest=====================
2020-02-19T08:10:04.467Z
Wed Feb 19 16:10:04 CST 2020
2020-02-19T16:10:04.467
2020-02-19

 

源码地址:https://github.com/xkzhangsan/xk-time

Java日期时间API系列20—–Jdk8中java.time包中的新的日期时间API类,ZoneId时区ID大全等。

  Java日期时间API系列19—–Jdk8中java.time包中的新的日期时间API类,ZonedDateTime与ZoneId和LocalDateTime的关系,ZonedDateTime格式化和时区转换等。中已经对ZoneId说明,并列出了常用时区ID信息。

  并且通过 java.time.ZoneId.getAvailableZoneIds()获取到所有可用时区ID。

1.测试代码

    /**
     * 获取可用时区ID
     */
    @Test
    public void getAvailableZoneIds(){
        for(String zoneId : ZoneId.getAvailableZoneIds()){
            System.out.println(zoneId);
        }
    }

 

输出:

Asia/Aden
America/Cuiaba
Etc/GMT+9
Etc/GMT+8
Africa/Nairobi
America/Marigot
Asia/Aqtau
Pacific/Kwajalein
America/El_Salvador
Asia/Pontianak
Africa/Cairo
Pacific/Pago_Pago
Africa/Mbabane
Asia/Kuching
Pacific/Honolulu
Pacific/Rarotonga
America/Guatemala
Australia/Hobart
Europe/London
America/Belize
America/Panama
Asia/Chungking
America/Managua
America/Indiana/Petersburg
Asia/Yerevan
Europe/Brussels
GMT
Europe/Warsaw
America/Chicago
Asia/Kashgar
Chile/Continental
Pacific/Yap
CET
Etc/GMT-1
Etc/GMT-0
Europe/Jersey
America/Tegucigalpa
Etc/GMT-5
Europe/Istanbul
America/Eirunepe
Etc/GMT-4
America/Miquelon
Etc/GMT-3
Europe/Luxembourg
Etc/GMT-2
Etc/GMT-9
America/Argentina/Catamarca
Etc/GMT-8
Etc/GMT-7
Etc/GMT-6
Europe/Zaporozhye
Canada/Yukon
Canada/Atlantic
Atlantic/St_Helena
Australia/Tasmania
Libya
Europe/Guernsey
America/Grand_Turk
US/Pacific-New
Asia/Samarkand
America/Argentina/Cordoba
Asia/Phnom_Penh
Africa/Kigali
Asia/Almaty
US/Alaska
Asia/Dubai
Europe/Isle_of_Man
America/Araguaina
Cuba
Asia/Novosibirsk
America/Argentina/Salta
Etc/GMT+3
Africa/Tunis
Etc/GMT+2
Etc/GMT+1
Pacific/Fakaofo
Africa/Tripoli
Etc/GMT+0
Israel
Africa/Banjul
Etc/GMT+7
Indian/Comoro
Etc/GMT+6
Etc/GMT+5
Etc/GMT+4
Pacific/Port_Moresby
US/Arizona
Antarctica/Syowa
Indian/Reunion
Pacific/Palau
Europe/Kaliningrad
America/Montevideo
Africa/Windhoek
Asia/Karachi
Africa/Mogadishu
Australia/Perth
Brazil/East
Etc/GMT
Asia/Chita
Pacific/Easter
Antarctica/Davis
Antarctica/McMurdo
Asia/Macao
America/Manaus
Africa/Freetown
Europe/Bucharest
Asia/Tomsk
America/Argentina/Mendoza
Asia/Macau
Europe/Malta
Mexico/BajaSur
Pacific/Tahiti
Africa/Asmera
Europe/Busingen
America/Argentina/Rio_Gallegos
Africa/Malabo
Europe/Skopje
America/Catamarca
America/Godthab
Europe/Sarajevo
Australia/ACT
GB-Eire
Africa/Lagos
America/Cordoba
Europe/Rome
Asia/Dacca
Indian/Mauritius
Pacific/Samoa
America/Regina
America/Fort_Wayne
America/Dawson_Creek
Africa/Algiers
Europe/Mariehamn
America/St_Johns
America/St_Thomas
Europe/Zurich
America/Anguilla
Asia/Dili
America/Denver
Africa/Bamako
Europe/Saratov
GB
Mexico/General
Pacific/Wallis
Europe/Gibraltar
Africa/Conakry
Africa/Lubumbashi
Asia/Istanbul
America/Havana
NZ-CHAT
Asia/Choibalsan
America/Porto_Acre
Asia/Omsk
Europe/Vaduz
US/Michigan
Asia/Dhaka
America/Barbados
Europe/Tiraspol
Atlantic/Cape_Verde
Asia/Yekaterinburg
America/Louisville
Pacific/Johnston
Pacific/Chatham
Europe/Ljubljana
America/Sao_Paulo
Asia/Jayapura
America/Curacao
Asia/Dushanbe
America/Guyana
America/Guayaquil
America/Martinique
Portugal
Europe/Berlin
Europe/Moscow
Europe/Chisinau
America/Puerto_Rico
America/Rankin_Inlet
Pacific/Ponape
Europe/Stockholm
Europe/Budapest
America/Argentina/Jujuy
Australia/Eucla
Asia/Shanghai
Universal
Europe/Zagreb
America/Port_of_Spain
Europe/Helsinki
Asia/Beirut
Asia/Tel_Aviv
Pacific/Bougainville
US/Central
Africa/Sao_Tome
Indian/Chagos
America/Cayenne
Asia/Yakutsk
Pacific/Galapagos
Australia/North
Europe/Paris
Africa/Ndjamena
Pacific/Fiji
America/Rainy_River
Indian/Maldives
Australia/Yancowinna
SystemV/AST4
Asia/Oral
America/Yellowknife
Pacific/Enderbury
America/Juneau
Australia/Victoria
America/Indiana/Vevay
Asia/Tashkent
Asia/Jakarta
Africa/Ceuta
Asia/Barnaul
America/Recife
America/Buenos_Aires
America/Noronha
America/Swift_Current
Australia/Adelaide
America/Metlakatla
Africa/Djibouti
America/Paramaribo
Europe/Simferopol
Europe/Sofia
Africa/Nouakchott
Europe/Prague
America/Indiana/Vincennes
Antarctica/Mawson
America/Kralendijk
Antarctica/Troll
Europe/Samara
Indian/Christmas
America/Antigua
Pacific/Gambier
America/Indianapolis
America/Inuvik
America/Iqaluit
Pacific/Funafuti
UTC
Antarctica/Macquarie
Canada/Pacific
America/Moncton
Africa/Gaborone
Pacific/Chuuk
Asia/Pyongyang
America/St_Vincent
Asia/Gaza
Etc/Universal
PST8PDT
Atlantic/Faeroe
Asia/Qyzylorda
Canada/Newfoundland
America/Kentucky/Louisville
America/Yakutat
Asia/Ho_Chi_Minh
Antarctica/Casey
Europe/Copenhagen
Africa/Asmara
Atlantic/Azores
Europe/Vienna
ROK
Pacific/Pitcairn
America/Mazatlan
Australia/Queensland
Pacific/Nauru
Europe/Tirane
Asia/Kolkata
SystemV/MST7
Australia/Canberra
MET
Australia/Broken_Hill
Europe/Riga
America/Dominica
Africa/Abidjan
America/Mendoza
America/Santarem
Kwajalein
America/Asuncion
Asia/Ulan_Bator
NZ
America/Boise
Australia/Currie
EST5EDT
Pacific/Guam
Pacific/Wake
Atlantic/Bermuda
America/Costa_Rica
America/Dawson
Asia/Chongqing
Eire
Europe/Amsterdam
America/Indiana/Knox
America/North_Dakota/Beulah
Africa/Accra
Atlantic/Faroe
Mexico/BajaNorte
America/Maceio
Etc/UCT
Pacific/Apia
GMT0
America/Atka
Pacific/Niue
Australia/Lord_Howe
Europe/Dublin
Pacific/Truk
MST7MDT
America/Monterrey
America/Nassau
America/Jamaica
Asia/Bishkek
America/Atikokan
Atlantic/Stanley
Australia/NSW
US/Hawaii
SystemV/CST6
Indian/Mahe
Asia/Aqtobe
America/Sitka
Asia/Vladivostok
Africa/Libreville
Africa/Maputo
Zulu
America/Kentucky/Monticello
Africa/El_Aaiun
Africa/Ouagadougou
America/Coral_Harbour
Pacific/Marquesas
Brazil/West
America/Aruba
America/North_Dakota/Center
America/Cayman
Asia/Ulaanbaatar
Asia/Baghdad
Europe/San_Marino
America/Indiana/Tell_City
America/Tijuana
Pacific/Saipan
SystemV/YST9
Africa/Douala
America/Chihuahua
America/Ojinaga
Asia/Hovd
America/Anchorage
Chile/EasterIsland
America/Halifax
Antarctica/Rothera
America/Indiana/Indianapolis
US/Mountain
Asia/Damascus
America/Argentina/San_Luis
America/Santiago
Asia/Baku
America/Argentina/Ushuaia
Atlantic/Reykjavik
Africa/Brazzaville
Africa/Porto-Novo
America/La_Paz
Antarctica/DumontDUrville
Asia/Taipei
Antarctica/South_Pole
Asia/Manila
Asia/Bangkok
Africa/Dar_es_Salaam
Poland
Atlantic/Madeira
Antarctica/Palmer
America/Thunder_Bay
Africa/Addis_Ababa
Asia/Yangon
Europe/Uzhgorod
Brazil/DeNoronha
Asia/Ashkhabad
Etc/Zulu
America/Indiana/Marengo
America/Creston
America/Punta_Arenas
America/Mexico_City
Antarctica/Vostok
Asia/Jerusalem
Europe/Andorra
US/Samoa
PRC
Asia/Vientiane
Pacific/Kiritimati
America/Matamoros
America/Blanc-Sablon
Asia/Riyadh
Iceland
Pacific/Pohnpei
Asia/Ujung_Pandang
Atlantic/South_Georgia
Europe/Lisbon
Asia/Harbin
Europe/Oslo
Asia/Novokuznetsk
CST6CDT
Atlantic/Canary
America/Knox_IN
Asia/Kuwait
SystemV/HST10
Pacific/Efate
Africa/Lome
America/Bogota
America/Menominee
America/Adak
Pacific/Norfolk
Europe/Kirov
America/Resolute
Pacific/Tarawa
Africa/Kampala
Asia/Krasnoyarsk
Greenwich
SystemV/EST5
America/Edmonton
Europe/Podgorica
Australia/South
Canada/Central
Africa/Bujumbura
America/Santo_Domingo
US/Eastern
Europe/Minsk
Pacific/Auckland
Africa/Casablanca
America/Glace_Bay
Canada/Eastern
Asia/Qatar
Europe/Kiev
Singapore
Asia/Magadan
SystemV/PST8
America/Port-au-Prince
Europe/Belfast
America/St_Barthelemy
Asia/Ashgabat
Africa/Luanda
America/Nipigon
Atlantic/Jan_Mayen
Brazil/Acre
Asia/Muscat
Asia/Bahrain
Europe/Vilnius
America/Fortaleza
Etc/GMT0
US/East-Indiana
America/Hermosillo
America/Cancun
Africa/Maseru
Pacific/Kosrae
Africa/Kinshasa
Asia/Kathmandu
Asia/Seoul
Australia/Sydney
America/Lima
Australia/LHI
America/St_Lucia
Europe/Madrid
America/Bahia_Banderas
America/Montserrat
Asia/Brunei
America/Santa_Isabel
Canada/Mountain
America/Cambridge_Bay
Asia/Colombo
Australia/West
Indian/Antananarivo
Australia/Brisbane
Indian/Mayotte
US/Indiana-Starke
Asia/Urumqi
US/Aleutian
Europe/Volgograd
America/Lower_Princes
America/Vancouver
Africa/Blantyre
America/Rio_Branco
America/Danmarkshavn
America/Detroit
America/Thule
Africa/Lusaka
Asia/Hong_Kong
Iran
America/Argentina/La_Rioja
Africa/Dakar
SystemV/CST6CDT
America/Tortola
America/Porto_Velho
Asia/Sakhalin
Etc/GMT+10
America/Scoresbysund
Asia/Kamchatka
Asia/Thimbu
Africa/Harare
Etc/GMT+12
Etc/GMT+11
Navajo
America/Nome
Europe/Tallinn
Turkey
Africa/Khartoum
Africa/Johannesburg
Africa/Bangui
Europe/Belgrade
Jamaica
Africa/Bissau
Asia/Tehran
WET
Europe/Astrakhan
Africa/Juba
America/Campo_Grande
America/Belem
Etc/Greenwich
Asia/Saigon
America/Ensenada
Pacific/Midway
America/Jujuy
Africa/Timbuktu
America/Bahia
America/Goose_Bay
America/Virgin
America/Pangnirtung
Asia/Katmandu
America/Phoenix
Africa/Niamey
America/Whitehorse
Pacific/Noumea
Asia/Tbilisi
America/Montreal
Asia/Makassar
America/Argentina/San_Juan
Hongkong
UCT
Asia/Nicosia
America/Indiana/Winamac
SystemV/MST7MDT
America/Argentina/ComodRivadavia
America/Boa_Vista
America/Grenada
Asia/Atyrau
Australia/Darwin
Asia/Khandyga
Asia/Kuala_Lumpur
Asia/Famagusta
Asia/Thimphu
Asia/Rangoon
Europe/Bratislava
Asia/Calcutta
America/Argentina/Tucuman
Asia/Kabul
Indian/Cocos
Japan
Pacific/Tongatapu
America/New_York
Etc/GMT-12
Etc/GMT-11
Etc/GMT-10
SystemV/YST9YDT
Europe/Ulyanovsk
Etc/GMT-14
Etc/GMT-13
W-SU
America/Merida
EET
America/Rosario
Canada/Saskatchewan
America/St_Kitts
Arctic/Longyearbyen
America/Fort_Nelson
America/Caracas
America/Guadeloupe
Asia/Hebron
Indian/Kerguelen
SystemV/PST8PDT
Africa/Monrovia
Asia/Ust-Nera
Egypt
Asia/Srednekolymsk
America/North_Dakota/New_Salem
Asia/Anadyr
Australia/Melbourne
Asia/Irkutsk
America/Shiprock
America/Winnipeg
Europe/Vatican
Asia/Amman
Etc/UTC
SystemV/AST4ADT
Asia/Tokyo
America/Toronto
Asia/Singapore
Australia/Lindeman
America/Los_Angeles
SystemV/EST5EDT
Pacific/Majuro
America/Argentina/Buenos_Aires
Europe/Nicosia
Pacific/Guadalcanal
Europe/Athens
US/Pacific
Europe/Monaco

====================================================

可以通过Google 翻译得到上面时区ID的中文含义。

 

Java日期时间API系列19—–Jdk8中java.time包中的新的日期时间API类,ZonedDateTime与ZoneId和LocalDateTime的关系,ZonedDateTime格式化和时区转换等。

  通过Java日期时间API系列6—–Jdk8中java.time包中的新的日期时间API类中时间范围示意图:可以很清晰的看出ZonedDateTime相当于LocalDateTime+ZoneId。

  

  ZonedDateTime是用来处理时区相关的时间,它的各种计算都离不开ZoneId。先看ZoneId。

1. ZoneId 为时区ID,比如Europe/Paris,表示欧洲巴黎时区

1.1 时区相关知识,时区,UTC时间,GMT时间,Unix时间戳

时区

地球自西向东旋转,东边比西边先看到太阳,东边的时间也比西边的早。为了统一世界的时间,1884年的国际经度会议规规定将全球划分为24个时区(东、西各12个时区)。规定英国(格林尼治天文台旧址)为零时区(GMT+00),东1-12区,西1-12区,中国北京处于东8区(GMT+08)。

若英国时间为6点整,则GMT时间为6点整,则北京时间为14点整。

GMT和UTC

GMT,即格林尼治标准时间,也就是世界时。GMT的正午是指当太阳横穿格林尼治子午线(本初子午线)时的时间。但由于地球自转不均匀不规则,导致GMT不精确,现在已经不再作为世界标准时间使用。

UTC,即协调世界时。UTC是以原子时秒长为基础,在时刻上尽量接近于GMT的一种时间计量系统。为确保UTC与GMT相差不会超过0.9秒,在有需要的情况下会在UTC内加上正或负闰秒。UTC现在作为世界标准时间使用。

所以,UTC与GMT基本上等同,误差不超过0.9秒。

UNIX时间戳

计算机中的UNIX时间戳,是以GMT/UTC时间「1970-01-01T00:00:00」为起点,到具体时间的秒数,不考虑闰秒。这么做当然是为了简化计算机对时间操作的复杂度。

比如我的电脑现在的系统时间为2015年2月27日15点43分0秒,因为我的电脑默认时区为东8区,则0时区的时间为2015年2月27日7点43分0秒,则UNIX时间戳为1425022980秒。

1.2  常用时区名称和缩写如下:

package com.xkzhangsan.time.enums;

/**
 * 常用时区枚举 包含中文名称,比如:"Asia/Shanghai","亚洲/上海"
 * 
 * @ClassName: ZoneIdEnum
 * @Description: ZoneIdEnum
 * @author xkzhangsan
 * @date 2020年02月18日
 * @version 0.1 ,初版,试用
 */
public enum ZoneIdEnum {

    /**
     * "Australia/Darwin","澳洲/达尔文"
     */
    ACT("Australia/Darwin", "澳洲/达尔文"),

    /**
     * "Australia/Sydney","澳洲/悉尼"
     */
    AET("Australia/Sydney", "澳洲/悉尼"),

    /**
     * "America/Argentina/Buenos_Aires","美洲/阿根廷/布宜诺斯艾利斯"
     */
    AGT("America/Argentina/Buenos_Aires", "美洲/阿根廷/布宜诺斯艾利斯"),

    /**
     * "Africa/Cairo","非洲/开罗"
     */
    ART("Africa/Cairo", "非洲/开罗"),

    /**
     * "America/Anchorage","美洲/安克雷奇"
     */
    AST("America/Anchorage", "美洲/安克雷奇"),

    /**
     * "America/Sao_Paulo","美洲/圣保罗"
     */
    BET("America/Sao_Paulo", "美洲/圣保罗"),

    /**
     * "Asia/Dhaka","亚洲/达卡"
     */
    BST("Asia/Dhaka", "亚洲/达卡"),

    /**
     * "Africa/Harare","非洲/哈拉雷"
     */
    CAT("Africa/Harare", "非洲/哈拉雷"),

    /**
     * "America/St_Johns","美洲/圣约翰"
     */
    CNT("America/St_Johns", "美洲/圣约翰"),

    /**
     * "America/Chicago","美洲/芝加哥"
     */
    CST("America/Chicago", "美洲/芝加哥"),

    /**
     * "Asia/Shanghai","亚洲/上海"
     */
    CTT("Asia/Shanghai", "亚洲/上海"),

    /**
     * "Africa/Addis_Ababa","非洲/亚的斯亚贝巴"
     */
    EAT("Africa/Addis_Ababa", "非洲/亚的斯亚贝巴"),

    /**
     * "Europe/Paris","欧洲/巴黎"
     */
    ECT("Europe/Paris", "欧洲/巴黎"),

    /**
     * "America/Indiana/Indianapolis","美洲/印第安纳州/印第安纳波利斯"
     */
    IET("America/Indiana/Indianapolis", "美洲/印第安纳州/印第安纳波利斯"),

    /**
     * "Asia/Kolkata","亚洲/加尔各答"
     */
    IST("Asia/Kolkata", "亚洲/加尔各答"),

    /**
     * "Asia/Tokyo","亚洲/东京"
     */
    JST("Asia/Tokyo", "亚洲/东京"),

    /**
     * "Pacific/Apia","太平洋/阿皮亚"
     */
    MIT("Pacific/Apia", "太平洋/阿皮亚"),

    /**
     * "Asia/Yerevan","亚洲/埃里温"
     */
    NET("Asia/Yerevan", "亚洲/埃里温"),

    /**
     * "Pacific/Auckland","太平洋/奥克兰"
     */
    NST("Pacific/Auckland", "太平洋/奥克兰"),

    /**
     * "Asia/Karachi","亚洲/卡拉奇"
     */
    PLT("Asia/Karachi", "亚洲/卡拉奇"),

    /**
     * "America/Phoenix","美洲/凤凰城"
     */
    PNT("America/Phoenix", "美洲/凤凰城"),

    /**
     * "America/Puerto_Rico","美洲/波多黎各"
     */
    PRT("America/Puerto_Rico", "美洲/波多黎各"),

    /**
     * "America/Los_Angeles","美洲/洛杉矶"
     */
    PST("America/Los_Angeles", "美洲/洛杉矶"),

    /**
     * "Pacific/Guadalcanal","太平洋/瓜达尔卡纳尔岛"
     */
    SST("Pacific/Guadalcanal", "太平洋/瓜达尔卡纳尔岛"),

    /**
     * "Asia/Ho_Chi_Minh","亚洲/胡志明市"
     */
    VST("Asia/Ho_Chi_Minh", "亚洲/胡志明市"),

    /**
     * "-05:00","东部标准时间"(纽约、华盛顿)
     */
    EST("-05:00", "东部标准时间"),

    /**
     * "-07:00","山地标准时间"
     */
    MST("-07:00", "山地标准时间"),

    /**
     * "-10:00","夏威夷-阿留申标准时区"
     */
    HST("-10:00", "夏威夷-阿留申标准时区"),;

    private final String zoneIdName;
    private final String zoneIdNameCn;

    public String getZoneIdName() {
        return zoneIdName;
    }

    public String getZoneIdNameCn() {
        return zoneIdNameCn;
    }

    private ZoneIdEnum(String zoneIdName, String zoneIdNameCn) {
        this.zoneIdName = zoneIdName;
        this.zoneIdNameCn = zoneIdNameCn;
    }
}

1.3  更多时区id

  可以通过 java.time.ZoneId.getAvailableZoneIds()获取到。

 

2. ZonedDateTime,ISO-8601日历系统中带有时区的日期时间,例如:2007-12-03T10:15:30+01:00 Europe/Paris

2.1 创建ZonedDateTime

        ZonedDateTime.now();

        ZonedDateTime.now(ZoneId.systemDefault());
        
        ZonedDateTime.of(LocalDateTime.now(), ZoneId.systemDefault());

 

2.2 ZonedDateTime与其他时间类的转换

    /**
     * 注意时间对应的时区和默认时区差异
     * @param zonedDateTime
     * @return
     */
    public static Date toDate(ZonedDateTime zonedDateTime) {
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        return Date.from(zonedDateTime.toInstant());
    }
    
    /**
     * 注意时间对应的时区和默认时区差异
     * @param zonedDateTime
     * @return
     */
    public static LocalDateTime toLocalDateTime(ZonedDateTime zonedDateTime) {
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        return zonedDateTime.toLocalDateTime();
    }
    
    /**
     * 注意时间对应的时区和默认时区差异
     * @param zonedDateTime
     * @return
     */
    public static LocalDate toLocalDate(ZonedDateTime zonedDateTime) {
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        return zonedDateTime.toLocalDate();
    }
    
    /**
     * 注意时间对应的时区和默认时区差异
     * @param zonedDateTime
     * @return
     */
    public static LocalTime toLocalTime(ZonedDateTime zonedDateTime) {
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        return zonedDateTime.toLocalTime();
    }
    
    /**
     * 注意时间对应的时区和默认时区差异
     * @param zonedDateTime
     * @return
     */
    public static Instant toInstant(ZonedDateTime zonedDateTime) {
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        return zonedDateTime.toInstant();
    }

    /**
     * 转换为ZonedDateTime,时区为系统默认时区
     * @param date
     * @return
     */
    public static ZonedDateTime toZonedDateTime(Date date) {
        Objects.requireNonNull(date, "date");
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime()
                .atZone(ZoneId.systemDefault());
    }
    
    /**
     * 转换为ZonedDateTime,时区为系统默认时区
     * @param localDateTime
     * @return
     */
    public static ZonedDateTime toZonedDateTime(LocalDateTime localDateTime) {
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.atZone(ZoneId.systemDefault());
    }
/** * LocalDateTime转ZonedDateTime,时区为zoneId对应时区 * 注意,需要保证localDateTime和zoneId是对应的,不然会出现错误 * * @param localDateTime * @param zoneId * @return */ public static ZonedDateTime toZonedDateTime(LocalDateTime localDateTime, String zoneId) { Objects.requireNonNull(localDateTime, "localDateTime"); Objects.requireNonNull(zoneId, "zoneId"); return localDateTime.atZone(ZoneId.of(zoneId)); }
/** * 转换为ZonedDateTime,时区为系统默认时区 * @param localDate * @return */ public static ZonedDateTime toZonedDateTime(LocalDate localDate) { Objects.requireNonNull(localDate, "localDate"); return localDate.atStartOfDay().atZone(ZoneId.systemDefault()); } /** * 以当天的日期+LocalTime组成新的ZonedDateTime,时区为系统默认时区 * @param localTime * @return */ public static ZonedDateTime toZonedDateTime(LocalTime localTime) { Objects.requireNonNull(localTime, "localTime"); return LocalDate.now().atTime(localTime).atZone(ZoneId.systemDefault()); } /** * 转换为ZonedDateTime,时区为系统默认时区 * @param instant * @return */ public static ZonedDateTime toZonedDateTime(Instant instant) { return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).atZone(ZoneId.systemDefault()); }

===================================================================================

测试代码:

    @Test
    public void zonedDateTimeConverterTest(){
        System.out.println("===================zonedDateTimeConverterTest=====================");
        System.out.println("===================ToOther=====================");
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        System.out.println(zonedDateTime);
        System.out.println(DateTimeConverterUtil.toDate(zonedDateTime));
        System.out.println(DateTimeConverterUtil.toLocalDateTime(zonedDateTime));
        System.out.println(DateTimeConverterUtil.toLocalDate(zonedDateTime));
        System.out.println(DateTimeConverterUtil.toLocalTime(zonedDateTime));
        System.out.println(DateTimeConverterUtil.toInstant(zonedDateTime));
        System.out.println("===================toZonedDateTime=====================");
        System.out.println(zonedDateTime);
        System.out.println(DateTimeConverterUtil.toZonedDateTime(new Date()));
        System.out.println(DateTimeConverterUtil.toZonedDateTime(LocalDateTime.now()));
        System.out.println(DateTimeConverterUtil.toZonedDateTime(LocalDate.now()));
        System.out.println(DateTimeConverterUtil.toZonedDateTime(LocalTime.now()));
        System.out.println(DateTimeConverterUtil.toZonedDateTime(Instant.now()));
    }

 

输出:

===================zonedDateTimeConverterTest=====================
===================ToOther=====================
2020-02-19T13:33:03.130+08:00[Asia/Shanghai]
Wed Feb 19 13:33:03 CST 2020
2020-02-19T13:33:03.130
2020-02-19
13:33:03.130
2020-02-19T05:33:03.130Z
===================toZonedDateTime=====================
2020-02-19T13:33:03.130+08:00[Asia/Shanghai]
2020-02-19T13:33:03.150+08:00[Asia/Shanghai]
2020-02-19T13:33:03.150+08:00[Asia/Shanghai]
2020-02-19T00:00+08:00[Asia/Shanghai]
2020-02-19T13:33:03.150+08:00[Asia/Shanghai]
2020-02-19T13:33:03.150+08:00[Asia/Shanghai]

由于  public static ZonedDateTime toZonedDateTime(LocalDate localDate),LocalDate只包含日期,所以,转换后显示为:2020-02-19T00:00+08:00[Asia/Shanghai]

 

2.3 常用时区时间创建和时区转换计算

常用时间,如北京时间,巴黎时间,纽约时间,东京时间等。

    /**
     * 获取当前系统当前时区时间
     * @param zoneId
     * @return
     */
    public static ZonedDateTime getZonedDateTimeNowOfDefault(){
        return ZonedDateTime.now(ZoneId.systemDefault());
    }
    
    /**
     * 获取当前上海时区时间(北京时间)
     * @param zoneId
     * @return
     */
    public static ZonedDateTime getZonedDateTimeNowOfShanghai(){
        return ZonedDateTime.now(ZoneId.of(ZoneIdEnum.CTT.getZoneIdName()));
    }
    
    /**
     * 获取当前巴黎时区时间
     * @param zoneId
     * @return
     */
    public static ZonedDateTime getZonedDateTimeNowOfParis(){
        return ZonedDateTime.now(ZoneId.of(ZoneIdEnum.ECT.getZoneIdName()));
    }
    
    /**
     * 获取当前美国东部标准时区(纽约、华盛顿)
     * @param zoneId
     * @return
     */
    public static ZonedDateTime getZonedDateTimeNowOfEST(){
        return ZonedDateTime.now(ZoneId.of(ZoneIdEnum.EST.getZoneIdName()));
    }
    
    /**
     * 获取当前东京时区时间
     * @param zoneId
     * @return
     */
    public static ZonedDateTime getZonedDateTimeNowOfTokyo(){
        return ZonedDateTime.now(ZoneId.of(ZoneIdEnum.JST.getZoneIdName()));
    }    
    
    /**
     * 获取时区当前时间
     * @param zoneId
     * @return
     */
    public static ZonedDateTime getZonedDateTimeNow(String zoneId){
        Objects.requireNonNull(zoneId, "zoneId");
        return ZonedDateTime.now(ZoneId.of(zoneId));
    }
    
    /**
     * 时区转换计算
     * @param zonedDateTime
     * @param zoneId 例如 Asia/Shanghai
     * @return
     */
    public static ZonedDateTime transform(ZonedDateTime zonedDateTime, String zoneId){
        Objects.requireNonNull(zoneId, "zoneId");
        return transform(zonedDateTime, ZoneId.of(zoneId));
    }
    
    /**
     * 时区转换计算
     * @param zonedDateTime
     * @param zone
     * @return
     */
    public static ZonedDateTime transform(ZonedDateTime zonedDateTime, ZoneId zone){
        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
        Objects.requireNonNull(zone, "zone");
        return zonedDateTime.withZoneSameInstant(zone);
    }

 

测试代码:

    /**
     * 时区时间计算
     */
    @Test
    public void zonedDateTimeTest(){
        //系统默认时区
        System.out.println(DateTimeCalculatorUtil.getZonedDateTimeNowOfDefault());
        //系统上海时区
        ZonedDateTime shanghaiZonedDateTime = DateTimeCalculatorUtil.getZonedDateTimeNowOfShanghai();
        System.out.println(shanghaiZonedDateTime);
        //系统巴黎时区
        ZonedDateTime parisZonedDateTime = DateTimeCalculatorUtil.getZonedDateTimeNowOfParis();
        System.out.println(parisZonedDateTime);
        //系统美国东部时区纽约时间
        System.out.println(DateTimeCalculatorUtil.getZonedDateTimeNowOfEST());
        //系统东京时区
        System.out.println(DateTimeCalculatorUtil.getZonedDateTimeNowOfTokyo());
        
        //上海时区,转换为巴黎时区
        System.out.println("============transform 时区转换=============");
        System.out.println("shanghaiZonedDateTime: "+shanghaiZonedDateTime);
        ZonedDateTime transformZonedDateTime = DateTimeCalculatorUtil.transform(shanghaiZonedDateTime,
                ZoneIdEnum.ECT.getZoneIdName());
        System.out.println("transformZonedDateTime: "+transformZonedDateTime);
        
    }

 

输出:

2020-02-19T13:40:49.638+08:00[Asia/Shanghai]
2020-02-19T13:40:49.640+08:00[Asia/Shanghai]
2020-02-19T06:40:49.642+01:00[Europe/Paris]
2020-02-19T00:40:49.653-05:00
2020-02-19T14:40:49.653+09:00[Asia/Tokyo]
============transform 时区转换=============
shanghaiZonedDateTime: 2020-02-19T13:40:49.640+08:00[Asia/Shanghai]
transformZonedDateTime: 2020-02-19T06:40:49.640+01:00[Europe/Paris]

 

2.4 时区时间格式化与解析

(1)时区时间格式化和ISO常用格式化,比如:yyyy-MM-dd’T’HH:mm:ssZ

    /**
     * 时区时间格式化和ISO常用格式化
     * YYYY_MM_DD_T_HH_MM_SS_Z = "yyyy-MM-dd'T'HH:mm:ssZ"
     */
    @Test
    public void zonedDateTimeFormatTest(){
        //默认为系统时区
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        //2020-02-18T22:37:55+0800
        System.out.println(DateTimeFormatterUtil.format(zonedDateTime, DateTimeFormatterUtil.YYYY_MM_DD_T_HH_MM_SS_Z_FMT));
        
        System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_DATE_FMT));
        System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_DATE_TIME_FMT));
        System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_INSTANT_FMT));
        System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_LOCAL_DATE_FMT));
        System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_LOCAL_DATE_TIME_FMT));
        System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_LOCAL_TIME_FMT));
        
        System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_TIME_FMT));
        System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_WEEK_DATE_FMT));
        System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_ZONED_DATE_TIME_FMT));
        System.out.println(zonedDateTime.format(DateTimeFormatterUtil.BASIC_ISO_DATE_FMT));
    }

 

输出:

2020-02-19T13:47:13+0800
2020-02-19+08:00
2020-02-19T13:47:13.271+08:00[Asia/Shanghai]
2020-02-19T05:47:13.271Z
2020-02-19
2020-02-19T13:47:13.271
13:47:13.271
13:47:13.271+08:00
2020-W08-3+08:00
2020-02-19T13:47:13.271+08:00[Asia/Shanghai]
20200219+0800

 

(2)时区时间解析

    /**
     * 时区时间解析
     * YYYY_MM_DD_T_HH_MM_SS_Z = "yyyy-MM-dd'T'HH:mm:ssZ"
     */
    @Test
    public void parseToZonedDateTimeTest(){
        String text = "2020-02-18T22:37:55+0800";
        ZonedDateTime zonedDateTime = DateTimeFormatterUtil.parseToZonedDateTime(text, DateTimeFormatterUtil.YYYY_MM_DD_T_HH_MM_SS_Z_FMT);
        System.out.println(zonedDateTime);
        
        String text2 = "2020-02-19T12:30:25.121+08:00[Asia/Shanghai]";
        ZonedDateTime zonedDateTime2 = DateTimeFormatterUtil.parseToZonedDateTime(text2, DateTimeFormatterUtil.ISO_ZONED_DATE_TIME_FMT);
        System.out.println(zonedDateTime2);
        
        ZonedDateTime zonedDateTime3 = ZonedDateTime.parse(text2);
        System.out.println(zonedDateTime3);
    }

 

输出:

2020-02-18T22:37:55+08:00
2020-02-19T12:30:25.121+08:00[Asia/Shanghai]
2020-02-19T12:30:25.121+08:00[Asia/Shanghai]

 

源代码地址:https://github.com/xkzhangsan/xk-time

部分参考:

https://www.cnblogs.com/xwdreamer/p/8761825.html

 

Java日期时间API系列18—–Jdk8中java.time包中的新的日期时间API类,java日期计算5,其他常用日期计算,星期计算,闰年计算等

  通过Java日期时间API系列8—–Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析中可以看出,java8中的方法特别丰富,一些常用的计算如星期计算,闰年计算等等。

下面是应用代码:

    /**
     * 获取星期值 1-7,星期一到星期日
     * @param date
     * @return
     */
    public static int getDayOfWeek(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).getDayOfWeek().getValue();
    }
    
    /**
     * 获取星期值 1-7,星期一到星期日
     * @param localDateTime
     * @return
     */
    public static int getDayOfWeek(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.getDayOfWeek().getValue();
    }
    
    /**
     * 获取星期值 1-7,星期一到星期日
     * @param instant
     * @return
     */
    public static int getDayOfWeek(Instant instant){
        return DateTimeConverterUtil.toLocalDateTime(instant).getDayOfWeek().getValue();
    }
    
    /**
     * 获取星期值当前月的最后一天
     * @param localDate
     * @return
     */
    public static LocalDate lastDayOfMonth(LocalDate localDate){
        Objects.requireNonNull(localDate, "localDate");
        return localDate.with(TemporalAdjusters.lastDayOfMonth());
    }
    
    /**
     * 获取星期值当前月的最后一天
     * @param localDateTime
     * @return
     */
    public static LocalDateTime lastDayOfMonth(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.with(TemporalAdjusters.lastDayOfMonth());
    }    
    
    /**
     * 获取星期值当前月的最后一天
     * @param date
     * @return
     */
    public static Date lastDayOfMonth(Date date){
        return DateTimeConverterUtil.toDate(DateTimeConverterUtil.toLocalDate(date).with(TemporalAdjusters.lastDayOfMonth()));
    }    
    
    /**
     * 判断是否闰年
     * @param localDate
     * @return
     */
    public static boolean isLeapYear(LocalDate localDate){
        Objects.requireNonNull(localDate, "localDate");
        return localDate.isLeapYear();
    }
    
    /**
     * 判断是否闰年
     * @param localDateTime
     * @return
     */
    public static boolean isLeapYear(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.toLocalDate().isLeapYear();
    }
    
    /**
     * 判断是否闰年
     * @param date
     * @return
     */
    public static boolean isLeapYear(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).toLocalDate().isLeapYear();
    }
    
    /**
     * 获取月的天数
     * @param localDate
     * @return
     */
    public static int lengthOfMonth(LocalDate localDate){
        Objects.requireNonNull(localDate, "localDate");
        return localDate.lengthOfMonth();
    }
    
    /**
     * 获取月的天数
     * @param localDateTime
     * @return
     */
    public static int lengthOfMonth(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.toLocalDate().lengthOfMonth();
    }
    
    /**
     * 获取月的天数
     * @param date
     * @return
     */
    public static int lengthOfMonth(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).toLocalDate().lengthOfMonth();
    }
    
    /**
     *  获取年的天数
     * @param localDate
     * @return
     */
    public static int lengthOfYear(LocalDate localDate){
        Objects.requireNonNull(localDate, "localDate");
        return localDate.lengthOfYear();
    }
    
    /**
     * 获取年的天数
     * @param localDateTime
     * @return
     */
    public static int lengthOfYear(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.toLocalDate().lengthOfYear();
    }
    
    /**
     * 获取年的天数
     * @param date
     * @return
     */
    public static int lengthOfYear(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).toLocalDate().lengthOfYear();
    }    
    
    /**
     * 下一个星期几
     * @param localDate
     * @param dayOfWeek
     * @return
     */
    public static LocalDate next(LocalDate localDate, DayOfWeek dayOfWeek){
        Objects.requireNonNull(localDate, "localDate");
        return localDate.with(TemporalAdjusters.next(dayOfWeek));
    }
    
    /**
     * 下一个星期几
     * @param localDateTime
     * @param dayOfWeek
     * @return
     */
    public static LocalDateTime next(LocalDateTime localDateTime, DayOfWeek dayOfWeek){
        return localDateTime.with(TemporalAdjusters.next(dayOfWeek));
    }

    /**
     * 下一个星期几
     * @param date
     * @param dayOfWeek
     * @return
     */
    public static Date next(Date date, DayOfWeek dayOfWeek){
        return DateTimeConverterUtil.toDate(DateTimeConverterUtil.toLocalDate(date).with(TemporalAdjusters.next(dayOfWeek)));
    }
    
    
    /**
     * 上一个星期几
     * @param localDate
     * @param dayOfWeek
     * @return
     */
    public static LocalDate previous(LocalDate localDate, DayOfWeek dayOfWeek){
        Objects.requireNonNull(localDate, "localDate");
        return localDate.with(TemporalAdjusters.previous(dayOfWeek));
    }
    
    /**
     * 上一个星期几
     * @param localDateTime
     * @param dayOfWeek
     * @return
     */
    public static LocalDateTime previous(LocalDateTime localDateTime, DayOfWeek dayOfWeek){
        return localDateTime.with(TemporalAdjusters.previous(dayOfWeek));
    }

    /**
     * 上一个星期几
     * @param date
     * @param dayOfWeek
     * @return
     */
    public static Date previous(Date date, DayOfWeek dayOfWeek){
        return DateTimeConverterUtil.toDate(DateTimeConverterUtil.toLocalDate(date).with(TemporalAdjusters.previous(dayOfWeek)));
    }
    
    /**
     * 获下一个工作日
     * @param localDate
     * @return
     */
    public static LocalDate nextWorkDay(LocalDate localDate){
        Objects.requireNonNull(localDate, "localDate");
        return localDate.with(TemporalAdjusterExtension.nextWorkDay());
    }
    
    /**
     * 获下一个工作日
     * @param localDateTime
     * @return
     */
    public static LocalDateTime nextWorkDay(LocalDateTime localDateTime){
        Objects.requireNonNull(localDateTime, "localDateTime");
        return localDateTime.with(TemporalAdjusterExtension.nextWorkDay());
    }
    
    /**
     * 获下一个工作日
     * @param date
     * @return
     */
    public static Date nextWorkDay(Date date){
        return DateTimeConverterUtil.toDate(DateTimeConverterUtil.toLocalDate(date).with(TemporalAdjusterExtension.nextWorkDay()));
    }

 

测试代码:

 

    /**
     * Date其他常用计算
     */
    @Test
    public void dateCalculatorOtherTest(){
        Date date = new Date();
        System.out.println(date);
        System.out.println(DateTimeConverterUtil.toLocalDateTime(date));
        //获取星期值
        System.out.println(DateTimeCalculatorUtil.getDayOfWeek(date));
        //获取星期值当前月的最后一天
        System.out.println(DateTimeCalculatorUtil.lastDayOfMonth(date));
        //判断是否闰年
        System.out.println(DateTimeCalculatorUtil.isLeapYear(date));
        //获取月的天数
        System.out.println(DateTimeCalculatorUtil.lengthOfMonth(date));
        //获取月的天数
        System.out.println(DateTimeCalculatorUtil.lengthOfYear(date));
        //下一个星期一
        System.out.println(DateTimeCalculatorUtil.next(date, DayOfWeek.MONDAY));
        //上一个星期一
        System.out.println(DateTimeCalculatorUtil.previous(date, DayOfWeek.MONDAY));
        //获下一个工作日
        System.out.println(DateTimeCalculatorUtil.nextWorkDay(date));
    }
    
    /**
     * LocalDateTime其他常用计算
     */
    @Test
    public void dateCalculatorOtherTest2(){
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);
        
        //获取星期值
        System.out.println(DateTimeCalculatorUtil.getDayOfWeek(ldt));
        //获取星期值当前月的最后一天
        System.out.println(DateTimeCalculatorUtil.lastDayOfMonth(ldt));
        //判断是否闰年
        System.out.println(DateTimeCalculatorUtil.isLeapYear(ldt));
        //获取月的天数
        System.out.println(DateTimeCalculatorUtil.lengthOfMonth(ldt));
        //获取月的天数
        System.out.println(DateTimeCalculatorUtil.lengthOfYear(ldt));
        //下一个星期一
        System.out.println(DateTimeCalculatorUtil.next(ldt, DayOfWeek.MONDAY));
        //上一个星期一
        System.out.println(DateTimeCalculatorUtil.previous(ldt, DayOfWeek.MONDAY));
        //获下一个工作日
        System.out.println(DateTimeCalculatorUtil.nextWorkDay(ldt));
    }

 

测试结果:

Fri Feb 07 18:34:40 CST 2020
2020-02-07T18:34:40.887
5
Sat Feb 29 00:00:00 CST 2020
true
29
366
Mon Feb 10 00:00:00 CST 2020
Mon Feb 03 00:00:00 CST 2020
Mon Feb 10 00:00:00 CST 2020




2020-02-07T18:34:56.421
5
2020-02-29T18:34:56.421
true
29
366
2020-02-10T18:34:56.421
2020-02-03T18:34:56.421
2020-02-10T18:34:56.421

 

源代码地址:https://github.com/xkzhangsan/xk-time