Java日期时间API系列17—–Jdk8中java.time包中的新的日期时间API类,java日期计算4,2个日期对比,获取相差年月日部分属性和相差总的天时分秒毫秒纳秒等

通过Java日期时间API系列9—–Jdk8中java.time包中的新的日期时间API类的Period和Duration的区别 ,可以看出java8设计非常好,新增了Period和Duration类,专用于对比2个时间场景:

Period,可以获取2个时间相差的年月日的属性。

Duration,可以获取2个时间相差总的天时分秒毫秒纳秒。

 

 

下面应用:

    /**
     * 获取2个日期的相差年月天的年数部分
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenYears(LocalDateTime startInclusive, LocalDateTime endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return Period.between(DateTimeConverterUtil.toLocalDate(startInclusive),
                DateTimeConverterUtil.toLocalDate(endExclusive)).getYears();
    }
    
    /**
     * 获取2个日期的相差年月天的年数部分
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenYears(Date startInclusive, Date endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return Period.between(DateTimeConverterUtil.toLocalDate(startInclusive),
                DateTimeConverterUtil.toLocalDate(endExclusive)).getYears();
    }
    
    /**
     * 获取2个日期的相差年月天的年数部分
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenYears(LocalDate startInclusive, LocalDate endExclusive){
        return Period.between(startInclusive, endExclusive).getYears();
    }
    
    /**
     * 获取2个日期的相差年月天的月数部分
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenMonths(LocalDateTime startInclusive, LocalDateTime endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return Period.between(DateTimeConverterUtil.toLocalDate(startInclusive),
                DateTimeConverterUtil.toLocalDate(endExclusive)).getMonths();
    }
    
    /**
     * 获取2个日期的相差年月天的月数部分
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenMonths(Date startInclusive, Date endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return Period.between(DateTimeConverterUtil.toLocalDate(startInclusive),
                DateTimeConverterUtil.toLocalDate(endExclusive)).getMonths();
    }
    
    /**
     * 获取2个日期的相差年月天的月数部分
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenMonths(LocalDate startInclusive, LocalDate endExclusive){
        return Period.between(startInclusive, endExclusive).getMonths();
    }
    
    /**
     * 获取2个日期的相差年月天的天数部分
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenDays(LocalDateTime startInclusive, LocalDateTime endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return Period.between(DateTimeConverterUtil.toLocalDate(startInclusive),
                DateTimeConverterUtil.toLocalDate(endExclusive)).getDays();
    }
    
    /**
     * 获取2个日期的相差年月天的天数部分
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenDays(Date startInclusive, Date endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return Period.between(DateTimeConverterUtil.toLocalDate(startInclusive),
                DateTimeConverterUtil.toLocalDate(endExclusive)).getDays();
    }
    
    /**
     * 获取2个日期的相差年月天的天数部分
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenDays(LocalDate startInclusive, LocalDate endExclusive){
        return Period.between(startInclusive, endExclusive).getDays();
    }
    
    /**
     * 获取2个日期的相差总天数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalDays(LocalDateTime startInclusive, LocalDateTime endExclusive){
        return Duration.between(startInclusive, endExclusive).toDays();
    }
    
    /**
     * 获取2个日期的相差总天数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalDays(Date startInclusive, Date endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return durationBetween(DateTimeConverterUtil.toLocalDateTime(startInclusive), DateTimeConverterUtil.toLocalDateTime(endExclusive)).toDays();
    }
    
    /**
     * 获取2个日期的相差总小时数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalHours(LocalDateTime startInclusive, LocalDateTime endExclusive){
        return Duration.between(startInclusive, endExclusive).toHours();
    }
    
    /**
     * 获取2个日期的相差总小时数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalHours(LocalTime startInclusive, LocalTime endExclusive){
        return Duration.between(startInclusive, endExclusive).toHours();
    }
    
    /**
     * 获取2个日期的相差总小时数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalHours(Date startInclusive, Date endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return durationBetween(DateTimeConverterUtil.toLocalDateTime(startInclusive), DateTimeConverterUtil.toLocalDateTime(endExclusive)).toHours();
    }
    
    /**
     * 获取2个日期的相差总分钟数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalMinutes(LocalDateTime startInclusive, LocalDateTime endExclusive){
        return Duration.between(startInclusive, endExclusive).toMinutes();
    }
    
    /**
     * 获取2个日期的相差总分钟数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalMinutes(LocalTime startInclusive, LocalTime endExclusive){
        return Duration.between(startInclusive, endExclusive).toMinutes();
    }
    
    /**
     * 获取2个日期的相差总分钟数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalMinutes(Date startInclusive, Date endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return durationBetween(DateTimeConverterUtil.toLocalDateTime(startInclusive), DateTimeConverterUtil.toLocalDateTime(endExclusive)).toMinutes();
    }
    
    /**
     * 获取2个日期的相差总秒数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalSeconds(LocalDateTime startInclusive, LocalDateTime endExclusive){
        return Duration.between(startInclusive, endExclusive).getSeconds();
    }
    
    /**
     * 获取2个日期的相差总秒数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalSeconds(LocalTime startInclusive, LocalTime endExclusive){
        return Duration.between(startInclusive, endExclusive).getSeconds();
    }
    
    /**
     * 获取2个日期的相差总秒数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalSeconds(Date startInclusive, Date endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return durationBetween(DateTimeConverterUtil.toLocalDateTime(startInclusive), DateTimeConverterUtil.toLocalDateTime(endExclusive)).getSeconds();
    }
    
    /**
     * 获取2个日期的相差总毫秒数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalMillis(LocalDateTime startInclusive, LocalDateTime endExclusive){
        return Duration.between(startInclusive, endExclusive).toMillis();
    }
    
    /**
     * 获取2个日期的相差总毫秒数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalMillis(LocalTime startInclusive, LocalTime endExclusive){
        return Duration.between(startInclusive, endExclusive).toMillis();
    }
    
    /**
     * 获取2个日期的相差总毫秒数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalMillis(Date startInclusive, Date endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return durationBetween(DateTimeConverterUtil.toLocalDateTime(startInclusive), DateTimeConverterUtil.toLocalDateTime(endExclusive)).toMillis();
    }    
    
    /**
     * 获取2个日期的相差总纳秒数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalNanos(LocalDateTime startInclusive, LocalDateTime endExclusive){
        return Duration.between(startInclusive, endExclusive).toNanos();
    }
    
    /**
     * 获取2个日期的相差总纳秒数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalNanos(LocalTime startInclusive, LocalTime endExclusive){
        return Duration.between(startInclusive, endExclusive).toNanos();
    }
    
    /**
     * 获取2个日期的相差总纳秒数
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long betweenTotalNanos(Date startInclusive, Date endExclusive){
        Objects.requireNonNull(startInclusive, "startInclusive");
        Objects.requireNonNull(endExclusive, "endExclusive");
        return durationBetween(DateTimeConverterUtil.toLocalDateTime(startInclusive), DateTimeConverterUtil.toLocalDateTime(endExclusive)).toNanos();
    }

 

测试代码

    /**
     * 使用Period比较2个LocalDate
     */
    @Test
    public void dateCalculatorPeriodBetweenTest(){
        LocalDate localDate = LocalDate.now();
        LocalDate localDate2 = LocalDate.of(2021, 3, 7);
        System.out.println(localDate);
        System.out.println(localDate2);
        
        System.out.println(DateTimeCalculatorUtil.betweenYears(localDate, localDate2));
        System.out.println(DateTimeCalculatorUtil.betweenMonths(localDate, localDate2));
        System.out.println(DateTimeCalculatorUtil.betweenDays(localDate, localDate2));
    }
    
    /**
     * 使用Period比较2个Date
     */
    @Test
    public void dateCalculatorPeriodBetweenTest2(){
        Date date = new Date();
        LocalDate localDate2 = LocalDate.of(2021, 3, 7);
        Date date2 = DateTimeConverterUtil.toDate(localDate2);
        System.out.println(date);
        System.out.println(date2);
        
        System.out.println(DateTimeCalculatorUtil.betweenYears(date, date2));
        System.out.println(DateTimeCalculatorUtil.betweenMonths(date, date2));
        System.out.println(DateTimeCalculatorUtil.betweenDays(date, date2));
    }
    
    /**
     * 使用Duration比较2个LocalDateTime
     */
    @Test
    public void dateCalculatorDurationBetweenTest(){
        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDateTime localDateTime2 = LocalDateTime.of(2021, 3, 7, 22, 10, 10);
        System.out.println(localDateTime);
        System.out.println(localDateTime2);
        
        System.out.println(DateTimeCalculatorUtil.betweenTotalDays(localDateTime, localDateTime2));
        System.out.println(DateTimeCalculatorUtil.betweenTotalHours(localDateTime, localDateTime2));
        System.out.println(DateTimeCalculatorUtil.betweenTotalMinutes(localDateTime, localDateTime2));
        System.out.println(DateTimeCalculatorUtil.betweenTotalSeconds(localDateTime, localDateTime2));
        System.out.println(DateTimeCalculatorUtil.betweenTotalMillis(localDateTime, localDateTime2));
        System.out.println(DateTimeCalculatorUtil.betweenTotalNanos(localDateTime, localDateTime2));
    }
    
    /**
     * 使用Duration比较2个Date
     */
    @Test
    public void dateCalculatorDurationBetweenTest2(){
        Date date = new Date();
        LocalDate localDate2 = LocalDate.of(2021, 3, 7);
        Date date2 = DateTimeConverterUtil.toDate(localDate2);
        System.out.println(date);
        System.out.println(date2);
        
        System.out.println(DateTimeCalculatorUtil.betweenTotalDays(date, date2));
        System.out.println(DateTimeCalculatorUtil.betweenTotalHours(date, date2));
        System.out.println(DateTimeCalculatorUtil.betweenTotalMinutes(date, date2));
        System.out.println(DateTimeCalculatorUtil.betweenTotalSeconds(date, date2));
        System.out.println(DateTimeCalculatorUtil.betweenTotalMillis(date, date2));
        System.out.println(DateTimeCalculatorUtil.betweenTotalNanos(date, date2));
    }

 

