您当前的位置: 首页 >  Java

white camel

暂无认证

  • 0浏览

    0关注

    442博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

重学Java8新特性(四) : 日期时间API、LocalDateTime、DateTimeFormatter、开发中时间工具类(常用)

white camel 发布时间:2022-08-05 09:25:34 ,浏览量:0

文章目录
  • 一、JDK8中日期时间API的介绍
    • 1.1、LocalDate、LocalTime、LocalDateTime的使用
    • 2.2、Instant类的使用
    • 2.3、DateTimeFormatter的使用
    • 2.4、ZoneId, ZonedDateTime, Clock, TemporalAdjuster
    • 2.5、参考:与传统日期处理的转换
  • 二、时间工具类

一、JDK8中日期时间API的介绍

java.time包介绍 : https://www.yiibai.com/javatime/javatime_instant.html

1、新日期时间API出现的背景

如果我们可以跟别人说:“我们在1502643933071见面,别晚了!”那么就再简单不过了。但是我们希望时间与昼夜和四季有关,于是事情就变复杂了。JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。而Calendar并不比Date好多少。它们面临的问题是:

  • 可变性:像日期和时间这样的类应该是不可变的。
  • 偏移性:Date中的年份是从1900开始的,而月份都从0开始。
  • 格式化:格式化只对Date有用,Calendar则不行。
  • 此外,它们也不是线程安全的;不能处理闰秒等。
import org.junit.Test;
import java.util.Date;

/**
 * jdk 8中日期时间API的测试
 *
 */
public class JDK8DateTimeTest {

    @Test
    public void testDate(){
        //偏移量
        Date date1 = new Date(2020,9,8);
        System.out.println(date1);  //Fri Oct 08 00:00:00 CST 3920

        Date date2 = new Date(2020 - 1900,9 - 1,8);
        System.out.println(date2); //Tue Sep 08 00:00:00 CST 2020
    }
}

第三次引入的API是成功的,并且Java 8中引入的java.time API 已经纠正了过去的缺陷,将来很长一段时间内它都会为我们服务。

Java 8 吸收了Joda-Time 的精华,以一个新的开始为Java 创建优秀的API。新的java.time 中包含了所有关于 本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。历史悠久的Date 类新增了toInstant() 方法,用于把Date 转换成新的表示形式。这些新增的本地化时间日期API 大大简化了日期时间和本地化的管理。

  • LocalDate:表示日期,包含:年月日。格式为:2020-01-13
  • LocalTime:表示时间,包含:时分秒。格式为:16:39:09.307
  • LocalDateTime:表示日期时间,包含:年月日 时分秒。格式为:2020-01-13T16:40:59.138
  • DateTimeFormatter:日期时间格式化类
  • Instant:时间戳类
  • Duration:用于计算 2 个时间(LocalTime,时分秒)之间的差距
  • Period:用于计算 2 个日期(LocalDate,年月日)之间的差距
  • ZonedDateTime:包含时区的时间
1.1、LocalDate、LocalTime、LocalDateTime的使用
  • LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。
    • LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储生日、纪念日等日期。
    • LocalTime表示一个时间,而不是日期。
    • LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一。
  • 注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历。
import org.junit.Test;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

/**
 * jdk 8中日期时间API的测试
 */
public class JDK8DateTimeTest {

    /**
     * LocalDate、LocalTime、LocalDateTime的使用
     *
     */
    @Test
    public void test1(){
        //now():获取当前的日期、时间、日期+时间
        LocalDate localDate = LocalDate.now();
        LocalTime localTime = LocalTime.now();
        LocalDateTime localDateTime = LocalDateTime.now();

        System.out.println(localDate);
        System.out.println(localTime);
        System.out.println(localDateTime);

        //of():设置指定的年、月、日、时、分、秒。没有偏移量
        LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 43);
        System.out.println(localDateTime1);

        //getXxx():获取相关的属性
        System.out.println(localDateTime.getDayOfMonth());
        System.out.println(localDateTime.getDayOfWeek());
        System.out.println(localDateTime.getMonth());
        System.out.println(localDateTime.getMonthValue());
        System.out.println(localDateTime.getMinute());

