java的时间操作介绍

一:介绍

Java 提供了多套日期时间 API,以下是主要类别的对比和常用方法总结:

|-------|----------------------------------------------------------------|------|-----|--------|-------------|
| 类别 | 主要类 | 线程安全 | 可变性 | java版本 | 特点 |
| 传统日期 | Date, Calendar,GregorianCalendar | 否 | 可变 | 1.0+ | 设计缺陷多,不推荐使用 |
| 新日期时间 | LocalDate, LocalTime, LocalDateTime, ZonedDateTime, ChronoUnit | 是 | 不可变 | 8+ | 设计良好,推荐使用 |
| 时间戳 | Instant | 是 | 不可变 | 8+ | 机器时间,精确到纳秒 |
| 格式化 | DateTimeFormatter | 是 | 不可变 | 8+ | 线程安全的格式化类 |

二:Date类

Java 中的 Date 类位于 java.util 包中,它表示特定的瞬间,精确到毫秒。

Date 类主要用于表示日期和时间信息,是 Java 中处理日期和时间的基础类之一。

复制代码
Date date = new Date();

// 获取自1970年1月1日00:00:00 GMT以来的毫秒数
long timeInMillis = date.getTime();

// 设置时间 (从1970年1月1日00:00:00 GMT开始的毫秒数)
date.setTime(1640995200000L);

// 比较两个日期
Date anotherDate = new Date();
int result = date.compareTo(anotherDate); // 小于返回-1,等于返回0,大于返回1

// 检查日期是否在指定日期之后
boolean isAfter = date.after(anotherDate);

// 检查日期是否在指定日期之前
boolean isBefore = date.before(anotherDate);

Date类的局限性

  • 不是线程安全的:Date 对象是可变的,这在多线程环境中可能会出现问题。
  • 设计不佳:月份从0开始(0表示1月),年份从1900年开始计算,这容易导致混淆。
  • 时区处理复杂:Date 类本身不包含时区信息,时区处理需要额外的类。
  • 功能有限:缺乏许多常用的日期操作功能,如加减天数、周数等。

三:Calendar类

Calendar 类是 Java 中用于处理日期和时间的抽象类,它位于 java.util 包中。这个类提供了一系列方法来操作日期和时间字段(如年、月、日、小时、分钟等),并且可以执行日期计算和比较。

复制代码
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);       // 获取年份
int month = calendar.get(Calendar.MONTH);     // 获取月份(0-11)
int day = calendar.get(Calendar.DAY_OF_MONTH);// 获取日
int hour = calendar.get(Calendar.HOUR_OF_DAY);// 获取小时(24小时制)
int minute = calendar.get(Calendar.MINUTE);   // 获取分钟
int second = calendar.get(Calendar.SECOND);   // 获取秒

// 在当前日期上加10天
calendar.add(Calendar.DAY_OF_MONTH, 10);

// 在当前月份上减3个月
calendar.add(Calendar.MONTH, -3);


//日期比较
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal2.add(Calendar.DAY_OF_MONTH, 1);
// result < 0 表示 cal1 早于 cal2
// result == 0 表示 cal1 等于 cal2
// result > 0 表示 cal1 晚于 cal2
int result = cal1.compareTo(cal2);

//获取时间戳(毫秒数)
long timestamp = calendar.getTimeInMillis();

//设置时区
TimeZone timeZone = TimeZone.getTimeZone("America/New_York");
calendar.setTimeZone(timeZone);

Calendar 类的注意事项

  • 月份从0开始:Calendar 类中月份是从0开始的(0=一月,11=十二月),这容易导致错误。
  • 可变性:Calendar 对象是可变的,修改一个 Calendar 对象会影响所有引用它的地方。
  • 线程安全:Calendar 类不是线程安全的,多线程环境下需要额外同步。
  • 性能:频繁创建 Calendar 实例会影响性能,可以考虑重用实例。
  • 时区问题:默认使用系统时区,跨时区应用需要特别注意。

四:GregorianCalendar类

GregorianCalendar 是 Java 中一个表示公历(格里高利历)的日历类,它继承自 Calendar 类。这个类提供了标准的日历系统,也是世界上大多数国家使用的日历系统。

GregorianCalendar 类位于 java.util 包中,用于处理日期和时间相关的操作。它支持从公元 1 年到未来的日期计算,并考虑了闰年等复杂的日历规则。

复制代码
//创建实例
// 创建表示当前日期和时间的实例
GregorianCalendar calendar1 = new GregorianCalendar();
// 创建指定年份、月份、日期的实例
// 注意:月份从0开始,0表示1月
GregorianCalendar calendar2 = new GregorianCalendar(2023, 10, 15);
// 创建指定年份、月份、日期、小时、分钟的实例
GregorianCalendar calendar3 = new GregorianCalendar(2023, 10, 15, 14, 30);
// 创建指定年份、月份、日期、小时、分钟、秒的实例
GregorianCalendar calendar4 = new GregorianCalendar(2023, 10, 15, 14, 30, 45);


