1. 简介

在维护一些老项目时,我们经常会遇到这样的情况:既不能用 Java 8 引入的新时间 API,也无法引入像 Joda-Time 这种成熟的第三方库。这时候,如何准确、安全地处理日期时间就成了一个“踩坑”高发区。

本文将带你回顾在 Java 8 之前,有哪些方式可以获取当前日期,并分析它们的适用场景和潜在问题。内容虽基础,但对理解遗留系统中的时间处理逻辑非常有帮助。

2. 系统时间(System Time)

如果你只需要一个能代表当前时间的数值,系统时间是最简单粗暴的选择。

System.currentTimeMillis() 返回自 1970年1月1日 00:00:00 GMT 以来的毫秒数,类型为 long

long elapsedMilliseconds = System.currentTimeMillis();

⚠️ 注意:这个值表示的是“时间戳”,不包含时区信息,仅适合做时间标记或计算时间差。

如果对精度要求更高,比如做性能分析,可以使用 System.nanoTime()

long elapsedNanosecondsStart = System.nanoTime();
// 执行某些操作
long elapsedNanoseconds = System.nanoTime() - elapsedNanosecondsStart;

nanoTime 返回的是纳秒级时间,但它的起点是 JVM 启动时的一个任意固定时刻,因此只适用于计算时间间隔,不能用来表示“当前是几点”。

3. java.util 包中的日期工具

java.util 包提供了更丰富的日期表示方式,核心是 DateCalendar 类。

3.1. java.util.Date

Date 是最常用的日期类,它内部用毫秒值表示时间,精度到毫秒级,并且隐含了本地时区信息(虽然它自己不直接暴露时区)。

获取当前时间非常简单:

Date currentUtilDate = new Date();

如果要从字符串解析日期,可以配合 SimpleDateFormat 使用:

SimpleDateFormat dateFormatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
Date customUtilDate = dateFormatter.parse("30-01-2020 10:11:12");

⚠️ 踩坑提示:

  • SimpleDateFormat 不是线程安全的,多线程环境下必须加锁或使用 ThreadLocal
  • Date 类的很多方法(如 getYear()getMonth())已被标记为过时,容易出错。

3.2. java.util.Calendar

Calendar 是对 Date 的增强,更适合做日期运算,比如加减天数、月份等。它还支持 Locale(地区信息),能处理不同地区的日历规则。

获取当前时间:

Calendar currentUtilCalendar = Calendar.getInstance();

Calendar 转为 Date

Date currentDate = Calendar.getInstance().getTime();

✅ 优势:

  • 支持时区(TimeZone)和区域(Locale)设置。
  • 提供 add()roll() 等方法方便做日期计算。

❌ 缺点:

  • API 设计复杂,代码冗长。
  • 同样存在线程安全问题。

📌 小知识:GregorianCalendarCalendar 的默认实现,也就是我们日常使用的公历。

4. java.sql 包中的 SQL 日期类型

这些类继承自 java.util.Date,主要用于与数据库交互,对应 SQL 中的日期类型。

4.1. java.sql.Date

表示 SQL 中的 DATE 类型,只包含年月日,不包含时分秒,也没有时区信息

创建当前日期:

Date currentSqlDate = new Date(System.currentTimeMillis());

从字符串创建(格式必须为 yyyy-MM-dd):

Date customSqlDate = Date.valueOf("2020-01-30");

⚠️ 注意:虽然构造函数接受毫秒值,但内部会截断到天级别。

4.2. java.sql.Time

表示 SQL 中的 TIME 类型,只包含时分秒,不包含日期和时区

获取当前时间:

Time currentSqlTime = new Time(System.currentTimeMillis());

从字符串创建(格式为 HH:mm:ss):

Time customSqlTime = Time.valueOf("10:11:12");

4.3. java.sql.Timestamp

表示 SQL 中的 TIMESTAMP精度可达纳秒级,是 DateTime 的结合体。

创建当前时间戳:

Timestamp currentSqlTimestamp = new Timestamp(System.currentTimeMillis());

从字符串创建(格式为 yyyy-MM-dd HH:mm:ss[.f...]):

Timestamp customSqlTimestamp = Timestamp.valueOf("2020-1-30 10:11:12.123456789");

✅ 使用场景:记录数据库操作时间、日志时间戳等需要高精度的场合。

5. 总结

在没有 Java 8 时间 API 的时代,我们主要依赖以下几种方式获取当前日期:

方式 适用场景 注意事项
System.currentTimeMillis() 时间戳、性能计时 只是数字,无时区
java.util.Date 通用日期表示 方法过时,非线程安全
java.util.Calendar 日期计算、时区处理 API 复杂,性能一般
java.sql.Date/Time/Timestamp 数据库交互 精度受限或需注意格式

📌 虽然这些类现在已被 LocalDateTimeZonedDateTime 等取代,但在维护老系统时仍需了解其行为。尤其是 SimpleDateFormatCalendar 的线程安全问题,是线上故障的常见来源。

示例代码已托管至 GitHub:https://github.com/example/java-date-legacy-demo


原始标题:Get the Current Date Prior to Java 8