        //体现不可变性
        //withXxx():设置相关的属性
        LocalDate localDate1 = localDate.withDayOfMonth(22);
        System.out.println(localDate);
        System.out.println(localDate1);

        LocalDateTime localDateTime2 = localDateTime.withHour(4);
        System.out.println(localDateTime);
        System.out.println(localDateTime2);

        //不可变性
        LocalDateTime localDateTime3 = localDateTime.plusMonths(3);
        System.out.println(localDateTime);
        System.out.println(localDateTime3);

        LocalDateTime localDateTime4 = localDateTime.minusDays(6);
        System.out.println(localDateTime);
        System.out.println(localDateTime4);
    }
}

在这里插入图片描述

2.2、Instant类的使用
  • Instant:时间线上的一个瞬时点。这可能被用来记录应用程序中的事件时间戳。

  • java.time包通过值类型Instant提供机器视图,不提供处理人类意义上的时间单位。Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒数。因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。

(1 ns = 10-9s) 1秒= 1000毫秒=106微秒=109纳秒 在这里插入图片描述

时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。

import org.junit.Test;

import java.time.*;

/**
 * jdk 8中日期时间API的测试
 */
public class JDK8DateTimeTest {

    /**
     * Instant的使用
     */
    @Test
    public void test2(){
        //now():获取本初子午线对应的标准时间
        Instant instant = Instant.now();
        System.out.println(instant);    //2020-05-10T09:55:55.561Z

        //添加时间的偏移量
        OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));//东八区
        System.out.println(offsetDateTime); //2020-05-10T18:00:00.641+08:00

        //toEpochMilli():获取自1970年1月1日0时0分0秒(UTC)开始的毫秒数  ---> Date类的getTime()
        long milli = instant.toEpochMilli();
        System.out.println(milli);  //1589104867591

        //ofEpochMilli():通过给定的毫秒数,获取Instant实例  -->Date(long millis)
        Instant instant1 = Instant.ofEpochMilli(1550475314878L);
        System.out.println(instant1);   //2019-02-18T07:35:14.878Z
    }
}
2.3、DateTimeFormatter的使用

java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:

  • 预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
  • 本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.LONG)
  • 自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)

在这里插入图片描述

import org.junit.Test;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.TemporalAccessor;

/**
 * jdk 8中日期时间API的测试
 */
public class JDK8DateTimeTest {

    /**
     * DateTimeFormatter:格式化或解析日期、时间
     *     类似于SimpleDateFormat
     */
    @Test
    public void test3(){
        //方式一:预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
        DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        //格式化:日期-->字符串
        LocalDateTime localDateTime = LocalDateTime.now();
        String str1 = formatter.format(localDateTime);
        System.out.println(localDateTime);
        System.out.println(str1);//2020-05-10T18:26:40.234

        //解析:字符串 -->日期
        TemporalAccessor parse = formatter.parse("2020-05-10T18:26:40.234");
        System.out.println(parse);

        //方式二:
        //本地化相关的格式。如:ofLocalizedDateTime()
        //FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT :适用于LocalDateTime
        DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
        //格式化
        String str2 = formatter1.format(localDateTime);
        System.out.println(str2);//2020年5月10日 下午06时26分40秒

        //本地化相关的格式。如:ofLocalizedDate()
        //FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 适用于LocalDate
        DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
        //格式化
        String str3 = formatter2.format(LocalDate.now());
        System.out.println(str3);//2020-5-10


       //重点: 方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
        DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
        //格式化
        String str4 = formatter3.format(LocalDateTime.now());
        System.out.println(str4);//2020-05-10 06:26:40

        //解析
        TemporalAccessor accessor = formatter3.parse("2020-05-10 06:26:40");
        System.out.println(accessor);

    }
}
2.4、ZoneId, ZonedDateTime, Clock, TemporalAdjuster
  • ZoneId:该类中包含了所有的时区信息,一个时区的ID,如Europe/Paris
  • ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,如2007-12-03T10:15:30+01:00Europe/Paris。
    • 其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等
import org.junit.Test;

import java.time.*;
import java.util.Set;

/**
 * jdk 8中日期时间API的测试
 */
