一文搞定LocalDate、LocalTime、LocalDateTime

在Java 8中,JDK引入了全新的时间日期API(java.time包),目的是替代旧的java.util.Datejava.util.Calendar等类,提供更安全、更高效、更易用的方式来处理日期和时间。LocalDateLocalTimeLocalDateTime是其中三个非常重要的类,它们是java.time包中的核心类,分别用来表示日期、时间和日期时间。

java.time包中的核心类

  • LocalDate:表示没有时区的日期,包含:年月日。格式为:2024-01-13
  • LocalTime:表示没有时区的时间,包含:时分秒。格式为:16:39:09.307
  • LocalDateTime:表示没有时区的日期时间,包含:年月日 时分秒。格式为:2024-01-13T16:40:59.138
  • DateTimeFormatter:日期时间格式化类
  • Instant:用于表示时间线上的某一时刻,精确到纳秒
  • Duration:用于计算两个时间之间的间隔
  • Period:用于计算两个日期之间的间隔
  • ZonedDateTime:包含时区的时间
  • ZoneId: 时区ID,用来确定InstantLocalDateTime互相转换的规则
  • Clock: 用于访问当前时刻、日期、时间,用到时区

LocalDate

LocalDate类表示没有时间部分的日期,精确到年、月、日。它不包含时区信息,也不包括具体的时间部分。

LocalDate的创建

public class LocalDateTest {
    public static void main(String[] args) {

        // 1. 使用now()方法获取当前日期(默认使用系统时区)
        LocalDate currentDate = LocalDate.now();
        System.out.println("Current date: " + currentDate);

        // 2. 使用指定的年月日创建日期
        LocalDate date = LocalDate.of(2024, 10, 13);
        System.out.println("Specific date: " + date);

        // 3. 从字符串解析日期(字符串格式必须符合ISO-8601标准,如yyyy-MM-dd)
        LocalDate dateFromString = LocalDate.parse("2024-11-13");
        System.out.println("Parsed date: " + dateFromString);
    }
}
Current date: 2024-11-13
Specific date: 2024-10-13
Parsed date: 2024-11-13

常用方法

public class LocalDateTest {
    public static void main(String[] args) {

        // 1. 使用now()方法获取当前日期(默认使用系统时区)
        LocalDate currentDate = LocalDate.now();
        System.out.println("Current date: " + currentDate);

        // 2. 常用方法
        // 获取日期的各个部分
        System.out.println("当前日期所属年份:" + currentDate.getYear());
        System.out.println("当前日期所属月份(英文):" + currentDate.getMonth());
        System.out.println("当前日期所属月份(数字):" + currentDate.getMonthValue());
        System.out.println("当前日期是本年第几天:" + currentDate.getDayOfYear());
        System.out.println("当前日期是本月第几天:" + currentDate.getDayOfMonth());
        System.out.println("当前日期是本周第几天(英文星期几):" + currentDate.getDayOfWeek());
        // ...
    }
}
Current date: 2024-11-13

当前日期所属年份:2024
当前日期所属月份(英文):NOVEMBER
当前日期所属月份(数字):11
当前日期是本年第几天:318
当前日期是本月第几天:13
当前日期是本周第几天(英文星期几):WEDNESDAY

LocalTime

LocalTime的创建

和LocalDate的创建类似

// 1. 使用now()方法获取当前时间(默认使用系统时区)
LocalTime currentTime = LocalTime.now();
System.out.println("Current time: " + currentTime);

// 2. 使用指定的 时分秒 创建时间
LocalTime time = LocalTime.of(16, 10, 13);
System.out.println("Specific time: " + time);

// 3. 从字符串解析时间(字符串格式必须符合ISO-8601标准,如HH:mm:ss)
LocalTime timeFromString = LocalTime.parse("16:10:13");
System.out.println("Parsed time: " + timeFromString);
Current time: 16:31:54.965
Specific time: 16:10:13
Parsed time: 16:10:13

常用方法

public static void main(String[] args) {
    // 1. 使用now()方法获取当前时间(默认使用系统时区)
    LocalTime currentTime = LocalTime.now();
    System.out.println("Current time: " + currentTime);

    // 2. 常用方法
    // 获取时间的各个部分
    System.out.println("获取当前时间的小时:" + currentTime.getHour());
    System.out.println("获取当前时间的分钟:" + currentTime.getMinute());
    System.out.println("获取当前时间的秒:" + currentTime.getSecond());
    System.out.println("获取当前时间的纳秒:" + currentTime.getNano());
    // ...
}
Current time: 16:31:54.965

