找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1186

积分

0

好友

210

主题
发表于 3 天前 | 查看: 4| 回复: 0

在Java开发中,处理日期和时间是常见的需求。Java的日期时间API历经演变,尤其是JDK 8的发布带来了全新的设计。本文将系统梳理JDK 8之前的核心API及其局限性,并详细讲解JDK 8引入的现代日期时间API的使用方法。

JDK 8之前的日期时间API

在Java 8之前,开发者主要依赖java.util包下的几个类进行日期时间操作,它们在设计上存在一些固有缺陷。

1. System.currentTimeMillis()

这是一个最基础的方法,用于获取当前时间与1970年1月1日0时0分0秒(UTC)之间的毫秒数差值,即时间戳。

  • 返回值long类型的时间戳。
  • 常用场景:用于计算时间间隔或生成唯一的时间戳ID。
2. java.util.Date 与 java.sql.Date

这是两个容易混淆的类,分别位于java.utiljava.sql包中。

  • java.util.Date
    用于表示特定的瞬间,精确到毫秒。但其大部分构造方法和方法已过时(deprecated)。

    • 创建对象Date date = new Date(); // 基于当前系统时间
    • 常用方法
      • toString(): 输出可读的日期时间字符串(如 Tue Dec 02 08:03:24 CST 2025)。
      • getTime(): 返回对应的毫秒时间戳。
    @Test
    public void testUtilDate() {
        Date date1 = new Date(); // 创建一个基于当前系统时间的Date对象
        System.out.println(date1.toString()); // 输出: Tue Dec 02 08:03:24 CST 2025
        long milliTimes = date1.getTime(); // 获取对应的时间戳
        System.out.println(milliTimes); // 输出: 1764598448012
    }
  • java.sql.Date
    它是java.util.Date的子类,主要用于与数据库中的DATE类型字段交互,只包含年月日信息。

    • 创建对象java.sql.Date date = new java.sql.Date(1764598448012L); // 基于指定时间戳
    • 常用方法toString() 方法仅输出年月日(如 2025-12-01)。
    @Test
    public void testSqlDate() {
        java.sql.Date date1 = new java.sql.Date(1764598448012L); // 基于时间戳创建
        System.out.println(date1.toString()); // 输出: 2025-12-01
        System.out.println(date1.getTime()); // 输出: 1764598448012
    }

Java日期时间处理指南:从JDK8前Date到新API LocalDateTime详解 - 图片 - 1 Java日期时间处理指南:从JDK8前Date到新API LocalDateTime详解 - 图片 - 2

3. SimpleDateFormat 类

此类用于Date对象与格式化的字符串之间相互转换,即格式化解析

  • 格式化 (Date → String):使用 format(Date date) 方法。
  • 解析 (String → Date):使用 parse(String source) 方法,字符串必须符合指定的格式。
@Test
public void testSimpleDateFormat() throws ParseException {
    SimpleDateFormat sdf = new SimpleDateFormat();
    Date date1 = new Date();

    // 格式化:日期 ----> 字符串
    String strDate = sdf.format(date1);
    System.out.println(strDate); // 输出默认格式,如: 2025/12/2 上午8:10

    // 解析:字符串 ----> 日期
    Date date2 = sdf.parse("2025/12/2 上午8:10");
    System.out.println(date2); // 输出: Tue Dec 02 08:10:00 CST 2025
}

可以通过构造器 SimpleDateFormat(String pattern) 指定格式。

@Test
public void testSimpleDateFormatPattern() {
    // 使用自定义格式
    SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
    Date date1 = new Date();
    String formattedStr = sdf.format(date1);
    System.out.println(formattedStr); // 输出: 周二,2 12月 2025 08:20:46 +0800

    // 更常见的格式
    sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    formattedStr = sdf.format(date1);
    System.out.println(formattedStr); // 输出: 2025-12-02 08:23:08
}

Java日期时间处理指南:从JDK8前Date到新API LocalDateTime详解 - 图片 - 3 Java日期时间处理指南:从JDK8前Date到新API LocalDateTime详解 - 图片 - 4