测试结果:

2020-02-06
2021-03-07
1
1
1



Thu Feb 06 22:09:38 CST 2020
Sun Mar 07 00:00:00 CST 2021
1
1
1


2020-02-06T22:09:48.247
2021-03-07T22:10:10
395
9480
568800
34128021
34128021753
34128021753000000


Thu Feb 06 22:09:58 CST 2020
Sun Mar 07 00:00:00 CST 2021
394
9457
567470
34048201
34048201995
34048201995000000

 

 

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

Java日期时间API系列16—–Jdk8中java.time包中的新的日期时间API类,java日期计算3,日期中年月日时分秒的属性值修改等

  通过Java日期时间API系列8—–Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析 ,可以看出java8设计非常好,实现接口Temporal, TemporalAdjuster, ChronoLocalDate等,有非常丰富的方法。例如:LocalDateTime:的部分方法:

 

 

包含了年月日,时分秒的属性值修改。Date中如果要进行属性值修改,必须使用Calendar才可以。现在通过将Date转换为LocalDateTime,就能非常方便,线程安全的年月日,时分秒等属性值修改。

// modify property

public static Date withYear(Date date, long newValue){
return with(date, ChronoField.YEAR, newValue);
}

public static LocalDateTime withYear(LocalDateTime localDateTime, long newValue){
return (LocalDateTime) with(localDateTime, ChronoField.YEAR, newValue);
}

public static LocalDate withYear(LocalDate localDate, long newValue){
return (LocalDate) with(localDate, ChronoField.YEAR, newValue);
}

public static Date withMonth(Date date, long newValue){
return with(date, ChronoField.MONTH_OF_YEAR, newValue);
}

public static LocalDateTime withMonth(LocalDateTime localDateTime, long newValue){
return (LocalDateTime) with(localDateTime, ChronoField.MONTH_OF_YEAR, newValue);
}

public static LocalDate withMonth(LocalDate localDate, long newValue){
return (LocalDate) with(localDate, ChronoField.MONTH_OF_YEAR, newValue);
}

public static Date withDayOfMonth(Date date, long newValue){
return with(date, ChronoField.DAY_OF_MONTH, newValue);
}

public static LocalDateTime withDayOfMonth(LocalDateTime localDateTime, long newValue){
return (LocalDateTime) with(localDateTime, ChronoField.DAY_OF_MONTH, newValue);
}

public static LocalDate withDayOfMonth(LocalDate localDate, long newValue){
return (LocalDate) with(localDate, ChronoField.DAY_OF_MONTH, newValue);
}

public static Date withDayOfYear(Date date, long newValue){
return with(date, ChronoField.DAY_OF_YEAR, newValue);
}

public static LocalDateTime withDayOfYear(LocalDateTime localDateTime, long newValue){
return (LocalDateTime) with(localDateTime, ChronoField.DAY_OF_YEAR, newValue);
}

public static LocalDate withDayOfYear(LocalDate localDate, long newValue){
return (LocalDate) with(localDate, ChronoField.DAY_OF_YEAR, newValue);
}

public static Date withHour(Date date, long newValue){
return with(date, ChronoField.HOUR_OF_DAY, newValue);
}

public static LocalDateTime withHour(LocalDateTime localDateTime, long newValue){
return (LocalDateTime) with(localDateTime, ChronoField.HOUR_OF_DAY, newValue);
}

public static LocalTime withHour(LocalTime localTime, long newValue){
return (LocalTime) with(localTime, ChronoField.HOUR_OF_DAY, newValue);
}

public static Date withMinute(Date date, long newValue){
return with(date, ChronoField.MINUTE_OF_HOUR, newValue);
}

public static LocalDateTime withMinute(LocalDateTime localDateTime, long newValue){
return (LocalDateTime) with(localDateTime, ChronoField.MINUTE_OF_HOUR, newValue);
}

public static LocalTime withMinute(LocalTime localTime, long newValue){
return (LocalTime) with(localTime, ChronoField.MINUTE_OF_HOUR, newValue);
}

public static Date withSecond(Date date, long newValue){
return with(date, ChronoField.SECOND_OF_MINUTE, newValue);
}

public static LocalDateTime withSecond(LocalDateTime localDateTime, long newValue){
return (LocalDateTime) with(localDateTime, ChronoField.SECOND_OF_MINUTE, newValue);
}

public static LocalTime withSecond(LocalTime localTime, long newValue){
return (LocalTime) with(localTime, ChronoField.SECOND_OF_MINUTE, newValue);
}

 

测试类:

@Test
public void dateCalculatorWithTest(){
Date date = new Date();
System.out.println(date);
System.out.println(DateTimeConverterUtil.toLocalDateTime(date));
System.out.println(DateTimeCalculatorUtil.getDayOfYear(date));

System.out.println(DateTimeCalculatorUtil.withYear(date, 2021));
System.out.println(DateTimeCalculatorUtil.withMonth(date, 3));
System.out.println(DateTimeCalculatorUtil.withDayOfMonth(date, 6));
System.out.println(DateTimeCalculatorUtil.withDayOfYear(date, 37));
System.out.println(DateTimeCalculatorUtil.withHour(date, 17));
System.out.println(DateTimeCalculatorUtil.withMinute(date, 30));
System.out.println(DateTimeCalculatorUtil.withSecond(date, 30));
}

@Test
public void dateCalculatorWithTest2(){
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
System.out.println(ldt.getDayOfYear());

System.out.println(DateTimeCalculatorUtil.withYear(ldt, 2021));
System.out.println(DateTimeCalculatorUtil.withMonth(ldt, 3));
System.out.println(DateTimeCalculatorUtil.withDayOfMonth(ldt, 6));
System.out.println(DateTimeCalculatorUtil.withDayOfYear(ldt, 37));
System.out.println(DateTimeCalculatorUtil.withHour(ldt, 17));
System.out.println(DateTimeCalculatorUtil.withMinute(ldt, 30));
System.out.println(DateTimeCalculatorUtil.withSecond(ldt, 30));
}

 

输出:

Wed Feb 05 16:20:47 CST 2020
2020-02-05T16:20:47.955
36
Fri Feb 05 16:20:47 CST 2021
Thu Mar 05 16:20:47 CST 2020
Thu Feb 06 16:20:47 CST 2020
Thu Feb 06 16:20:47 CST 2020
Wed Feb 05 17:20:47 CST 2020
Wed Feb 05 16:30:47 CST 2020
Wed Feb 05 16:20:30 CST 2020

 

 

2020-02-05T16:21:03.760
36
2021-02-05T16:21:03.760
2020-03-05T16:21:03.760
2020-02-06T16:21:03.760
2020-02-06T16:21:03.760
2020-02-05T17:21:03.760
2020-02-05T16:30:03.760
2020-02-05T16:21:30.760

 

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

 

Java日期时间API系列15—–Jdk8中java.time包中的新的日期时间API类,java日期计算2,年月日时分秒的加减等

  通过Java日期时间API系列8—–Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析 ,可以看出java8设计非常好,实现接口Temporal, TemporalAdjuster, ChronoLocalDate等,有非常丰富的方法。例如:LocalDateTime:的部分方法:

  

 