获取当前时间的小时:16
获取当前时间的分钟:31
获取当前时间的秒:54
获取当前时间的纳秒:965000000

LocalDateTime

创建方法和前面的大同小异

public class LocalDateTimeTest {

    public static void main(String[] args) {
        // 1. 使用now()方法获取当前日期时间(默认使用系统时区)
        LocalDateTime currentDateTime = LocalDateTime.now();
        System.out.println("Current dateTime: " + currentDateTime); // 2024-11-13T16:40:59.697

        // 2. 使用指定的 年月日 时分秒 创建日期时间
        LocalDateTime dateTime = LocalDateTime.of(2024,11,13,16, 10, 13);
        System.out.println("Specific dateTime: " + dateTime); // 2024-11-13T16:10:13

        // 3. 从字符串解析时间(字符串格式必须符合ISO-8601标准,如HH:mm:ss)
        LocalDateTime dateTimeFromString = LocalDateTime.parse("2024-11-13T10:15:30");
        System.out.println("Parsed dateTime: " + dateTimeFromString); // 2024-11-13T10:15:30

        // 4. 常用方法
        // 获取日期时间的各个部分
        System.out.println("当前日期所属年份:" + currentDateTime.getYear()); // 2024
        System.out.println("当前日期所属月份(英文):" + currentDateTime.getMonth()); // NOVEMBER
        System.out.println("当前日期所属月份(数字):" + currentDateTime.getMonthValue()); // 11
        System.out.println("当前日期是本年第几天:" + currentDateTime.getDayOfYear()); // 318
        System.out.println("当前日期是本月第几天:" + currentDateTime.getDayOfMonth()); // 13
        System.out.println("当前日期是本周第几天(英文星期几):" + currentDateTime.getDayOfWeek()); // WEDNESDAY
        System.out.println("获取当前日期时间的小时:" + currentDateTime.getHour()); // 16
        System.out.println("获取当前日期时间的分钟:" + currentDateTime.getMinute()); // 40
        System.out.println("获取当前日期时间的秒:" + currentDateTime.getSecond()); // 59
        System.out.println("获取当前日期时间的纳秒:" + currentDateTime.getNano()); // 697000000
    }
}

日期时间加减

public class LocalDateTimeTest {

    public static void main(String[] args) {
        // 1. 使用now()方法获取当前日期时间(默认使用系统时区)
        LocalDateTime currentDateTime = LocalDateTime.now();
        System.out.println("Current dateTime: " + currentDateTime); // 2024-11-13T16:40:59.697

        System.out.println("===========时间日期的加减============");
        System.out.println("当前日期时间:" + currentDateTime);
        System.out.println(currentDateTime + "--->增加2年后的时间是:" + currentDateTime.plusYears(2));
        System.out.println(currentDateTime + "--->增加3月后的时间是:" + currentDateTime.plusMonths(3));
        System.out.println(currentDateTime + "--->减少1年后的时间是:" + currentDateTime.minusYears(1));
        System.out.println(currentDateTime + "--->减少13月后的时间是:" + currentDateTime.minusMonths(13));
        System.out.println(currentDateTime + "--->增加1小时后的时间是:" + currentDateTime.plusHours(1));
        System.out.println(currentDateTime + "--->增加30分钟后的时间是:" + currentDateTime.plusMinutes(30));

    }


}
Current dateTime: 2024-11-13T16:49:22.260


===========时间日期的加减============
当前日期时间:2024-11-13T16:49:22.260
2024-11-13T16:49:22.260--->增加2年后的时间是:2026-11-13T16:49:22.260
2024-11-13T16:49:22.260--->增加3月后的时间是:2025-02-13T16:49:22.260
2024-11-13T16:49:22.260--->减少1年后的时间是:2023-11-13T16:49:22.260
2024-11-13T16:49:22.260--->减少13月后的时间是:2023-10-13T16:49:22.260
2024-11-13T16:49:22.260--->增加1小时后的时间是:2024-11-13T17:49:22.260
2024-11-13T16:49:22.260--->增加30分钟后的时间是:2024-11-13T17:19:22.260