4. Calendar 类(日历类)

Calendar 是一个抽象类,提供了比Date更丰富的日期字段(年、月、日、时、分、秒等)操作。

  • 实例化:通过静态方法 Calendar.getInstance() 获取子类实例(通常是GregorianCalendar)。
  • 常用方法:
    • get(int field): 获取指定字段的值(如 Calendar.DAY_OF_MONTH)。
    • set(int field, int value): 设置字段值。
    • add(int field, int amount): 为字段添加(或减去)值。
    • getTime(): 将Calendar转换为Date
    • setTime(Date date): 用Date对象设置Calendar的时间。
@Test
public void testCalendar() {
    Calendar calendar = Calendar.getInstance();
    System.out.println(calendar.getClass()); // 输出: class java.util.GregorianCalendar

    // get(int field)
    System.out.println(calendar.get(Calendar.DAY_OF_MONTH)); // 输出当月第几天,如: 2
    System.out.println(calendar.get(Calendar.DAY_OF_YEAR));  // 输出当年第几天,如: 336

    // set(int field, int value)
    calendar.set(Calendar.DAY_OF_MONTH, 23);
    System.out.println(calendar.get(Calendar.DAY_OF_MONTH)); // 输出: 23

    // add(int field, int amount)
    calendar.add(Calendar.DAY_OF_MONTH, 4);
    System.out.println(calendar.get(Calendar.DAY_OF_MONTH)); // 输出: 27

    // getTime(): Calendar ----> Date
    Date date = calendar.getTime();
    System.out.println(date); // 输出: Sat Dec 27 08:53:52 CST 2025

    // setTime(Date date): 使用指定Date重置Calendar
    Date date1 = new Date();
    calendar.setTime(date1);
    System.out.println(calendar.get(Calendar.DAY_OF_MONTH)); // 输出当前日期,如: 2
}

Java日期时间处理指南:从JDK8前Date到新API LocalDateTime详解 - 图片 - 5

JDK 8 全新的日期时间 API

鉴于旧API存在的诸多问题(如可变性、偏移性、非线程安全、设计混乱等),Java 8 引入了全新的 java.time 包。这是现代Java应用处理日期时间的首选。

1. 旧API过时的主要原因
  • 可变性:如DateCalendar是可变的,这在多线程环境下不安全。
  • 偏移性Date的年份从1900开始,月份从0开始,不符合直觉。
  • 设计缺陷SimpleDateFormat只能格式化Date,且本身非线程安全。
  • 功能不足:无法很好地处理时区、闰秒等复杂场景。
2. LocalDate、LocalTime、LocalDateTime

这三个类是java.time包的核心,分别表示日期、时间、日期+时间。它们都是不可变线程安全的。

  • 实例化
    • now(): 获取当前日期/时间。
    • of(...): 根据指定参数创建对象。
@Test
public void testLocalDateTime() {
    // now():获取当前实例
    LocalDate localDate = LocalDate.now();
    LocalTime localTime = LocalTime.now();
    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println(localDate);     // 输出: 2025-12-02
    System.out.println(localTime);     // 输出: 10:26:11.893155300
    System.out.println(localDateTime); // 输出: 2025-12-02T10:26:11.893155300

    // of():指定参数创建
    LocalDate localDate1 = LocalDate.of(2025, 12, 2);
    LocalTime localTime1 = LocalTime.of(10, 26, 11);
    LocalDateTime localDateTime1 = LocalDateTime.of(2025, 12, 2, 10, 29, 12);
    System.out.println(localDate1);     // 输出: 2025-12-02
    System.out.println(localTime1);     // 输出: 10:26:11
    System.out.println(localDateTime1); // 输出: 2025-12-02T10:29:12
}
  • 常用方法 (体现不可变性):
    • getXxx(): 获取字段值。
    • withXxx(): 返回一个修改了指定字段的新对象,原对象不变。
    • plusXxx()/minusXxx(): 返回一个增加了或减少了时间的新对象