public class JDK8DateTimeTest {
	
	@Test
	public void test1(){
		//ZoneId:类中包含了所有的时区信息
		// ZoneId的getAvailableZoneIds():获取所有的ZoneId
		Set zoneIds= ZoneId.getAvailableZoneIds();
		for(String s: zoneIds) {
			System.out.println(s);
		}
		// ZoneId的of():获取指定时区的时间
		LocalDateTime localDateTime= LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
		System.out.println(localDateTime);
		
		//ZonedDateTime:带时区的日期时间
		// ZonedDateTime的now():获取本时区的ZonedDateTime对象
		ZonedDateTime zonedDateTime= ZonedDateTime.now();
		System.out.println(zonedDateTime);
		// ZonedDateTime的now(ZoneId id):获取指定时区的ZonedDateTime对象
		ZonedDateTime zonedDateTime1= ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
		System.out.println(zonedDateTime1);
	}
}
  • Clock:使用时区提供对当前即时、日期和时间的访问的时钟。
  • 持续时间:Duration,用于计算两个“时间”间隔
  • 日期间隔:Period,用于计算两个“日期”间隔
  • TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。
  • TemporalAdjusters : 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster 的实现。
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;

import org.junit.Test;

public class JDK8APITest {
	
	@Test
	public void test2(){
		//Duration:用于计算两个“时间”间隔,以秒和纳秒为基准
		LocalTime localTime= LocalTime.now();
		LocalTime localTime1= LocalTime.of(15, 23, 32);
		//between():静态方法,返回Duration对象,表示两个时间的间隔
		Duration duration= Duration.between(localTime1, localTime);
		System.out.println(duration);
		
		System.out.println(duration.getSeconds());
		System.out.println(duration.getNano());
		
		LocalDateTime localDateTime= LocalDateTime.of(2016, 6, 12, 15, 23, 32);
		LocalDateTime localDateTime1= LocalDateTime.of(2017, 6, 12, 15, 23, 32);
		
		Duration duration1= Duration.between(localDateTime1, localDateTime);
		System.out.println(duration1.toDays());
	}
}
import java.time.Period;
import org.junit.Test;

public class JDK8APITest {
	
	@Test
	public void test3(){
		//Period:用于计算两个“日期”间隔,以年、月、日衡量
		LocalDate localDate= LocalDate.now();
		LocalDate localDate1= LocalDate.of(2028, 3, 18);
		
		Period period= Period.between(localDate, localDate1);
		System.out.println(period);
        System.out.println(period.getYears());
		
		System.out.println(period.getMonths());
		System.out.println(period.getDays());
		
		Period period1= period.withYears(2);
		System.out.println(period1);
	}
}
2.5、参考:与传统日期处理的转换

在这里插入图片描述