包含了年月日,时分秒的加和减。Date中如果要进行加减,必须使用Calendar才可以。现在通过将Date转换为LocalDateTime,就能非常方便,线程安全的加减年月日,时分秒等信息。

	// plus two times
	
	public static Date plusYears(Date date, long amountToAdd){
		return plus(date, ChronoUnit.YEARS, amountToAdd);
	}
	
	public static LocalDateTime plusYears(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) plus(localDateTime, ChronoUnit.YEARS, amountToAdd);
	}
	
	public static LocalDate plusYears(LocalDate localDate, long amountToAdd){
		return (LocalDate) plus(localDate, ChronoUnit.YEARS, amountToAdd);
	}
	
	public static Date plusMonths(Date date, long amountToAdd){
		return plus(date, ChronoUnit.MONTHS, amountToAdd);
	}
	
	public static LocalDateTime plusMonths(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) plus(localDateTime, ChronoUnit.MONTHS, amountToAdd);
	}
	
	public static LocalDate plusMonths(LocalDate localDate, long amountToAdd){
		return (LocalDate) plus(localDate, ChronoUnit.MONTHS, amountToAdd);
	}
	
	public static Date plusWeeks(Date date, long amountToAdd){
		return plus(date, ChronoUnit.WEEKS, amountToAdd);
	}
	
	public static LocalDateTime plusWeeks(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) plus(localDateTime, ChronoUnit.WEEKS, amountToAdd);
	}
	
	public static LocalDate plusWeeks(LocalDate localDate, long amountToAdd){
		return (LocalDate) plus(localDate, ChronoUnit.WEEKS, amountToAdd);
	}	
	
	public static Date plusDays(Date date, long amountToAdd){
		return plus(date, ChronoUnit.DAYS, amountToAdd);
	}
	
	public static LocalDateTime plusDays(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) plus(localDateTime, ChronoUnit.DAYS, amountToAdd);
	}
	
	public static LocalDate plusDays(LocalDate localDate, long amountToAdd){
		return (LocalDate) plus(localDate, ChronoUnit.DAYS, amountToAdd);
	}
	
	public static Date plusHours(Date date, long amountToAdd){
		return plus(date, ChronoUnit.HOURS, amountToAdd);
	}
	
	public static LocalDateTime plusHours(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) plus(localDateTime, ChronoUnit.HOURS, amountToAdd);
	}
	
	public static LocalTime plusHours(LocalTime localTime, long amountToAdd){
		return (LocalTime) plus(localTime, ChronoUnit.HOURS, amountToAdd);
	}
	
	public static Date plusMinutes(Date date, long amountToAdd){
		return plus(date, ChronoUnit.MINUTES, amountToAdd);
	}
	
	public static LocalDateTime plusMinutes(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) plus(localDateTime, ChronoUnit.MINUTES, amountToAdd);
	}
	
	public static LocalTime plusMinutes(LocalTime localTime, long amountToAdd){
		return (LocalTime) plus(localTime, ChronoUnit.MINUTES, amountToAdd);
	}
	
	public static Date plusSeconds(Date date, long amountToAdd){
		return plus(date, ChronoUnit.SECONDS, amountToAdd);
	}
	
	public static LocalDateTime plusSeconds(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) plus(localDateTime, ChronoUnit.SECONDS, amountToAdd);
	}
	
	public static LocalTime plusSeconds(LocalTime localTime, long amountToAdd){
		return (LocalTime) plus(localTime, ChronoUnit.SECONDS, amountToAdd);
	}	
	
	// minus two times
	
	public static Date minusYears(Date date, long amountToAdd){
		return minus(date, ChronoUnit.YEARS, amountToAdd);
	}
	
	public static LocalDateTime minusYears(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) minus(localDateTime, ChronoUnit.YEARS, amountToAdd);
	}
	
	public static LocalDate minusYears(LocalDate localDate, long amountToAdd){
		return (LocalDate) minus(localDate, ChronoUnit.YEARS, amountToAdd);
	}
	
	public static Date minusMonths(Date date, long amountToAdd){
		return minus(date, ChronoUnit.MONTHS, amountToAdd);
	}
	
	public static LocalDateTime minusMonths(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) minus(localDateTime, ChronoUnit.MONTHS, amountToAdd);
	}
	
	public static LocalDate minusMonths(LocalDate localDate, long amountToAdd){
		return (LocalDate) minus(localDate, ChronoUnit.MONTHS, amountToAdd);
	}
	
	public static Date minusWeeks(Date date, long amountToAdd){
		return minus(date, ChronoUnit.WEEKS, amountToAdd);
	}
	
	public static LocalDateTime minusWeeks(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) minus(localDateTime, ChronoUnit.WEEKS, amountToAdd);
	}
	
	public static LocalDate minusWeeks(LocalDate localDate, long amountToAdd){
		return (LocalDate) minus(localDate, ChronoUnit.WEEKS, amountToAdd);
	}	
	
	public static Date minusDays(Date date, long amountToAdd){
		return minus(date, ChronoUnit.DAYS, amountToAdd);
	}
	
	public static LocalDateTime minusDays(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) minus(localDateTime, ChronoUnit.DAYS, amountToAdd);
	}
	
	public static LocalDate minusDays(LocalDate localDate, long amountToAdd){
		return (LocalDate) minus(localDate, ChronoUnit.DAYS, amountToAdd);
	}
	
	public static Date minusHours(Date date, long amountToAdd){
		return minus(date, ChronoUnit.HOURS, amountToAdd);
	}
	
	public static LocalDateTime minusHours(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) minus(localDateTime, ChronoUnit.HOURS, amountToAdd);
	}
	
	public static LocalTime minusHours(LocalTime localTime, long amountToAdd){
		return (LocalTime) minus(localTime, ChronoUnit.HOURS, amountToAdd);
	}
	
	public static Date minusMinutes(Date date, long amountToAdd){
		return minus(date, ChronoUnit.MINUTES, amountToAdd);
	}
	
	public static LocalDateTime minusMinutes(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) minus(localDateTime, ChronoUnit.MINUTES, amountToAdd);
	}
	
	public static LocalTime minusMinutes(LocalTime localTime, long amountToAdd){
		return (LocalTime) minus(localTime, ChronoUnit.MINUTES, amountToAdd);
	}
	
	public static Date minusSeconds(Date date, long amountToAdd){
		return minus(date, ChronoUnit.SECONDS, amountToAdd);
	}
	
	public static LocalDateTime minusSeconds(LocalDateTime localDateTime, long amountToAdd){
		return (LocalDateTime) minus(localDateTime, ChronoUnit.SECONDS, amountToAdd);
	}
	
	public static LocalTime minusSeconds(LocalTime localTime, long amountToAdd){
		return (LocalTime) minus(localTime, ChronoUnit.SECONDS, amountToAdd);
	}

 

测试类:

