Java 日期与时间类

发布于 2026-07-30 20:20 更新于 2026-10-13 17:14 1275 字 7 min read ... 访问量 AI 审阅 文章内容已由 AI 审阅过,但仍需谨慎判断。 AI 改写 文章内容主要由他人撰写,AI 帮我改写或润色。

AI 审阅 文章内容已由 AI 审阅过,但仍需谨慎判断。

本文介绍了 Java 中日期时间相关的 API,分为旧版(Date、Calendar、SimpleDateFormat)和新版本(java.time 包)两大类。旧版 API 虽仍可用于历史代码维护,但存在可变性、线程不安全及易错等问题,推荐新项目使用不可变、线程安全的 java.time API。Java 8 新 API 提供了更清晰、更安全的日期时间类,如 LocalDate、LocalDateTime 和 DateTimeFormatter,支持精确的日期计算和格式化,建议在新项目中优先使用。

Java 日期与时间类

Java 中常见的日期时间 API 可以分为两类:

  • 旧版 API:Date、Calendar、SimpleDateFormat。
  • Java 8 新 API:LocalDate、LocalDateTime、Instant、DateTimeFormatter 等。

旧版 API 在维护历史代码时仍会遇到,但新项目通常优先使用 java.time 包。

一、时间戳与时区

Unix 时间戳通常表示从 1970-01-01T00:00:00Z 开始经过的时间。Date 使用毫秒精度保存时间点。

北京时间通常采用 UTC+8。时区会影响时间点如何显示为年月日和时分秒,但不会改变时间点本身。

二、Date 类

java.util.Date 表示时间轴上的一个时间点,内部核心值是从 Unix 纪元开始计算的毫秒数。它并不是简单地分别保存年、月、日、时、分、秒。

Date 中许多直接操作年月日的方法已经过时,日期计算应使用 Calendar 或更推荐的 java.time API。

构造器

Date now = new Date();

无参构造器创建表示当前时间的对象。

Date date = new Date(1_000_000L);

传入的 long 值表示从 Unix 纪元开始经过的毫秒数。

常用方法

Date date = new Date();

long timestamp = date.getTime();
date.setTime(timestamp + 1_000L);
  • getTime():获取毫秒时间戳。
  • setTime(long time):修改该对象表示的时间点。

Date 是可变对象,调用 setTime() 会改变原对象。

三、Calendar 类

Calendar 是旧版日历计算类,可以根据时区和区域设置处理年月日等字段。

它的构造器通常不直接调用,而是通过 getInstance() 获取实例:

Calendar calendar = Calendar.getInstance();

获取和修改日期字段

Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, 3);

int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1;
int day = calendar.get(Calendar.DAY_OF_MONTH);

System.out.println(year + "-" + month + "-" + day);

注意:

  • Calendar.MONTH 从 0 开始,因此显示月份时通常需要加 1。
  • add() 的参数可以为正数或负数,用于增加或减少时间。
  • Calendar 也是可变对象。

与 Date 相互转换

Calendar calendar = Calendar.getInstance();
Date dateFromCalendar = calendar.getTime();

Date date = new Date(100_000_000L);
Calendar anotherCalendar = Calendar.getInstance();
anotherCalendar.setTime(date);
  • calendar.getTime():将 Calendar 当前表示的时间转换为 Date。
  • calendar.setTime(date):让 Calendar 使用指定 Date 的时间点。

四、SimpleDateFormat 类

SimpleDateFormat 用于在 Date 与字符串之间进行格式化和解析。

常见格式符号如下:

符号含义示例
yyyy四位年份2026
MM两位月份01
dd两位日期25
HH24 小时制小时16
mm分钟30
ss秒45

格式符号区分大小写。例如,MM 表示月份,mm 表示分钟。

将 Date 格式化为字符串

import java.text.SimpleDateFormat;
import java.util.Date;

public class FormatDateDemo {

    public static void main(String[] args) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date now = new Date();

        String text = formatter.format(now);
        System.out.println(text);
    }
}

将字符串解析为 Date

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ParseDateDemo {

    public static void main(String[] args) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        formatter.setLenient(false);

        String text = "2026-01-25";

        try {
            Date date = formatter.parse(text);
            System.out.println(date);
        } catch (ParseException e) {
            System.out.println("日期格式不正确");
        }
    }
}

setLenient(false) 用于关闭宽松解析。例如,在严格模式下,2026-02-30 会解析失败,而不是自动调整到下一个月。

SimpleDateFormat 不是线程安全的,不应把同一个实例作为共享对象供多个线程同时使用。

五、旧版 API 应用

指定日期增加十五天

将 20260122 增加十五天,并按中文日期格式输出:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class AddDaysLegacyDemo {

    public static void main(String[] args) {
        String text = "20260122";
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        formatter.setLenient(false);

        try {
            Date date = formatter.parse(text);

            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.DATE, 15);

            formatter.applyPattern("yyyy年MM月dd日");
            System.out.println(formatter.format(calendar.getTime()));
        } catch (ParseException e) {
            System.out.println("日期格式不正确");
        }
    }
}

计算两个时间点的毫秒差

long differenceMillis = endDate.getTime() - startDate.getTime();

直接除以一天的毫秒数只能得到固定时长意义上的天数。如果时间范围跨越夏令时变化,结果可能与日历日期差不同。因此,计算日期之间相差多少天时,更适合使用 LocalDate 和 ChronoUnit.DAYS。

六、Java 8 日期时间 API

java.time API 的类型设计更清晰,并且大多数核心类不可变、线程安全。

LocalDate

LocalDate 表示不带时区的日期,例如生日或课程日期。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class LocalDateDemo {

    public static void main(String[] args) {
        DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");

        LocalDate date = LocalDate.parse("20260122", inputFormatter);
        LocalDate result = date.plusDays(15);

        System.out.println(result.format(outputFormatter));
    }
}

计算日期差

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class DateDifferenceDemo {

    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");

        LocalDate startDate = LocalDate.parse("20260122", formatter);
        LocalDate endDate = LocalDate.parse("20260302", formatter);

        long days = ChronoUnit.DAYS.between(startDate, endDate);
        System.out.println(days);
    }
}

常用类型

类型适用场景
LocalDate只需要年月日,不需要时区
LocalTime只需要时分秒
LocalDateTime需要日期和时间,但不包含时区
Instant时间轴上的时间点,适合记录时间戳
ZonedDateTime需要明确时区规则的日期时间
Duration表示基于秒和纳秒的时长
Period表示基于年、月、日的日期差
DateTimeFormatter日期时间的格式化和解析

新代码应根据业务含义选择类型,而不是所有时间都使用 Date 或字符串保存。

执笔 AI 改写

喜欢的话,留下你的评论吧~

加载中...