//获取日期和时间信息
GregorianCalendar calendar = new GregorianCalendar();

int year = calendar.get(Calendar.YEAR);       // 获取年份
int month = calendar.get(Calendar.MONTH);    // 获取月份(0-11)
int day = calendar.get(Calendar.DAY_OF_MONTH); // 获取日期
int hour = calendar.get(Calendar.HOUR_OF_DAY); // 获取小时(24小时制)
int minute = calendar.get(Calendar.MINUTE);   // 获取分钟
int second = calendar.get(Calendar.SECOND);   // 获取秒


//设置日期和时间
GregorianCalendar calendar = new GregorianCalendar();
// 设置年份
calendar.set(Calendar.YEAR, 2024);
// 设置月份(0-11)
calendar.set(Calendar.MONTH, Calendar.JANUARY);
// 设置日期
calendar.set(Calendar.DAY_OF_MONTH, 1);
// 同时设置年、月、日
calendar.set(2024, Calendar.JANUARY, 1);


//日期计算
GregorianCalendar calendar = new GregorianCalendar(2023, Calendar.NOVEMBER, 15);
// 增加10天
calendar.add(Calendar.DAY_OF_MONTH, 10);
// 减少2个月
calendar.add(Calendar.MONTH, -2);


//比较日期
GregorianCalendar cal1 = new GregorianCalendar(2023, Calendar.NOVEMBER, 15);
GregorianCalendar cal2 = new GregorianCalendar(2023, Calendar.DECEMBER, 25);
// 比较两个日期
int result = cal1.compareTo(cal2);  // cal1在cal2之前返回负数,之后返回正数,相等返回0
// 判断是否在某个日期之前
boolean isBefore = cal1.before(cal2);
// 判断是否在某个日期之后
boolean isAfter = cal1.after(cal2);

五:LocalDate类

LocalDate 是 Java 8 中引入的一个不可变日期类,属于 java.time 包的一部分。

LocalDate 表示不带时区的日期(年-月-日),例如 "2023-05-15"。LocalDate 不包含时间和时区信息,非常适合处理生日、节假日等只需要日期的场景。

LocalDate特点:

  1. 不可变性

LocalDate 实例是不可变的,任何修改操作都会返回一个新的 LocalDate 对象,而不是修改原有对象。

  1. 线程安全

由于不可变性,LocalDate 是线程安全的,可以在多线程环境中安全使用。

  1. ISO-8601 标准

LocalDate 遵循 ISO-8601 日历系统,这是现代日期和时间表示的国际标准。

复制代码
//获取当前日期
LocalDate today = LocalDate.now();
System.out.println("今天的日期: " + today);


//获取日期信息
LocalDate date = LocalDate.of(2023, 5, 15);
int year = date.getYear();        // 2023
Month month = date.getMonth();    // MAY
int day = date.getDayOfMonth();   // 15
DayOfWeek dow = date.getDayOfWeek(); // MONDAY
int len = date.lengthOfMonth();   // 31 (5月的天数)
boolean leap = date.isLeapYear(); // false (2023不是闰年)

//日期加减
LocalDate tomorrow = today.plusDays(1); //+1天
LocalDate nextWeek = today.plusWeeks(1); //+1周
LocalDate nextMonth = today.plusMonths(1); //+1月
LocalDate nextYear = today.plusYears(1); //+1年
LocalDate yesterday = today.minusDays(1); //-1天


//日期比较
LocalDate date1 = LocalDate.of(2023, 5, 15);
LocalDate date2 = LocalDate.of(2023, 6, 20);

boolean isBefore = date1.isBefore(date2); // true
boolean isAfter = date1.isAfter(date2);   // false
boolean isEqual = date1.isEqual(date2);   // false

六:LocalTime类

LocalTime 是 Java 8 引入的日期时间 API (java.time 包)中的一个重要类,用于表示不带时区信息的时间。它专门处理一天中的时间,精确到纳秒级别。

LocalTime特点:

  1. 不可变性

LocalTime 是不可变类,所有修改操作都会返回新的实例,原始对象保持不变。

  1. 无时区信息

LocalTime 不包含时区信息,仅表示本地时间。

  1. 时间精度

支持从小时到纳秒的时间精度(HH:mm:ss.nnnnnnnnn)。

复制代码
LocalTime currentTime = LocalTime.now();
System.out.println("当前时间: " + currentTime); //当前时间: 16:07:57.111878700