@Test
	public void dateCalculatorPlusTest(){
		Date date = new Date();
		System.out.println(date);
		System.out.println(DateTimeConverterUtil.toLocalDateTime(date));
		
		System.out.println(DateTimeCalculatorUtil.plusYears(date, 1));
		System.out.println(DateTimeCalculatorUtil.plusMonths(date, 1));
		System.out.println(DateTimeCalculatorUtil.plusWeeks(date, 1));
		System.out.println(DateTimeCalculatorUtil.plusDays(date, 1));
		System.out.println(DateTimeCalculatorUtil.plusHours(date, 1));
		System.out.println(DateTimeCalculatorUtil.plusMinutes(date, 1));
		System.out.println(DateTimeCalculatorUtil.plusSeconds(date, 1));
	}
	
	@Test
	public void dateCalculatorMinusTest(){
		Date date = new Date();
		System.out.println(date);
		System.out.println(DateTimeConverterUtil.toLocalDateTime(date));
		
		System.out.println(DateTimeCalculatorUtil.minusYears(date, 1));
		System.out.println(DateTimeCalculatorUtil.minusMonths(date, 1));
		System.out.println(DateTimeCalculatorUtil.minusWeeks(date, 1));
		System.out.println(DateTimeCalculatorUtil.minusDays(date, 1));
		System.out.println(DateTimeCalculatorUtil.minusHours(date, 1));
		System.out.println(DateTimeCalculatorUtil.minusMinutes(date, 1));
		System.out.println(DateTimeCalculatorUtil.minusSeconds(date, 1));
	}
	
	@Test
	public void dateCalculatorPlusTest2(){
		LocalDateTime ldt = LocalDateTime.now();
		System.out.println(ldt);
		
		System.out.println(DateTimeCalculatorUtil.plusYears(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.plusMonths(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.plusWeeks(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.plusDays(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.plusHours(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.plusMinutes(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.plusSeconds(ldt, 1));
	}
	
	@Test
	public void dateCalculatorMinusTest2(){
		LocalDateTime ldt = LocalDateTime.now();
		System.out.println(ldt);
		
		System.out.println(DateTimeCalculatorUtil.minusYears(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.minusMonths(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.minusWeeks(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.minusDays(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.minusHours(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.minusMinutes(ldt, 1));
		System.out.println(DateTimeCalculatorUtil.minusSeconds(ldt, 1));
	}

 

输出:

Wed Feb 05 14:27:30 CST 2020
2020-02-05T14:27:30.398
Fri Feb 05 14:27:30 CST 2021
Thu Mar 05 14:27:30 CST 2020
Wed Feb 12 14:27:30 CST 2020
Thu Feb 06 14:27:30 CST 2020
Wed Feb 05 15:27:30 CST 2020
Wed Feb 05 14:28:30 CST 2020
Wed Feb 05 14:27:31 CST 2020

 

 

Wed Feb 05 14:27:43 CST 2020

2020-02-05T14:27:43.498

Tue Feb 05 14:27:43 CST 2019

Sun Jan 05 14:27:43 CST 2020

Wed Jan 29 14:27:43 CST 2020

Tue Feb 04 14:27:43 CST 2020

Wed Feb 05 13:27:43 CST 2020

Wed Feb 05 14:26:43 CST 2020

Wed Feb 05 14:27:42 CST 2020

 

 

 

2020-02-05T14:27:54.747

2021-02-05T14:27:54.747

2020-03-05T14:27:54.747

2020-02-12T14:27:54.747

2020-02-06T14:27:54.747

2020-02-05T15:27:54.747

2020-02-05T14:28:54.747

2020-02-05T14:27:55.747

 

 

2020-02-05T14:27:54.747

2021-02-05T14:27:54.747

2020-03-05T14:27:54.747

2020-02-12T14:27:54.747

2020-02-06T14:27:54.747

2020-02-05T15:27:54.747

2020-02-05T14:28:54.747

2020-02-05T14:27:55.747

 

 

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

 

Java日期时间API系列14—–Jdk8中java.time包中的新的日期时间API类,java日期计算1,获取年月日时分秒等

  通过Java日期时间API系列8—–Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析 ,可以看出java8设计非常好,实现接口Temporal, TemporalAdjuster, ChronoLocalDate等,有非常丰富的方法。例如:LocalDateTime:的部分方法:

  

 

包含了获取年月日,时分秒纳秒。Date中如果要获取这些信息,必须使用Calendar才可以。现在通过将Date转换为LocalDateTime,就能非常方便,线程安全的获取年月日,时分秒等信息。

    public static int getYear(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).getYear();
    }
    
    public static int getYear(Instant instant){
        return DateTimeConverterUtil.toLocalDateTime(instant).getYear();
    }
    
    public static int getMonth(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).getMonthValue();
    }
    
    public static int getMonth(Instant instant){
        return DateTimeConverterUtil.toLocalDateTime(instant).getMonthValue();
    }
    
    public static int getDayOfMonth(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).getDayOfMonth();
    }
    
    public static int getDayOfMonth(Instant instant){
        return DateTimeConverterUtil.toLocalDateTime(instant).getDayOfMonth();
    }    
    
    public static int getHour(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).getHour();
    }
    
    public static int getHour(Instant instant){
        return DateTimeConverterUtil.toLocalDateTime(instant).getHour();
    }    
    
    public static int getMinute(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).getMinute();
    }
    
    public static int getMinute(Instant instant){
        return DateTimeConverterUtil.toLocalDateTime(instant).getMinute();
    }    
    
    public static int getSecond(Date date){
        return DateTimeConverterUtil.toLocalDateTime(date).getSecond();
    }
    
    public static int getSecond(Instant instant){
        return DateTimeConverterUtil.toLocalDateTime(instant).getSecond();
    }

 

测试类:

    @Test
    public void dateCalculatorGetTest(){
        Date date = new Date();
        System.out.println(date);
        System.out.println(DateTimeConverterUtil.toLocalDateTime(date));
        System.out.println(DateTimeCalculatorUtil.getYear(date));
        System.out.println(DateTimeCalculatorUtil.getMonth(date));
        System.out.println(DateTimeCalculatorUtil.getDayOfMonth(date));
        System.out.println(DateTimeCalculatorUtil.getHour(date));
        System.out.println(DateTimeCalculatorUtil.getMinute(date));
        System.out.println(DateTimeCalculatorUtil.getSecond(date));
    }

 

输出:

Sun Jan 12 22:24:07 CST 2020
2020-01-12T22:24:07.681
2020
1
12
22
24
7

 

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

Java日期时间API系列12—–Jdk8中java.time包中的新的日期时间API类,日期格式化,常用日期格式大全

  通过Java日期时间API系列10—–Jdk8中java.time包中的新的日期时间API类的DateTimeFormatter, 可以看出java8的DateTimeFormatter完美解决了SimpleDateFormat线程安全问题。下面是关于DateTimeFormatter的使用实例,包括常用日期格式大全,

以2020-01-01 00:00:00为例。

 

package com.xkzhangsan.time.test;

import java.time.LocalDateTime;
import java.util.Date;

import com.xkzhangsan.time.LunarDate;
import com.xkzhangsan.time.converter.DateTimeConverterUtil;
import com.xkzhangsan.time.formatter.DateTimeFormatterUtil;

public class NewYearFormatTest {

    public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTime.of(2020, 1, 1, 0, 0, 0);
        Date date = DateTimeConverterUtil.toDate(localDateTime);
        LunarDate lunarDate = LunarDate.from(localDateTime);
        System.out.println("=============================");
        System.out.println("Hello " + lunarDate.format());
        
        System.out.println("=============================");
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_CN_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_EN_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYYMM_FMT));
        
        System.out.println("=============================");
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_DD_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_DD_CN_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_DD_EN_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_DD_POINT_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_DD_E_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYYMMDD_FMT));
        
        System.out.println("=============================");
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_DD_HH_MM_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYYMMDDHHMM_FMT));
        
        System.out.println("=============================");
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_DD_HH_MM_SS_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_DD_HH_MM_SS_CN_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_DD_HH_MM_SS_A_CN_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYYMMDDHHMMSS_FMT));//22
        
        System.out.println("=============================");
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYY_MM_DD_HH_MM_SS_SSS_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.YYYYMMDDHHMMSSSSS_FMT));        
        
        System.out.println("=============================");
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.MM_DD_HH_MM_SS_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.MM_DD_HH_MM_SS_CN_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.MM_DD_HH_MM_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.MM_DD_HH_MM_CN_FMT));
        
        System.out.println("=============================");
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.MM_DD_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.MM_DD_CN_FMT));
        
        System.out.println("=============================");
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.HH_MM_SS_FMT));
        System.out.println(DateTimeFormatterUtil.format(date, DateTimeFormatterUtil.HHMMSS_FMT));
        System.out.println("=============================");
    }
}

 

输出:

=============================
Hello 己亥猪年 二〇一九年腊月初七 星期三
=============================
2020
2020-01
2020年01月
2020/01
202001
=============================
2020-01-01
2020年01月01日
2020/01/01
2020.01.01
2020-01-01 星期三
20200101
=============================
2020-01-01 00:00
202001010000
=============================
2020-01-01 00:00:00
2020年01月01日 00:00:00
2020年01月01日 00:00:00 上午
20200101000000
=============================
2020-01-01 00:00:00.000
20200101000000000
=============================
01-01 00:00:00
01月01日 00:00:00
01-01 00:00
01月01日 00:00
=============================
01-01
01月01日
=============================
00:00:00
000000
=============================

 

注意:上面代码中的 DateTimeFormatterUtil.YYYY_FMT中的YYYY_FMT是定义的常量,不是真正的转换格式模板,原代码中是小写的y:yyyy。YYYY会出现bug。

源码为:

    private static final String YYYY = "yyyy";
    /**
     * such as 2019
     */
    public static final DateTimeFormatter YYYY_FMT = DateTimeFormatter.ofPattern(YYYY).withZone(ZONE);

 

    /**
     * 根据 formatter格式化 date
     * @param date
     * @param formatter
     * @return
     */
    public static String format(Date date, DateTimeFormatter formatter){
        Objects.requireNonNull(formatter, "formatter");
        return DateTimeConverterUtil.toLocalDateTime(date).format(formatter);
    }

 

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