这里需要注意的是,LocalDate、LocalTime、LocalDateTime类的实例是不可变的,在对象上进行日期和时间的加减,不改变原有对象的值,这里是复制了一个新的对象来进行修改的,修改后的对象和原对象是两个不同的对象。

日期时间比较

public static void main(String[] args) {
    // 时间1
    LocalDateTime currentDateTime1 = LocalDateTime.now();
    // 时间2
    LocalDateTime currentDateTime2 = LocalDateTime.parse("2023-10-10T01:01:01");
    System.out.println("时间1在时间2前面吗?-----》" + currentDateTime1.isBefore(currentDateTime2));
    System.out.println("时间1在时间2后面吗?-----》" + currentDateTime1.isAfter(currentDateTime2));

}
时间1在时间2前面吗?-----false
时间1在时间2后面吗?-----true

计算日期时间差

jdk8中,提供了DurationPeriod类来计算日期时间的差值

Duration类:比较两个时间(LocalTime)的差值

Period类:比较两个日期(LocalDate)的差值

Duration类

public class DurationAndPeriodTest {
    public static void main(String[] args) {
        // Duration类 比较两个时间LocalTime的差值
        LocalTime time1 = LocalTime.now();
        System.out.println("time1 :" + time1);
        LocalTime time2 = LocalTime.of(12, 23, 23);
        System.out.println("time2 :" + time2);
        Duration duration = Duration.between(time2, time1);
        System.out.println("相差的小时数:" + duration.toHours());
        System.out.println("相差的分钟数:" + duration.toMinutes());
    }
}
time1 :17:22:00.981
time2 :12:23:23
相差的小时数:4
相差的分钟数:298

Duration.between()方法是用第二个参数减去第一个参数的值,这里注意位置,避免得出的结果是负数

Period类

public class DurationAndPeriodTest {
    public static void main(String[] args) {
        
        // Period类 比较两个日期LocalDate的差值
        LocalDate date1 = LocalDate.now();
        System.out.println("date1 :" + date1);
        LocalDate date2 = LocalDate.of(2022, 9, 1);
        System.out.println("date2 :" + date2);
        Period period = Period.between(date2, date1);
        System.out.println("相差的年数:" + period.getYears());
        System.out.println("相差的天数:" + period.getDays());
        System.out.println("相差的月数:" + period.getMonths());

    }
}
date1 :2024-11-13
date2 :2022-09-01
相差的年数:2
相差的天数:12
相差的月数:2

注意,这里有个坑,Period在比较的时候,并不是计算总的差值,而是各字段上的时间差,这里的月份和天数都不对,这就有点难受了。

Period的坑及解决办法

对于获取相差的月份来说,Period给了toTotalMonths()方法,获取总相差的月份

public long toTotalMonths() {
    return years * 12L + months;  // no overflow
}
// Period类 比较两个日期LocalDate的差值
LocalDate date1 = LocalDate.now();
System.out.println("date1 :" + date1);
LocalDate date2 = LocalDate.of(2022, 9, 1);
System.out.println("date2 :" + date2);
Period period = Period.between(date2, date1);

System.out.println("总的相差的月份数:" + period.toTotalMonths());
date1 :2024-11-13
date2 :2022-09-01

总的相差的月份数:26

对于天数的统计,可以用ChronoUnit.DAYS.between()

// Period类 比较两个日期LocalDate的差值
LocalDate date1 = LocalDate.now();
System.out.println("date1 :" + date1);
LocalDate date2 = LocalDate.of(2022, 9, 1);
System.out.println("date2 :" + date2);
Period period = Period.between(date2, date1);
System.out.println("相差的年数:" + period.getYears());
System.out.println("相差的天数:" + period.getDays());
System.out.println("相差的月数:" + period.getMonths());

System.out.println("总的相差的月份数:" + period.toTotalMonths());
long days = ChronoUnit.DAYS.between(date2, date1);
System.out.println("总的相差的天数:" + days);
date1 :2024-11-13
date2 :2022-09-01

总的相差的月份数:26
总的相差的天数:804

DateTimeFormatter 日期时间格式化与解析

DateTimeFormatter是Java 8中用于格式化和解析日期时间的工具类。专门用于格式化和解析LocalDateLocalTimeLocalDateTime以及ZonedDateTime等日期和时间对象。通过DateTimeFormatter,我们可以将这些日期和时间对象转化为指定格式的字符串,也可以将符合特定格式的字符串解析为日期和时间对象。