// 创建 14:30:00 
LocalTime time1 = LocalTime.of(14, 30);

// 创建 09:15:30 
LocalTime time2 = LocalTime.of(9, 15, 30);

// 创建 10:20:30.500 (500毫秒) 
LocalTime time3 = LocalTime.of(10, 20, 30, 500000000);


//时间比较
LocalTime time1 = LocalTime.of(10, 30);
LocalTime time2 = LocalTime.of(11, 15);

boolean isBefore = time1.isBefore(time2);  // true
boolean isAfter = time1.isAfter(time2);    // false
boolean isEqual = time1.equals(time2);     // false


//时间运算
LocalTime time = LocalTime.of(9, 0);

// 加2小时 
LocalTime plusHours = time.plusHours(2); // 11:00

// 减30分钟 
LocalTime minusMinutes = time.minusMinutes(30); // 08:30

// 加1小时15分钟 
LocalTime plusDuration = time.plus(Duration.ofMinutes(75)); // 10:15

七:LocalDateTime类

LocalDateTime 是 Java 8 引入的日期时间 API(java.time 包)中的一个重要类,它表示一个不可变的日期时间对象,不包含时区信息。这个类可以存储年、月、日、时、分、秒和纳秒级别的日期时间信息。

LocalDateTime特点:

  • 不可变性:所有 java.time 类都是不可变的,线程安全

  • 不包含时区:只表示本地日期和时间

  • 精确到纳秒:可以表示精确到纳秒级别的时间

  • 丰富的 API:提供了大量方法用于日期时间计算和格式化

    LocalDateTime dateTime = LocalDateTime.now();

    //时间获取
    int year = dateTime.getYear();//年
    int monthValue = dateTime.getMonthValue(); //月 返回 1-12
    int day = dateTime.getDayOfMonth();//日
    int hour = dateTime.getHour();//时
    int minute = dateTime.getMinute();//分
    int second = dateTime.getSecond();//秒
    int nano = dateTime.getNano();//毫秒

    //时间计算
    // 加操作
    LocalDateTime plusYears = dateTime.plusYears(1);
    LocalDateTime plusMonths = dateTime.plusMonths(1);
    LocalDateTime plusDays = dateTime.plusDays(1);
    LocalDateTime plusHours = dateTime.plusHours(1);
    LocalDateTime plusMinutes = dateTime.plusMinutes(1);
    LocalDateTime plusSeconds = dateTime.plusSeconds(1);

    // 减操作
    LocalDateTime minusYears = dateTime.minusYears(1);
    LocalDateTime minusDays = dateTime.minusDays(1);

    //时间比较
    LocalDateTime dateTime1 = LocalDateTime.of(2023, 5, 15, 14, 30);
    LocalDateTime dateTime2 = LocalDateTime.of(2023, 5, 16, 14, 30);

    boolean isBefore = dateTime1.isBefore(dateTime2); // true
    boolean isAfter = dateTime1.isAfter(dateTime2); // false
    boolean isEqual = dateTime1.isEqual(dateTime2); // false

八:ZonedDateTime类

ZonedDateTime 是 Java 8 引入的日期时间 API (java.time 包)中的一个重要类,它表示带有时区的日期和时间。这个类结合了 LocalDateTime 和 ZoneId,能够精确地表示特定时区的时间点。

ZonedDateTime特点:

包含日期(年、月、日)

包含时间(时、分、秒、纳秒)

包含时区信息

是不可变且线程安全的类

支持时区转换和夏令时自动调整

复制代码
// 获取当前系统默认时区的日期时间
ZonedDateTime now = ZonedDateTime.now();

// 获取指定时区的当前日期时间
ZonedDateTime nowInTokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));


//时间获取
ZonedDateTime zdt = ZonedDateTime.now();

int year = zdt.getYear();          // 年
Month month = zdt.getMonth();      // 月
int day = zdt.getDayOfMonth();     // 日
int hour = zdt.getHour();          // 时
int minute = zdt.getMinute();      // 分
int second = zdt.getSecond();      // 秒
ZoneId zone = zdt.getZone();       // 时区


//时间加减操作
ZonedDateTime zdt = ZonedDateTime.now();
// 加1天
ZonedDateTime tomorrow = zdt.plusDays(1);
// 减2小时
ZonedDateTime twoHoursEarlier = zdt.minusHours(2);
// 加3周
ZonedDateTime threeWeeksLater = zdt.plusWeeks(3);

九:ChronoUnit类

ChronoUnit 是 Java 8 引入的一个枚举类,属于 java.time.temporal 包。