Java日期时间API系列11—–Jdk8中java.time包中的新的日期时间API类,使用java8日期时间API重写农历LunarDate

  通过Java日期时间API系列7—–Jdk8中java.time包中的新的日期时间API类的优点,java8具有很多优点,现在网上查到的农历转换工具类都是基于jdk7及以前的类写的,下面使用java新的日期时间API重写农历LunarDate。

 1. version 0.1版本 农历原始算法来自网络,有2个问题:

(1)com.xkzhangsan.time.LunarDate.lunarInfo 数据有误,导致个别农历计算不准确。

(2)没有二十四节气计算。

2.version 0.2版本修改了上面问题:

package com.xkzhangsan.time;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.util.Date;

import com.xkzhangsan.time.calculator.DateTimeCalculatorUtil;
import com.xkzhangsan.time.converter.DateTimeConverterUtil;
import com.xkzhangsan.time.holiday.ChineseHolidayEnum;

/**
 * 农历日期
 * 仅支持公历1901-2050年的农历转换
* @ClassName: LunarDate 
* @Description: LunarDate
* @author xkzhangsan
* @date 2019年12月30日
* @version 0.2 试用
 */
public final class LunarDate implements Temporal{
    
    /**
     * 农历信息
     */
    private static final long[] lunarInfo = new long[] { 0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554,
            0x056a0, 0x09ad0, 0x055d2, 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0,
            0x14977, 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, 0x06566,
            0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, 0x0d4a0, 0x1d8a6, 0x0b550,
            0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0,
            0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263,
            0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0,
            0x195a6, 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, 0x04af5,
            0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, 0x0c960, 0x0d954, 0x0d4a0,
            0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9,
            0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0,
            0x0d260, 0x0ea65, 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520,
            0x0dd45, 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0,
            0x14b63 };

    /**
     * 农历月份列表
     */
    public static final String[] lunarMonth = new String[] { "", "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬",
            "腊" };
    