@Test
public void testLocalDateTimeMethods() {
    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println(localDateTime.getDayOfMonth()); // 输出当前日,如: 2

    // withXxx():设置,返回新对象
    LocalDateTime localDateTime1 = localDateTime.withDayOfMonth(12);
    System.out.println(localDateTime);        // 原对象未变
    System.out.println(localDateTime1);       // 新对象日期已改为12号
    System.out.println(localDateTime.getDayOfMonth()); // 输出: 2
    System.out.println(localDateTime1.getDayOfMonth());// 输出: 12

    // plusXxx():增加,返回新对象
    LocalDateTime localDateTime2 = localDateTime1.plusDays(5);
    System.out.println(localDateTime1.getDayOfMonth()); // 输出: 12
    System.out.println(localDateTime2.getDayOfMonth()); // 输出: 17
}

Java日期时间处理指南:从JDK8前Date到新API LocalDateTime详解 - 图片 - 6 Java日期时间处理指南:从JDK8前Date到新API LocalDateTime详解 - 图片 - 7

3. Instant 类

Instant 用于表示时间线上的一个瞬时点(时间戳),类似于 java.util.Date,但精度可达纳秒。

  • 实例化
    • Instant.now(): 获取当前时刻(默认是格林威治时间)。
    • Instant.ofEpochMilli(long epochMilli): 根据毫秒时间戳创建。
  • 常用方法
    • toEpochMilli(): 获取对应的毫秒时间戳。
    • atOffset(ZoneOffset offset): 结合偏移量得到OffsetDateTime,用于处理时区。
@Test
public void testInstant() {
    // now(): 格林威治时间
    Instant instant = Instant.now();
    System.out.println(instant); // 输出: 2025-12-02T02:50:50.636435400Z

    // 调整为东八区时间
    OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
    System.out.println(offsetDateTime); // 输出: 2025-12-02T10:53:24.552167200+08:00

    // ofEpochMilli(): 通过时间戳创建
    Instant instant1 = Instant.ofEpochMilli(32312341232L);
    System.out.println(instant1); // 输出: 1971-01-09T23:39:01.232Z

    // toEpochMilli(): 获取时间戳
    long milliTime = instant.toEpochMilli();
    System.out.println(milliTime); // 输出: 1764644598934
}

Java日期时间处理指南:从JDK8前Date到新API LocalDateTime详解 - 图片 - 8

4. DateTimeFormatter 类

这是JDK 8中用于替代SimpleDateFormat的格式化类,它是线程安全的。

  • 实例化:常用 DateTimeFormatter.ofPattern(String pattern) 自定义格式。
  • 常用方法
    • format(TemporalAccessor temporal): 格式化(日期时间 -> 字符串)。
    • parse(CharSequence text): 解析(字符串 -> 日期时间对象)。
@Test
public void testDateTimeFormatter() {
    // 自定义格式
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    // 格式化:LocalDateTime ----> 字符串
    LocalDateTime localDateTime = LocalDateTime.now();
    String strDateTime = formatter.format(localDateTime);
    System.out.println(strDateTime); // 输出: 2025-12-02 11:19:45

    // 解析:字符串 ----> LocalDateTime
    TemporalAccessor parsed = formatter.parse("2025-12-02 15:19:45");
    LocalDateTime localDateTime1 = LocalDateTime.from(parsed);
    System.out.println(localDateTime1); // 输出: 2025-12-02T15:19:45
}

Java日期时间处理指南:从JDK8前Date到新API LocalDateTime详解 - 图片 - 9

总结

java.util.DateCalendarjava.time包,Java日期时间API完成了一次重要的现代化革新。新API设计清晰(如LocalDateLocalTimeLocalDateTime分工明确)、线程安全、且符合ISO标准。对于新项目,强烈建议直接使用Java 8及以上的日期时间API,它能更优雅、更安全地处理各类日期时间场景。




上一篇:软件开发外包项目客户沟通实战指南与标准话术
下一篇:Hugo静态博客免费部署到Vercel保姆级教程
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-17 19:06 , Processed in 0.109487 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表