ChronoUnit 定义了一组标准的时间单位,用于表示日期和时间的不同粒度。ChronoUnit 主要用于与 Java 8 日期时间 API(如 LocalDate、LocalTime、LocalDateTime 等)一起使用,进行时间的计算和比较。

复制代码
LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS); // 加一周
LocalDate lastMonth = today.minus(1, ChronoUnit.MONTHS); // 减一个月

//时间差计算
LocalDate start = LocalDate.of(2023, 1, 1);
LocalDate end = LocalDate.of(2023, 12, 31);
long days = ChronoUnit.DAYS.between(start, end); // 计算天数差


//计算年龄
LocalDate birthDate = LocalDate.of(1990, 5, 15);
LocalDate now = LocalDate.now();
long age = ChronoUnit.YEARS.between(birthDate, now);
System.out.println("年龄: " + age + " 岁");

十:Instant类

Instant 类是 Java 8 引入的日期时间 API (java.time 包)中的一个重要类,它代表时间线上的一个瞬时点。这个类主要用于记录时间戳,精确到纳秒级别。

Instant特点:

表示从 1970-01-01T00:00:00Z (即 Unix 纪元)开始的时间

不包含时区信息

是不可变且线程安全的

精确到纳秒(而传统的 Date 类只精确到毫秒)

复制代码
Instant now = Instant.now();  // 获取当前时刻


//时间错获取
long seconds = instant.getEpochSecond();  // 获取从1970-01-01开始的秒数
int nanos = instant.getNano();  // 获取纳秒部分


//时间比较
Instant instant1 = Instant.now();
Instant instant2 = instant1.plusSeconds(10);

boolean isBefore = instant1.isBefore(instant2);  // true
boolean isAfter = instant1.isAfter(instant2);  // false


//时间运算
Instant instant = Instant.now();

// 加10秒
Instant later = instant.plusSeconds(10);

// 减5分钟
Instant earlier = instant.minus(Duration.ofMinutes(5));

// 加2天4小时30分钟
Instant future = instant.plus(2, ChronoUnit.DAYS)
                       .plus(4, ChronoUnit.HOURS)
                       .plus(30, ChronoUnit.MINUTES);

十一:DateTimeFormatter类

DateTimeFormatter 是 Java 8 引入的日期时间 API (java.time 包) 中的一个重要类,它用于格式化和解析日期时间对象。这个类提供了强大的功能来处理日期时间的显示和转换。

复制代码
LocalDateTime now = LocalDateTime.now();

// 使用预定义的格式化器
System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE));     // 2023-11-15
System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_TIME));     // 14:30:45.123
System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); // 2023-11-15T14:30:45.123


DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = now.format(formatter);  // 格式化
System.out.println(formattedDateTime);             // 2023-11-15 14:30:45

// 解析
LocalDateTime parsedDateTime = LocalDateTime.parse("2023-11-15 14:30:45", formatter);

// 常用中文日期格式
DateTimeFormatter chineseFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
String formattedDate = today.format(chineseFormatter);
System.out.println("中文格式日期: " + formattedDate);

// 解析中文日期字符串
String chineseDateStr = "2023年05月20日";
LocalDate parsedDate = LocalDate.parse(chineseDateStr, chineseFormatter);
System.out.println("解析后的日期: " + parsedDate);

// 其他常用格式
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("MM/dd/yyyy");
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 EEEE", Locale.CHINA);

System.out.println("格式1: " + today.format(formatter1));
System.out.println("格式2: " + today.format(formatter2));
System.out.println("格式3(带星期): " + today.format(formatter3));
相关推荐
就不掉头发2 小时前
C++右值与右值引用
开发语言·c++
IT猿手2 小时前
基于 CBF 的多无人机编队动态避障路径规划研究,无人机及障碍物数量可以自定义修改,MATLAB代码
开发语言·matlab·无人机·动态路径规划
炸膛坦客2 小时前
单片机/C/C++八股:(十六)C 中 malloc/free 和 C++ 中 new/delete 有什么区别?
c语言·开发语言·c++
@insist1232 小时前
软件设计师-组网技术基础:网络设备、传输介质与局域网核心协议
开发语言·网络·软考·软件设计师·软件水平考试
毕设源码-朱学姐2 小时前
【开题答辩全过程】以 基于SpringBoot+Vue的百货商品进出货平台为例,包含答辩的问题和答案
java·spring boot·后端
左左右右左右摇晃2 小时前
Java笔记——包装类(自动拆装箱)
java·笔记·python
CSDN_Colinw2 小时前
C++中的工厂方法模式
开发语言·c++·算法
森林里的程序猿猿2 小时前
Java深入理解并发、线程、与等待通知机制(一)
java
liulilittle2 小时前
范围随机算法实现
开发语言·c++·算法·lua·c·js