    /**
     * 天干列表
     */
    private static final String[] tianGan = new String[] { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" };

    /**
     * 地支列表
     */
    private static final String[] diZhi = new String[] { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" };

    /**
     * 生肖列表
     */
    private static final String[] animals = new String[] { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" };

    /**
     * 中文数字0-9
     */
    public static final String[] numStr = new String[] { "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九"};    

    
    /**
     * 二十四节气
     */
    public static final String[] solarTerms = new String[] {"小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"};
    
    
    /**
     * 二十四节气数据
     */
    private static final long[] solarTermInfo = new long[] {0,21208,42467,63836,85337,107014,128867,150921,173149,195551,218072,240693,263343,285989,308563,331033,353350,375494,397447,419210,440795,462224,483532,504758};
    
    /**
     * 标准日期
     */
    private final LocalDate localDate;

    /**
     * 农历日期,中文
     */
    private String lDateCn;

    /**
     * 岁次
     */
    private String suiCi;

    /**
     * 生肖
     */
    private String lAnimal;

    /**
     * 农历年
     */
    private int lYear;

    /**
     * 农历月
     */
    private int lMonth;

    /**
     * 农历日
     */
    private int lDay;

    /**
     * 农历年,中文
     */
    private String lYearCn;

    /**
     * 农历月,中文
     */
    private String lMonthCn;

    /**
     * 农历日,中文
     */
    private String lDayCn;

    /**
     * 星期,中文
     */
    private String weekCn;
    
    /**
     * 二十四节气 
     */
    private String solarTerm;
    
    /**
     * 当前日期月份是否为闰月,是 为"闰"
     */
    private String leapMonthCn;

    private LunarDate(LocalDate localDate) {
        super();
        this.localDate = localDate;
        initialize();
    }
    
    /**
     * 初始化农历日期
     */
    public void initialize() {
        int year = localDate.getYear();
        int month = localDate.getMonthValue();
        int day = localDate.getDayOfMonth();
        long[] l = calElement(year, month, day);
        
        this.lYear = (int) l[0];
        this.lMonth = (int) l[1];
        this.lDay = (int) l[2];
        
        this.suiCi = cyclical(this.lYear);
        this.lAnimal = animalsYear(this.lYear);


        this.lYearCn = getChinaYear(this.lYear);
        this.lMonthCn = lunarMonth[this.lMonth];
        this.lDayCn = getChinaDay(this.lDay);

        this.weekCn = getWeekCn(localDate.getDayOfWeek().getValue());
        if(l[7] != -1){
            this.solarTerm = solarTerms[(int)l[7]];
        }else{
            this.solarTerm = "";
        }
        if(l[6] == 1){
            this.leapMonthCn = "闰";
        }else{
            this.leapMonthCn = "";
        }
        this.lDateCn = this.lYearCn + "年" + this.leapMonthCn + this.lMonthCn + "月" + this.lDayCn;
    }
    
    /**
     * 通过LocalDateTime创建LunarDate
     * @param localDateTime
     * @return
     */
    public static LunarDate from(LocalDateTime localDateTime) {
        return new LunarDate(DateTimeConverterUtil.toLocalDate(localDateTime));
    }

    /**
     * 通过LocalDate创建LunarDate
     * @param localDate
     * @return
     */
    public static LunarDate from(LocalDate localDate) {
        return new LunarDate(localDate);
    }
    
    /**
     * 通过Instant创建LunarDate
     * @param instant
     * @return
     */
    public static LunarDate from(Instant instant) {
        return new LunarDate(DateTimeConverterUtil.toLocalDate(instant));
    }    

    /**
     * 通过Date创建LunarDate
     * @param date
     * @return
     */
    public static LunarDate from(Date date) {
        return new LunarDate(DateTimeConverterUtil.toLocalDate(date));
    }
    
    public static LunarDate from(Temporal temporal) {
        return new LunarDate(DateTimeConverterUtil.toLocalDate(temporal));
    }

    /**
     * 传回农历year年的总天数
     *
     * @param year
     * @return
     */
    private static final int lunarYearDays(int year) {
        int i, sum = 348;
        for (i = 0x8000; i > 0x8; i >>= 1) {
            if ((lunarInfo[year - 1900] & i) != 0)
                sum += 1;
        }
        return (sum + leapMonthDays(year));
    }

    /**
     * 传回农历 year年闰月的天数
     *
     * @param year
     * @return
     */
    private static final int leapMonthDays(int year) {
        if (leapMonth(year) != 0) {
            if ((lunarInfo[year - 1900] & 0x10000) != 0)
                return 30;
            else
                return 29;
        } else
            return 0;
    }

    /**
     * 传回农历 year年闰哪个月 1-12 , 没闰传回 0
     *
     * @param year
     * @return
     */
    private static final int leapMonth(int year) {
        return (int) (lunarInfo[year - 1900] & 0xf);
    }

    /**
     * 传回农历 year年month月的总天数
     *
     * @param year
     * @param month
     * @return
     */
    private static final int monthDays(int year, int month) {
        if ((lunarInfo[year - 1900] & (0x10000 >> month)) == 0)
            return 29;
        else
            return 30;
    }

    /**
     * 传回农历 year年的生肖
     *
     * @param year
     * @return
     */
    public static final String animalsYear(int year) {
        return animals[(year - 4) % 12];
    }

    /**
     * 传入 月日的offset 传回干支,0=甲子
     *
     * @param num
     * @return
     */
    private static final String cyclicalm(int num) {
        return (tianGan[num % 10] + diZhi[num % 12]);
    }

    /**
     * 传入 offset 传回干支, 0=甲子
     *
     * @param year
     * @return
     */
    public static final String cyclical(int year) {
        int num = year - 1900 + 36;
        return (cyclicalm(num));
    }
    
    /**
     * 计算某年第n个节气的天
     * @param year 公历年
     * @param n
     * @return
     */
    public static final int solarTerm(int year, int n){
        LocalDateTime startLocalDateTime = LocalDateTime.of(1900,1,6,2,5);
        long millis = (long) ((31556925974.7*(year-1900) + solarTermInfo[n]*60000));
        LocalDateTime tempLocalDateTime = DateTimeCalculatorUtil.plusMillis(startLocalDateTime, millis);
        return tempLocalDateTime.getDayOfMonth();
    }

    /**
     * 传出year年month月day日对应的农历.year0 .month1 .day2 .yearCyl3 .monCyl4 .dayCyl5
     * .isLeap6.solarTermIndex7
     *
     * @param year
     * @param month
     * @param day
     * @return
     */
    public static final long[] calElement(int year, int month, int day) {
        long[] nongDate = new long[8];
        int i = 0, temp = 0, leap = 0;
        LocalDateTime baseDate = LocalDate.of(1900, 1, 31).atStartOfDay();
        LocalDateTime objDate = LocalDate.of(year, month, day).atStartOfDay();
        long offset = DateTimeCalculatorUtil.betweenTotalDays(baseDate, objDate);        
        nongDate[5] = offset + 40;
        nongDate[4] = 14;
        for (i = 1900; i < 2050 && offset > 0; i++) {
            temp = lunarYearDays(i);
            offset -= temp;
            nongDate[4] += 12;
        }
        if (offset < 0) {
            offset += temp;
            i--;
            nongDate[4] -= 12;
        }
        nongDate[0] = i;
        nongDate[3] = i - 1864;
        leap = leapMonth(i); // 闰哪个月
        nongDate[6] = 0;
        for (i = 1; i < 13 && offset > 0; i++) {
            // 闰月
            if (leap > 0 && i == (leap + 1) && nongDate[6] == 0) {
                --i;
                nongDate[6] = 1;
                temp = leapMonthDays((int) nongDate[0]);
            } else {
                temp = monthDays((int) nongDate[0], i);
            }
            // 解除闰月
            if (nongDate[6] == 1 && i == (leap + 1))
                nongDate[6] = 0;
            offset -= temp;
            if (nongDate[6] == 0)
                nongDate[4]++;
        }
        if (offset == 0 && leap > 0 && i == leap + 1) {
            if (nongDate[6] == 1) {
                nongDate[6] = 0;
            } else {
                nongDate[6] = 1;
                --i;
                --nongDate[4];
            }
        }
        if (offset < 0) {
            offset += temp;
            --i;
            --nongDate[4];
        }
        nongDate[1] = i;
        nongDate[2] = offset + 1;
        
        //二十四节气
        int solarTermIndex = -1;
        int tempMonth = month - 1;
        int firstSolarTermOfMonth = solarTerm(year, tempMonth*2);
        int secondSolarTermOfMonth = solarTerm(year, tempMonth*2+1);
        if(day == firstSolarTermOfMonth){
            solarTermIndex = tempMonth*2;
        }else if(day == secondSolarTermOfMonth){
            solarTermIndex = tempMonth*2 + 1;
        }
        nongDate[7] = solarTermIndex;
        return nongDate;
    }

    /**
     * 获取农历中文年
     * @param year
     * @return
     */
    public final static String getChinaYear(int year) {
        String ge = numStr[year % 10];
        String shi = numStr[year / 10 % 10];
        String bai = numStr[year / 100 % 10];
        String qian = numStr[year / 1000 % 10];
        return qian + bai + shi + ge;
    }
    /**
     * 获取农历中文日期
     * @param day
     * @return
     */
    public final static String getChinaDay(int day) {
        String a = "";
        if (day == 10)
            return "初十";
        if (day == 20)
            return "二十";
        if (day == 30)
            return "三十";
        int two = (int) ((day) / 10);
        if (two == 0)
            a = "初";
        if (two == 1)
            a = "十";
        if (two == 2)
            a = "廿";
        if (two == 3)
            a = "三";
        int one = (int) (day % 10);
        switch (one) {
        case 1:
            a += "一";
            break;
        case 2:
            a += "二";
            break;
        case 3:
            a += "三";
            break;
        case 4:
            a += "四";
            break;
        case 5:
            a += "五";
            break;
        case 6:
            a += "六";
            break;
        case 7:
            a += "七";
            break;
        case 8:
            a += "八";
            break;
        case 9:
            a += "九";
            break;
        default:
            a += "";
            break;
        }
        return a;
    }
    
    /**
     * 获取中文星期
     * @param week
     * @return
     */
    public final static String getWeekCn(int week) {
        String weekCn = "";
        switch (week) {
        case 1:
            weekCn = "星期一";
            break;
        case 2:
            weekCn = "星期二";
            break;
        case 3:
            weekCn = "星期三";
            break;
        case 4:
            weekCn = "星期四";
            break;
        case 5:
            weekCn = "星期五";
            break;
        case 6:
            weekCn = "星期六";
            break;
        case 7:
            weekCn = "星期日";
            break;
        default:
            weekCn = "";
            break;
        }
        return weekCn;
    }

    /**
     * 以当前时间创建农历日期LunarDate
     * @return
     */
    public static LunarDate now() {
        LocalDate today = LocalDate.now();
        return new LunarDate(today);
    }

    public LocalDate getLocalDate() {
        return localDate;
    }

    public String getlDateCn() {
        return lDateCn;
    }

    public String getSuiCi() {
        return suiCi;
    }

    public String getlAnimal() {
        return lAnimal;
    }

    public int getlYear() {
        return lYear;
    }

    public int getlMonth() {
        return lMonth;
    }

    public int getlDay() {
        return lDay;
    }

    public String getlYearCn() {
        return lYearCn;
    }

    public String getlMonthCn() {
        return lMonthCn;
    }

    public String getlDayCn() {
        return lDayCn;
    }

    public String getWeekCn() {
        return weekCn;
    }
    
    public String getSolarTerm() {
        return solarTerm;
    }

    public String getLeapMonthCn() {
        return leapMonthCn;
    }
    
    @Override
    public String toString() {
        return "LunarDate [localDate=" + localDate + ",lDateCn=" + lDateCn + ", suiCi=" + suiCi + ", lAnimal=" + lAnimal + ", lYear=" + lYear
                + ", lMonth=" + lMonth + ", lDay=" + lDay + ", lYearCn=" + lYearCn + ", lMonthCn=" + lMonthCn
                + ", lDayCn=" + lDayCn + ", weekCn=" + weekCn + ", solarTerm=" + solarTerm + ", leapMonthCn=" + leapMonthCn + "]";
    }

    /**
     * 格式化输出,如:庚子鼠年 二〇二〇年正月初一 星期六 春节
     * @return
     */
    public String formatLongCnWithChineseHoliday(){
        return suiCi + lAnimal + "年 " + lDateCn + " " + weekCn + " " + ChineseHolidayEnum.getHoliday(localDate).getName();
    }    
    
    /**
     * 格式化输出,如: 己亥猪年 二〇一九年腊月初六 星期二
     * @return
     */
    public String formatLongCn(){
        return suiCi + lAnimal + "年 " + lDateCn + " " + weekCn;
    }
    
    /**
     * 格式化输出,如: 0101
     * @return
     */
    public String formatShort(){
        return String.format("%02d", lMonth) + String.format("%02d", lDay);
    }

    @Override
    public boolean isSupported(TemporalField field) {
        return localDate.isSupported(field);
    }

    @Override
    public long getLong(TemporalField field) {
        return localDate.getLong(field);
    }

    @Override
    public boolean isSupported(TemporalUnit unit) {
        return localDate.isSupported(unit);
    }

    @Override
    public Temporal with(TemporalField field, long newValue) {
        return localDate.with(field, newValue);
    }

    @Override
    public Temporal plus(long amountToAdd, TemporalUnit unit) {
        return localDate.plus(amountToAdd, unit);
    }

    @Override
    public long until(Temporal endExclusive, TemporalUnit unit) {
        return localDate.until(endExclusive, unit);
    }
    
    public static void main(String[] args) {
        String str =LunarDate.now().toString();
        System.out.println(str);
    }
    
}

 

 输出:

 

LunarDate [localDate=2020-03-22,lDateCn=二〇二〇年二月廿九, suiCi=庚子, lAnimal=鼠, lYear=2020, lMonth=2, lDay=29, lYearCn=二〇二〇, lMonthCn=二, lDayCn=廿九, weekCn=星期日, solarTerm=, leapMonthCn=]

 

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

Java日期时间API系列10—–Jdk8中java.time包中的新的日期时间API类的DateTimeFormatter

1.DateTimeFormatter

final修饰,线程安全,用于打印和解析日期-时间对象的格式化程序。

创建DateTimeFormatter:

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());

 

2.格式化日期

例如:LocalDateTime

     LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(dateTimeFormatter.format(localDateTime));

输出:2019-12-28 23:06:12

 

3.解析日期

(1)使用 LocalDateTime.parse

例如:解析 “2019-12-28 23:06:12”

     LocalDateTime localDateTime2 = LocalDateTime.parse("2019-12-28 23:06:12", dateTimeFormatter);
        System.out.println("localDateTime2:"+dateTimeFormatter.format(localDateTime2));

输出:localDateTime2:2019-12-28 23:06:12

(2)DateTimeFormatter.parse

例如:解析 “2019-12-28 23:06:12”

        LocalDateTime localDateTime3 = LocalDateTime.from(dateTimeFormatter.parse("2019-12-28 23:06:12"));
        System.out.println("localDateTime2:"+dateTimeFormatter.format(localDateTime3));

输出:localDateTime3:2019-12-28 23:06:12

 

4.常用符号含义

 更多说明见 Patterns for Formatting and Parsing部分:

 https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html   

.

5.YYYY格式问题

格式化时,年部分的y是小写的y,如:yyyy-MM-dd。写成YYYY的话,会出现bug。

 

6.Jdk8 解析 yyyyMMddHHmmssSSS 问题

https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8031085

这个问题在Jdk9中修复。

Java8中推荐创建DateTimeFormatter方式:

DateTimeFormatter dtf = new DateTimeFormatterBuilder().appendPattern("yyyyMMddHHmmss").appendValue(ChronoField.MILLI_OF_SECOND, 3).toFormatter();

 

Java日期时间API系列9—–Jdk8中java.time包中的新的日期时间API类的Period和Duration的区别

1.Period

final修饰,线程安全,ISO-8601日历系统中基于日期的时间量,例如2年3个月4天。

主要属性:年数,月数,天数。

    /**
     * The number of years.
     */
    private final int years;
    /**
     * The number of months.
     */
    private final int months;
    /**
     * The number of days.
     */
    private final int days;

用于时间量,比较2个日期。

例如:

     LocalDate localDate1 = LocalDate.of(2019, 11, 15);
        LocalDate localDate2 = LocalDate.of(2020, 1, 1);
        Period p = Period.between(localDate1, localDate2);
        System.out.println("years:"+p.getYears()+" months:"+p.getMonths()+" days:"+p.getDays());

输出:

years:0 months:1 days:17

2.Duration

final修饰,线程安全,基于时间的时间量,如“34.5秒”。

主要属性:秒,纳秒

    /**
     * The number of seconds in the duration.
     */
    private final long seconds;
    /**
     * The number of nanoseconds in the duration, expressed as a fraction of the
     * number of seconds. This is always positive, and never exceeds 999,999,999.
     */
    private final int nanos;

用于时间量,比较2个时间。

例如:

        LocalDateTime localDateTime1 = LocalDateTime.of(2019, 11, 15, 0, 0);
        LocalDateTime localDateTime2 = LocalDateTime.of(2019, 11, 15, 10, 30);
        Duration d = Duration.between(localDateTime1, localDateTime2);
        System.out.println("days:"+d.toDays());
        System.out.println("hours:"+d.toHours());
        System.out.println("minutes:"+d.toMinutes());
        System.out.println("millis:"+d.toMillis());

输出:

days:0
hours:10
minutes:630
millis:37800000

3.Period和Duration的区别

(1)包含属性不同

Period包含年数,月数,天数,而Duration只包含秒,纳秒。

Period只能返回年数,月数,天数;Duration可以返回天数,小时数,分钟数,毫秒数等。

(2)between方法可以使用的类型不同

Period只能使用LocalDate,Duration可以使用所有包含了time部分且实现了Temporal接口的类,比如LocalDateTime,LocalTime和Instant等。

Period:

public static Period between(LocalDate startDateInclusive, LocalDate endDateExclusive)

 

Duration:

public static Duration between(Temporal startInclusive, Temporal endExclusive)

 

(3)between获取天数差的区别

通过上面的实例可以看出:

Period  p.getDays()  获取天数时,只会获取days属性值,而不会将年月部分都计算成天数,不会有2020.1.1和2019.1.1比较后获取天数为365天的情况。

    public int getDays() {
        return days;
    }

 

Duration d.toDays()  获取天数时,会将秒属性转换成天数。

    public long toDays() {
        return seconds / SECONDS_PER_DAY;
    }

 

所以,想要获取2个时间的相差总天数,只能用Duration。

(4)Period有获取总月数的方法,为什么没有获取总天数方法?

Period有获取总月数的方法:

    public long toTotalMonths() {
        return years * 12L + months;  // no overflow
    }

为什么没有获取总天数方法?

因为between后获取到的Period,不会记录2个日期中间的闰年信息,有闰年的存在,每年的天数不一定是365天,所以计算不准确。

Java日期时间API系列8—–Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

目录

0.前言

1.TemporalAccessor源码

2.Temporal源码

3.TemporalAdjuster源码

4.ChronoLocalDate源码

5.LocalDate源码

6.总结

 

0.前言

  通过前面Java日期时间API系列6—–Jdk8中java.time包中的新的日期时间API类中主要的类关系简图如下:

 

可以看出主要的LocalDate, LocalTime, LocalDateTime, Instant都是实现相同的接口,这里以LocalDate为例分析java8时间api源码,其他的类与LocalDate类似。

  LocalDate的相关类图如下:完整类图

可以看出LocalDate同时实现了Temporal, TemporalAdjuster, ChronoLocalDate三个接口。

java.time包是在jdk8中上添加进来的,jdk8接口有了一些新的特性:接口的默认方法、静态方法和函数式接口

接口的默认方法:使用default 关键字给接口增加非抽象的方法实现,子类可以选择性实现。

静态方法:接口里可以声明静态方法,并且可以实现。

函数式接口:增加@FunctionalInterface 注解,只要这个接口只包含一个抽象方法。

更多描述可以参考Java 8 指南:https://www.cnblogs.com/xkzhangsanx/p/10847284.html

 

1.TemporalAccessor源码

TemporalAccessor是框架级接口,定义对时态对象(如日期、时间、偏移量或它们的某些组合)的只读访问。

这是日期、时间和偏移量对象的基本接口类型。它是由那些可以提供信息的类实现的,比如{@linkplain TemporalField字段}或{@linkplain TemporalQuery查询}。

(1)boolean isSupported(TemporalField field)

检查是否支持指定的字段

(2)default ValueRange range(TemporalField field)

默认方法,获取指定字段的有效值范围

(3)default int get(TemporalField field)

这个方法为默认方法,以int的形式获取指定字段的值

(4)long getLong(TemporalField field)

以long的形式获取指定字段的值

(5)default R query(TemporalQuery query)

默认方法,这个日期-时间查询。它使用指定的查询策略对象查询此日期-时间。

 

2.Temporal源码

 Temporal继承TemporalAccessor接口。

Temporal也是框架级接口,定义对时态对象(如日期、时间、偏移量或它们的某些组合)的读写访问。

这是日期、时间和偏移量对象的基本接口类型,这些对象足够完整,可以使用加减操作。

(1)boolean isSupported(TemporalUnit unit)

检查是否支持指定的单元

(2)default Temporal with(TemporalAdjuster adjuster)

默认方法,返回调整后的对象

例如:

date = date.with(lastDayOfMonth());

返回当前月的最后一天

(3)Temporal with(TemporalField field, long newValue)

根据指定的字段更改

(4)default Temporal plus(TemporalAmount amount)

默认方法,增加指定时间

(5)Temporal plus(long amountToAdd, TemporalUnit unit)

根据指定的单位增加时间

(6)default Temporal minus(TemporalAmount amount)

默认方法,减少指定时间

(7)default Temporal minus(long amountToSubtract, TemporalUnit unit)

默认方法,根据指定的单元减少时间

(8)long until(Temporal endExclusive, TemporalUnit unit)

根据指定的单元计算到另一个时间的相差值

例如:

        LocalDate localDate = LocalDate.of(2019, 1, 1);
        LocalDate endDate = LocalDate.of(2019, 1, 16);
        long days = localDate.until(endDate, ChronoUnit.DAYS);
        System.out.println(days);

输出:15

3.TemporalAdjuster源码

 

TemporalAdjuster接口加了函数式接口@FunctionalInterface注解,用于调整时间对象的策略。

(1)Temporal adjustInto(Temporal temporal)

调整指定的时间对象。

java.time.temporal.TemporalAdjusters 为常用的时间调节器,包含当月第一天,最后一天等等。

方法说明:

dayOfWeekInMonth   同一个月中每一周的第几天
firstDayOfMonth     当月的第一天
firstDayOfNextMonth   下月的第一天
firstDayOfNextYear   明年的第一天
firstDayOfYear     当年的第一天
firstInMonth          同一个月中,第一个符合星期几要求的值
lastDayOfMonth     当月的最后一天
lastDayOfNextMonth   下月的最后一天
lastDayOfNextYear   明年的最后一天
lastDayOfYear   今年的最后一天
lastInMonth   同一个月中,最后一个符合星期几要求的值
next/previous  将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期
nextOrSame/previousOrSame  将其值设定为日期调整后或者调整前,第一个符合指定星
期几要求的日期,如果该日期已经符合要求,直接返回该对象

 例如:当月最后一天

temporal = temporal.with(lastDayOfMonth());

 

4.ChronoLocalDate源码

ChronoLocalDate 接口 继承了Temporal, TemporalAdjuster, Comparable接口。

在任意年表中不包含(时间或时区)的日期,用于高级全球化用例。

从图中圈中部分可以看出 ChronoLocalDate实现了实现或重写了Temporal, TemporalAdjuster, Comparable接口。

其他方法:

(1)default boolean isLeapYear()

默认方法,计算闰年

(2)int lengthOfMonth()

根据日历系统的定义,返回由这个日期表示的月份的长度。

(3)default int lengthOfYear()

默认方法,返回由日历系统定义的日期表示的年份长度。

(4)default long toEpochDay()

默认方法,返回1970-01-01开始的天数

(5)default int compareTo(ChronoLocalDate other)

默认方法,实现接口Comparable,比较大小

(6)default boolean isAfter(ChronoLocalDate other)

是否在other后面

(7)default boolean isBefore(ChronoLocalDate other)

是否在other前面

(8)default boolean isEqual(ChronoLocalDate other)

是否与other相等

(9)object接口相关的方法:

boolean equals(Object obj)

int hashCode()

String toString()

(10)static ChronoLocalDate from(TemporalAccessor temporal)

从时态对象获取ChronoLocalDate的实例。

(11)default ChronoLocalDateTime atTime(LocalTime localTime)

将这个日期和时间组合起来,创建一个ChronoLocalDateTime。

(12)default String format(DateTimeFormatter formatter)

ChronoLocalDate 格式化处理

(13)Chronology getChronology()

获取此日期的年表

(14)default Era getEra()

获取由年表定义的年代

 

5.LocalDate源码

LocalDate同时实现了Temporal, TemporalAdjuster, ChronoLocalDate三个接口,是ChronoLocalDate接口国际化的ISO-8601标准实现,final修饰,线程安全,方法特别多,但很有规律。

类图如下:

主要属性为:

/**
*最小日期:-999999999-01-01
*/
public static final LocalDate MIN = LocalDate.of(Year.MIN_VALUE, 1, 1); 

/**
*最d大日期:+999999999-12-31
*/
public static final LocalDate MAX = LocalDate.of(Year.MAX_VALUE, 12, 31);

/**
*400年周期中的天数
*/
private static final int DAYS_PER_CYCLE = 146097;

/**
*从0年到1970年的天数
*/
static final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L);

/**
*年
*/
private final int year;

/**
*月
*/
private final short month;

/**
*日
*/
private final short day;

主要方法,除了实现Temporal, TemporalAdjuster, ChronoLocalDate三个接口还添加了一些特有的方法。所有可以分为6类方法:

(1)创建LocalDate对象方法