二、时间工具类
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DateTimeUtils {
    public static final String PATTERN_YYYY_MM_DD = "yyyy-MM-dd";
    public static final String PATTERN_YYYY_MM_DD_HH = "yyyy-MM-dd HH";
    public static final String PATTERN_YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
    public static final String PATTERN_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static final String PATTERN_YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String PATTERN_YYYY_MM_DD_T_HH_MM_SS_SSS_Z = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
    public static final String PATTERN_YYYYMMDD = "yyyyMMdd";
    public static final String PATTERN_YYYYMMDDHH = "yyyyMMddHH";
    public static final String PATTERN_YYYYMMDDHHMM = "yyyyMMddHHmm";
    public static final String PATTERN_YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final String PATTERN_YYYYMMDDHHMMSSSSS = "yyyyMMddHHmmssSSS";
    public static final String PATTERN_HH_MM = "HH:mm";
    public static final String PATTERN_HH_MM_SS = "HH:mm:ss";
    public static final String PATTERN_HHMMSS = "HHmmss";
    public static final String[] WEEKS = {"一", "二", "三", "四", "五", "六", "日"};
    public static final String[] DAYS = {"今天", "明天", "后天"};
    public static final DateTimeFormatter FORMATTER_YYYY_MM_DD = DateTimeFormatter.ofPattern(PATTERN_YYYY_MM_DD).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_YYYY_MM_DD_HH = DateTimeFormatter.ofPattern(PATTERN_YYYY_MM_DD_HH).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_YYYY_MM_DD_HH_MM = DateTimeFormatter.ofPattern(PATTERN_YYYY_MM_DD_HH_MM).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_YYYY_MM_DD_HH_MM_SS = DateTimeFormatter.ofPattern(PATTERN_YYYY_MM_DD_HH_MM_SS).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_YYYY_MM_DD_HH_MM_SS_SSS = DateTimeFormatter.ofPattern(PATTERN_YYYY_MM_DD_HH_MM_SS_SSS).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_YYYYMMDD = DateTimeFormatter.ofPattern(PATTERN_YYYYMMDD).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_YYYYMMDDHH = DateTimeFormatter.ofPattern(PATTERN_YYYYMMDDHH).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_YYYYMMDDHHMM = DateTimeFormatter.ofPattern(PATTERN_YYYYMMDDHHMM).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_YYYYMMDDHHMMSS = DateTimeFormatter.ofPattern(PATTERN_YYYYMMDDHHMMSS).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_YYYYMMDDHHMMSSSSS = DateTimeFormatter.ofPattern(PATTERN_YYYYMMDDHHMMSSSSS).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_HH_MM = DateTimeFormatter.ofPattern(PATTERN_HH_MM).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_HH_MM_SS = DateTimeFormatter.ofPattern(PATTERN_HH_MM_SS).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_HHMMSS = DateTimeFormatter.ofPattern(PATTERN_HHMMSS).withZone(ZoneId.systemDefault());
    public static final DateTimeFormatter FORMATTER_YYYY_MM_DD_T_HH_MM_SS_SSS_Z = DateTimeFormatter.ofPattern(PATTERN_YYYY_MM_DD_T_HH_MM_SS_SSS_Z).withZone(ZoneId.systemDefault());

    private static final Map FORMATTERS = new ConcurrentHashMap();

    static {
        FORMATTERS.put(PATTERN_YYYY_MM_DD, FORMATTER_YYYY_MM_DD);
        FORMATTERS.put(PATTERN_YYYY_MM_DD_HH, FORMATTER_YYYY_MM_DD_HH);
        FORMATTERS.put(PATTERN_YYYY_MM_DD_HH_MM, FORMATTER_YYYY_MM_DD_HH_MM);
        FORMATTERS.put(PATTERN_YYYY_MM_DD_HH_MM_SS, FORMATTER_YYYY_MM_DD_HH_MM_SS);
        FORMATTERS.put(PATTERN_YYYY_MM_DD_HH_MM_SS_SSS, FORMATTER_YYYY_MM_DD_HH_MM_SS_SSS);
        FORMATTERS.put(PATTERN_YYYYMMDD, FORMATTER_YYYYMMDD);
        FORMATTERS.put(PATTERN_YYYYMMDDHH, FORMATTER_YYYYMMDDHH);
        FORMATTERS.put(PATTERN_YYYYMMDDHHMM, FORMATTER_YYYYMMDDHHMM);
        FORMATTERS.put(PATTERN_YYYYMMDDHHMMSS, FORMATTER_YYYYMMDDHHMMSS);
        FORMATTERS.put(PATTERN_YYYYMMDDHHMMSSSSS, FORMATTER_YYYYMMDDHHMMSSSSS);
        FORMATTERS.put(PATTERN_HH_MM, FORMATTER_HH_MM);
        FORMATTERS.put(PATTERN_HH_MM_SS, FORMATTER_HH_MM_SS);
        FORMATTERS.put(PATTERN_HHMMSS, FORMATTER_HHMMSS);
        FORMATTERS.put(PATTERN_YYYY_MM_DD_T_HH_MM_SS_SSS_Z, FORMATTER_YYYY_MM_DD_T_HH_MM_SS_SSS_Z);
    }

    private DateTimeUtils() {
    }

    /**
     * 格式化日期
     *
     * @param temporal 日期,常见的实现类:
     *                 {@link LocalDateTime},
     *                 {@link LocalDate},
     *                 {@link LocalTime},
     *                 {@link ZonedDateTime}
     *                 {@link Instant}
     * @param pattern  格式
     * @return 被格式化后的日期字符串
     * @see LocalDateTime
     * @see LocalDate
     * @see LocalTime
     * @see Instant
     * @see ZonedDateTime
     */
    public static String format(TemporalAccessor temporal, String pattern) {
        return FORMATTERS.getOrDefault(pattern, DateTimeFormatter.ofPattern(pattern).withZone(ZoneId.systemDefault())).format(temporal);
    }

    /**
     * 解析字符串日期
     *
     * @param dateStr 日期字符串
     * @param pattern 格式
     * @return LocalDateTime
     */
    public static LocalDateTime parseLocalDateTime(String dateStr, String pattern) {
        return LocalDateTime.parse(dateStr, FORMATTERS.getOrDefault(pattern, DateTimeFormatter.ofPattern(pattern).withZone(ZoneId.of("Asia/Shanghai"))));
    }

    /**
     * 解析字符串日期
     *
     * @param dateStr 日期字符串
     * @param pattern 格式
     * @return LocalDate
     */
    public static LocalDate parseLocalDate(String dateStr, String pattern) {
        return LocalDate.parse(dateStr, FORMATTERS.getOrDefault(pattern, DateTimeFormatter.ofPattern(pattern).withZone(ZoneId.systemDefault())));
    }

    /**
     * 解析字符串时间
     *
     * @param timeStr 时间字符串
     * @param pattern 格式
     * @return LocalTime
     */
    public static LocalTime parseLocalTime(String timeStr, String pattern) {
        return LocalTime.parse(timeStr, FORMATTERS.getOrDefault(pattern, DateTimeFormatter.ofPattern(pattern).withZone(ZoneId.systemDefault())));
    }

    /**
     * 相差多少年
     *
     * @param from 日期1 inclusive
     * @param to   日期2 exclusive
     * @return 如果from大于to则会返回负数
     * @see LocalDateTime
     * @see LocalDate
     * @see Instant
     * @see ZonedDateTime
     */
    public static long betweenYears(Temporal from, Temporal to) {
        return ChronoUnit.YEARS.between(from, to);
    }

    /**
     * 相差多少月
     *
     * @param from 日期1 inclusive
     * @param to   日期2 exclusive
     * @return 如果from大于to则会返回负数
     * @see LocalDateTime
     * @see LocalDate
     * @see Instant
     * @see ZonedDateTime
     */
    public static long betweenMonths(Temporal from, Temporal to) {
        return ChronoUnit.MONTHS.between(from, to);
    }

    /**
     * 相差多少周
     *
     * @param from 日期1 inclusive
     * @param to   日期2 exclusive
     * @return 如果from大于to则会返回负数
     * @see LocalDateTime
     * @see LocalDate
     * @see Instant
     * @see ZonedDateTime
     */
    public static long betweenWeeks(Temporal from, Temporal to) {
        return ChronoUnit.WEEKS.between(from, to);
    }

    /**
     * 相差多少天
     *
     * @param from 日期1 inclusive
     * @param to   日期2 exclusive
     * @return 如果from大于to则会返回负数
     * @see LocalDateTime
     * @see LocalDate
     * @see Instant
     * @see ZonedDateTime
     */
    public static long betweenDays(Temporal from, Temporal to) {
        return ChronoUnit.DAYS.between(from, to);
    }

    /**
     * 相差多少小时
     *
     * @param from 日期1 inclusive
     * @param to   日期2 exclusive
     * @return 如果from大于to则会返回负数
     * @see LocalDateTime
     * @see Instant
     * @see ZonedDateTime
     * @see LocalTime
     */
    public static long betweenHours(Temporal from, Temporal to) {
        return ChronoUnit.HOURS.between(from, to);
    }

    /**
     * 相差多少分钟
     *
     * @param from 日期1 inclusive
     * @param to   日期2 exclusive
     * @return 如果from大于to则会返回负数
     * @see LocalDateTime
     * @see Instant
     * @see ZonedDateTime
     * @see LocalTime
     */
    public static long betweenMinutes(Temporal from, Temporal to) {
        return ChronoUnit.MINUTES.between(from, to);
    }

    /**
     * 相差多少秒
     *
     * @param from 日期1 inclusive
     * @param to   日期2 exclusive
     * @return 如果from大于to则会返回负数
     * @see LocalDateTime
     * @see Instant
     * @see ZonedDateTime
     * @see LocalTime
     */
    public static long betweenSeconds(Temporal from, Temporal to) {
        return ChronoUnit.SECONDS.between(from, to);
    }

    /**
     * {@param from} 和 {@param to} 是否同一天
     *
     * @param localDate1 日期1
     * @param localDate2 日期2
     * @return true {@param from} 和 {@param to} 同一天,否则 false
     */
    public static boolean isSameDay(LocalDate localDate1, LocalDate localDate2) {
        return localDate1.compareTo(localDate2) == 0;
    }

    /**
     * {@param from} 和 {@param to} 是否同一天
     *
     * @param localDateTime1 日期1
     * @param localDateTime2 日期2
     * @return true {@param from} 和 {@param to} 同一天,否则 false
     */
    public static boolean isSameDay(LocalDateTime localDateTime1, LocalDateTime localDateTime2) {
        return isSameDay(localDateTime1.toLocalDate(), localDateTime2.toLocalDate());
    }

    /**
     * 返回只包含日期,不包含时间属性的日期
     *
     * @return 只包含日期的日期
     */
    public static LocalDateTime getOnlyDay() {
        return LocalDateTime.now().truncatedTo(ChronoUnit.DAYS);
    }

    /**
     * 返回只包含日期,不包含时间属性的日期
     *
     * @param localDateTime 原始日期
     * @return 只包含日期的日期
     */
    public static LocalDateTime getOnlyDay(LocalDateTime localDateTime) {
        return localDateTime.truncatedTo(ChronoUnit.DAYS);
    }

    /**
     * LocalDateTime 转 Date
     *
     * @param localDateTime 需要转换的日期
     * @return Date 类型的日期
     */
    public static Date toDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * LocalDate 转 Date,时间部分初始化为00:00:00.0000000
     *
     * @param localDate 需要转换的日期
     * @return Date 类型的日期
     */
    public static Date toDate(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    /**
     * Date 转 LocalDateTime
     *
     * @param date 需要转换的日期
     * @return LocalDateTime 类型的日期
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    /**
     * 毫秒转LocalDateTime
     *
     * @param millis 毫秒数
     * @return LocalDateTime 类型的日期
     */
    public static LocalDateTime toLocalDateTime(long millis) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.systemDefault());
    }

    /**
     * LocalDate转LocalDateTime
     *
     * @param localDate LocalDate
     * @return LocalDateTime 类型的日期
     */
    public static LocalDateTime toLocalDateTime(LocalDate localDate) {
        return LocalDateTime.of(localDate, LocalTime.MIN);
    }

    /**
     * Date 转 LocalDate
     *
     * @param date 需要转换的日期
     * @return LocalDate 类型的日期
     */
    public static LocalDate toLocalDate(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).toLocalDate();
    }


    /**
     * 毫秒 转 LocalDate
     *
     * @param millis 需要转换的日期
     * @return LocalDate 类型的日期
     */
    public static LocalDate toLocalDate(long millis) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 获取毫秒
     *
     * @param localDateTime 日期
     * @return 毫秒
     */
    public static long toMillis(LocalDateTime localDateTime) {
        return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 获取毫秒(处在00:00:00.0000000时刻的毫秒)
     *
     * @param localDate 日期
     * @return 毫秒
     */
    public static long toMillis(LocalDate localDate) {
        return localDate.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 判断是否是合法的日期
     *
     * @param dateStr 日期字符串
     * @param pattern 日期的格式
     * @return true 合法,false 不合法
     */
    public static boolean isValid(String dateStr, String pattern) {
        try {
            DateTimeFormatter formatter = FORMATTERS.getOrDefault(pattern, DateTimeFormatter.ofPattern(pattern).withZone(ZoneId.systemDefault()));
            //之所以最后比较一遍是为了处理2月份的情况
            //比如,dateStr=2020-02-30 12:12:56, pattern=yyyy-MM-dd HH:mm:ss,
            //当使用parse方法时是不报错的,因为会自动处理为2020-02-29 12:12:56,
            //但是上面的情况不是我们想要的,因此最后比较一下即可
            return dateStr.equals(formatter.format(formatter.parse(dateStr)));
        } catch (Exception e) {
            //ignore
        }
        return false;
    }

    /**
     * 在指定日期上增加天数,然后返回只包含日期属性的日期
     *
     * @param localDateTime 日期
     * @param days          需要增加的天数
     * @return 只包含日期属性的日期
     */
    public static LocalDateTime getOnlyDay4FutureDate(LocalDateTime localDateTime, long days) {
        return localDateTime.plusDays(days).truncatedTo(ChronoUnit.DAYS);
    }

    /**
     * 是否是今天
     *
     * @param localDateTime 日期
     * @return true 是今天,false 不是今天
     */
    public static boolean isToday(LocalDateTime localDateTime) {
        return isSameDay(localDateTime.toLocalDate(), LocalDate.now());
    }

    /**
     * 是否是今天
     *
     * @param localDate 日期
     * @return true 是今天,false 不是今天
     */
    public static boolean isToday(LocalDate localDate) {
        return isSameDay(localDate, LocalDate.now());
    }


    /**
     * 判断目标日期是否在日期区间内
     *
     * @param target 目标日期
     * @param left   左边界日期,exclusive
     * @param right  右边界日期,exclusive
     * @return true 在,false 不在
     */
    public static boolean isInRange(LocalDate target, LocalDate left, LocalDate right) {
        return target.isAfter(left) && target.isBefore(right);
    }

    /**
     * 判断目标日期是否在日期区间内
     *
     * @param target 目标日期
     * @param left   左边界日期,exclusive
     * @param right  右边界日期,exclusive
     * @return true 在,false 不在
     */
    public static boolean isInRange(LocalDateTime target, LocalDateTime left, LocalDateTime right) {
        return target.isAfter(left) && target.isBefore(right);
    }


    /**
     * 比较目标时间点是否在区间中
     * 注意:此方法会涉及到次日逻辑,也就说{@param left} 可能大于 {@param right}
     * 比如:left:22:0,right:08:00,则表示时间段段是昨天22:00到次日08:00,因此target=03:00 也是合理的
     *
     * @param target 目标时间
     * @param left   左边界,格式HH:mm,exclusive
     * @param right  右边界,格式HH:mm,exclusive
     * @return true 在,false 不在
     * @see #PATTERN_HH_MM
     */
    public static boolean isInRange(LocalTime target, LocalTime left, LocalTime right) {
        return (target.isAfter(left) && target.isBefore(right))
                || (left.isAfter(right) && (target.isBefore(right) || target.isAfter(left)));
    }

    /**
     * 比较目标时间点是否在区间中
     * 注意:此方法会涉及到隔天逻辑,也就说{@param left} 可能大于 {@param right}
     * 比如:left:22:0,right:08:00,则表示时间段段是昨天22:00到次日08:00,因此target=03:00 也是合理的
     *
     * @param target 目标时间
     * @param left   左边界,格式HH:mm,exclusive
     * @param right  右边界,格式HH:mm,exclusive
     * @return true 在,false 不在
     * @see #PATTERN_HH_MM
     */
    public static boolean isInRange(LocalDateTime target, String left, String right) {
        LocalTime tt = target.toLocalTime();
        LocalTime lt = parseLocalTime(left, PATTERN_HH_MM);
        LocalTime rt = parseLocalTime(right, PATTERN_HH_MM);
        return isInRange(tt, lt, rt);
    }

    /**
     * 比较目标时间点是否在区间中
     * 注意:此方法会涉及到隔天逻辑,也就说{@param left} 可能大于 {@param right}
     * 比如:left:22:0,right:08:00,则表示时间段段是昨天22:00到次日08:00,因此target=03:00 也是合理的
     *
     * @param target 目标时间
     * @param left   左边界,格式HH:mm,exclusive
     * @param right  右边界,格式HH:mm,exclusive
     * @return true 在,false 不在
     * @see #PATTERN_HH_MM
     */
    public static boolean isInRange(String target, String left, String right) {
        LocalTime tt = parseLocalTime(target, PATTERN_HH_MM);
        LocalTime lt = parseLocalTime(left, PATTERN_HH_MM);
        LocalTime rt = parseLocalTime(right, PATTERN_HH_MM);
        return isInRange(tt, lt, rt);
    }

    /**
     * 返回指定小时和分钟的日期
     *
     * @param time 时间 HH:mm
     * @return 指定小时和分钟的日期
     * @see #PATTERN_HH_MM
     */
    public static LocalDateTime getDateTimeByHourMinute(String time) {
        LocalTime localTime = parseLocalTime(time, PATTERN_HH_MM);
        return getDateTimeByHourMinute(localTime.getHour(), localTime.getMinute());
    }

    /**
     * 返回指定小时和分钟的日期
     *
     * @param hour   小时
     * @param minute 分钟
     * @return
     */
    public static LocalDateTime getDateTimeByHourMinute(int hour, int minute) {
        return LocalDateTime.of(LocalDateTime.now().toLocalDate(), LocalTime.of(hour, minute));
    }

    /**
     * 获取某月的第一天,时间是午夜
     *
     * @param year  年份
     * @param month 月份,1-12
     * @return 返回该月的第一天,时间是午夜
     */
    public static LocalDateTime getStartDayOfMonth(int year, int month) {
        return LocalDateTime.of(
                LocalDate.of(year, month, 1),
                LocalTime.MIN);
    }

    /**
     * 获取某月的第一天,时间是午夜
     *
     * @param localDateTime 日期
     * @return 返回该月的第一天,时间是午夜
     */
    public static LocalDateTime getStartDayOfMonth(LocalDateTime localDateTime) {
        return LocalDateTime.of(
                localDateTime
                        .withDayOfMonth(1)
                        .toLocalDate(),
                LocalTime.MIN);
    }

    /**
     * 获取某月的第一天
     *
     * @param localDate 日期
     * @return 返回该月的第一天
     */
    public static LocalDate getStartDayOfMonth(LocalDate localDate) {
        return localDate.withDayOfMonth(1);
    }

    /**
     * 获取每月的最后一天
     *
     * @param year  年份
     * @param month 月份,1-12
     * @return 返回该月的最后一天
     */
    public static LocalDateTime getEndDayOfMonth(int year, int month) {
        return LocalDateTime.of(
                LocalDate.now()
                        .withYear(year)
                        .withMonth(month)
                        .with(TemporalAdjusters.lastDayOfMonth()),
                LocalTime.MAX);
    }


    /**
     * 获取某月的最后一天
     *
     * @param localDateTime 日期
     * @return 返回该月的最后一天
     */
    public static LocalDateTime getEndDayOfMonth(LocalDateTime localDateTime) {
        return LocalDateTime.of(
                localDateTime
                        .with(TemporalAdjusters.lastDayOfMonth())
                        .toLocalDate(),
                LocalTime.MAX);
    }

    /**
     * 获取某月的最后一天
     *
     * @param localDate 日期
     * @return 返回该月的最后一天
     */
    public static LocalDate getEndDayOfMonth(LocalDate localDate) {
        return localDate.with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 时间字符串转时间戳,时间以半点为分界:
     * 小于半点(=30),向上取整
     *
     * @param time 时间,格式 yyyy-MM-dd HH:mm,如 2020-10-30 17:20
     * @return 毫秒数
     * @see #PATTERN_YYYY_MM_DD_HH_MM
     */
    public static long truncateByHalfHour(String time) {
        LocalDateTime localDateTime = parseLocalDateTime(time, PATTERN_YYYY_MM_DD_HH_MM);
        return toMillis(truncateByHalfHour(localDateTime));
    }


    /**
     * 时间以半点(30分)为分界:
     * 小于半点(=30),向上取整
     *
     * @param localDateTime
     * @return LocalDateTime
     */
    public static LocalDateTime truncateByHalfHour(LocalDateTime localDateTime) {
        LocalDateTime resultTime = localDateTime.getMinute()             
关注
打赏
1661428283
查看更多评论
0.0488s