标准格式

DateTimeFormatter类中,预定义了很多种标准格式

一文搞定LocalDate、LocalTime、LocalDateTime_第1张图片

比如DateTimeFormatter.ISO_LOCAL_DATE 用于格式化或解析LocalDate对象,格式为 yyyy-MM-dd

public static final DateTimeFormatter ISO_LOCAL_DATE;
static {
    ISO_LOCAL_DATE = new DateTimeFormatterBuilder()
            .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
            .appendLiteral('-')
            .appendValue(MONTH_OF_YEAR, 2)
            .appendLiteral('-')
            .appendValue(DAY_OF_MONTH, 2)
            .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
}

自定义格式

使用DateTimeFormatter.ofPattern()自定义日期时间格式化类型,

日期时间对象使用format()方法进行格式化输出为字符串

使用parse()方法解析字符串为时间日期对象

public static void main(String[] args) {
    LocalDateTime dateTime = LocalDateTime.now();
    System.out.println("当前日期时间:" + dateTime);

    // 设置格式化样式
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
    // 格式化
    String formattedDateTime = dateTime.format(formatter);
    System.out.println("格式化后的日期时间对象: " + formattedDateTime);

    // 解析
    String dateStr = "2024-11-13 18:15:53";
    DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    LocalDate dateTime1 = LocalDate.parse(dateStr, formatter2);
    System.out.println("解析后的日期对象:" + dateTime1);

}
当前日期时间:2024-11-13T18:21:54.663
格式化后的日期时间对象: 2024111318:21:54
解析后的日期对象:2024-11-13

DateTimeFormatter不可变的线程安全的,因此它可以被多个线程共享。在实际应用中,建议创建一个DateTimeFormatter实例并在整个应用中复用,而不是每次需要格式化或解析时都创建一个新的实例。

时间带时区

前面提到,LocalDateLocalTimeLocalDateTime 是不带时区的,如果要加入时区,与之对应的有三个类,分别是ZonedDateZonedTimeZonedDateTime

举个例子

public static void main(String[] args) {
    // 使用计算机默认时区
    ZonedDateTime defaultNow = ZonedDateTime.now();
    System.out.println("当前本地时间:" + defaultNow);

    // 世界标准时间
    ZonedDateTime zdt = ZonedDateTime.now(Clock.systemUTC());
    System.out.println("世界标准时间: " + zdt);

    System.out.println("==========改变时区==========");
    ZonedDateTime zonedDateTime = zdt.withZoneSameInstant(ZoneId.systemDefault());
    System.out.println("设置为系统默认时区后的时间:" + zonedDateTime);
    ZonedDateTime zonedDateTime1 = zdt.withZoneSameInstant(ZoneId.of("Asia/Shanghai"));
    System.out.println("设置为东八区后的时间:" + zonedDateTime1);


}
当前本地时间:2024-11-13T18:36:45.277+08:00[Asia/Shanghai]
世界标准时间: 2024-11-13T10:36:45.278Z
==========改变时区==========
设置为系统默认时区后的时间:2024-11-13T18:36:45.278+08:00[Asia/Shanghai]
设置为东八区后的时间:2024-11-13T18:36:45.278+08:00[Asia/Shanghai]

Java 8中Date与LocalDateTime、LocalDate、LocalTime的互转

这里主要说下 DateLocalDateTimeLocalDate 进行互转的情况,而对于 LocalTimeDate 的转换其实意义不大,这里就不再赘述。

Date转换为LocalDateTime

先将 Date 对象转换为 Instant ,然后设置时区,进而转为 LocalDateTime

Date date = new Date();
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

LocalDateTime转换为Date

先设置时区,再转为 Instant,最后借助 Date.from 转为 Date 类型

LocalDateTime localDateTime = LocalDateTime.now();
Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

Date转换为LocalDate

这个和 Date 转为 localDateTime 类似,只是转为 LocalDate 时去掉了时间部分

Date date = new Date();
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

LocalDate转换为Date

LocalDate 是没有时间部分的,转为 Date 时先通过atStartOfDay设置时间为一天的开始,进而转为 Date 类型。

LocalDate localDate = LocalDate.now();
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());

你可能感兴趣的:(java基础,Java,LocalDate,Java基础)