 例如:创建当前日期:

LocalDate now = LocalDate.now();

源码:可以看出是使用系统默认的Clock创建当前日期的。

    public static LocalDate now() {
        return now(Clock.systemDefaultZone());
    }

 

 (2)获取属性方法

 例如:获取年

int year = now.getYear();

源码:直接获取属性中year

    public int getYear() {
        return year;
    }

 

 (3)修改属性的方法

 例如:修改年,输出:2020-12-26

        LocalDate localDate1 = now.withYear(2020);
        System.out.println(localDate1);

源码:可以看到底层,return new LocalDate(year, month, day); 创建了一个新对象。

    public LocalDate withYear(int year) {
        if (this.year == year) {
            return this;
        }
        YEAR.checkValidValue(year);
        return resolvePreviousValid(year, month, day);
    }


private static LocalDate resolvePreviousValid(int year, int month, int day) {
        switch (month) {
            case 2:
                day = Math.min(day, IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28);
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                day = Math.min(day, 30);
                break;
        }
        return new LocalDate(year, month, day);
    }

 

 (4)增加或减少日期方法

 例如:减少1年,输出:2018-12-26

        LocalDate localDate2 = now.minusYears(1);
        System.out.println(localDate2);

源码:可以看出底层使用了:plusYears(-yearsToSubtract),相当于+(-1)

    public LocalDate minusYears(long yearsToSubtract) {
        return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
    }

 

(5)转换为各类DateTime(LocalDateTime、ZonedDateTime和OffsetDateTime)方法

 例如:转为LocalDateTime 输出为:2019-12-26T00:00

        LocalDateTime localDateTime = now.atStartOfDay();
        System.out.println(localDateTime);

源码:this为当前的日期,LocalTime.MIDNIGHT为零点时间,组合为为LocalDateTime

    public LocalDateTime atStartOfDay() {
        return LocalDateTime.of(this, LocalTime.MIDNIGHT);
    }

 

 (6)其他方法主要为实现ChronoLocalDate定义的方法

例如:ChronoLocalDate中定义的判断和比较方法

   

6.总结

  TemporalAccessor主要定义了只读的获取属性方法,Temporal主要定义了修改日期属性和日期加减运算方法,ChronoLocalDate定义了国际化lDate的通用方法,LocalDate是ChronoLocalDate的ISO标准实现,实现了上述所有接口,final修饰,线程安全,方法定义明确,丰富多样,适用广。

Java日期时间API系列7—–Jdk8中java.time包中的新的日期时间API类的优点

1.不变性

新的日期/时间API中,所有的类都是不可变的,这对多线程环境有好处。

比如:LocalDateTime

 

 

 

2.关注点分离

新的API将人可读的日期时间和机器时间(unix timestamp)明确分离,它为日期(Date)、时间(Time)、日期时间(DateTime)、时间戳(unix timestamp)以及时区定义了不同的类。

不同时间分解成了各个类,比如:LocalDate, LocalTime, LocalDateTime, Instant,Year,Month,YearMonth,MonthDay,DayOfWeek等,满足各种不同场景使用需求。

 

3.清晰

在所有的类中,方法都被明确定义用以完成相同的行为。

举个例子,要拿到当前实例我们可以使用now()方法,在所有的类中都定义了format()和parse()方法,而不是像以前那样专门有一个独立的类。方法明确,清晰,统一,方便好记。

 

4.实用操作

(相当于很多工具方法,不再需要我们自己封装了):所有新的日期/时间API类都实现了一系列方法用以完成通用的任务,如:加、减、格式化、解析、从日期/时间中提取单独部分,等等。

比如:LocalDateTime,包含非常丰富的实用操作(转换,获取各个字段,修改字段,增加和减少等)。

 

 

5.TemporalAdjuster 让你能够用更精细的方式操纵日期

不再局限于一次只能改变它的 一个值,并且你还可按照需求定义自己的日期转换器。比如:将日期调整到下个周日、下个工作日,或者是本月的最后一天。

lastDayOfMonth 创建一个新的日期,它的值为当月的最后一天。

 

6.对比Jdk7及以前的日期时间类的缺点改进

6.1 Date和Calendar的不方便使用问题

(1)new Date(2019,01,01)实际是3919年2月。因为Date的构造函数 的年份表示的始于1900年的差值。

  LocalDate创建实例:

LocalDate localDate = LocalDate.of(2019, 1, 1);

(2)month是从0开始的。

LocalDate month是从1开始的:

        LocalDate localDate = LocalDate.of(2019, 1, 1);
        System.out.println(localDate.getMonthValue());

输出是1

(3)DAY_OF_WEEK 的取值,是从周日(1)开始的。

LocalDate week是从周一(1)开始的:

        LocalDate localDate = LocalDate.of(2019, 1, 1);
        System.out.println(localDate.getDayOfWeek());
        System.out.println(localDate.getDayOfWeek().getValue());

输出

TUESDAY
2

 

(4)Date如果不格式化,打印出的日期可读性差。

LocalDate的输出,清晰。

        LocalDate localDate = LocalDate.of(2019, 1, 1);
        System.out.println(localDate.getMonthValue());
        System.out.println(localDate.toString());

输出:

2019-01-01

(5)日期类并不提供国际化,没有时区支持

java8的时间类都支持了时区操作。

例如:LocalDateTime

         //中国时间,输出时不包含时区
         LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
         System.out.println(ldt);
        //意大利罗马时间,输出时包含时区
        ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Rome"));
        System.out.println(zdt);

输出

2019-12-20T23:17:07.914
2019-12-20T16:17:07.915+01:00[Europe/Rome]

6.2 线程安全问题

(1)Date、Calendar可变性,线程安全问题

java8中所有类都是final修饰的,每次修改都会生成新的副本。

(2)DateFormat和SimpleDateFormat线程安全问题

java8中的DateTimeFormatter也是不可变的,源码:

 

 6.3 java8对日期api进行系统的设计,增加了许多实用方便的操作,几乎不用再使用dateutil额外工具类。

比如,增加一天。

        LocalDate localDate = LocalDate.of(2019, 1, 1);
        LocalDate localDate2 = localDate.plusDays(1);
        System.out.println("localDate:"+localDate);
        System.out.println("localDate2:"+localDate2);

输出:

localDate:2019-01-01
localDate2:2019-01-02

 

 

参考:https://blog.csdn.net/wangsun300/article/details/103403490