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
包提供了更丰富的日期表示方式,核心是 Date
和 Calendar
类。
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 设计复杂,代码冗长。
- 同样存在线程安全问题。
📌 小知识:
GregorianCalendar
是Calendar
的默认实现,也就是我们日常使用的公历。
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
,精度可达纳秒级,是 Date
和 Time
的结合体。
创建当前时间戳:
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 |
数据库交互 | 精度受限或需注意格式 |
📌 虽然这些类现在已被 LocalDateTime
、ZonedDateTime
等取代,但在维护老系统时仍需了解其行为。尤其是 SimpleDateFormat
和 Calendar
的线程安全问题,是线上故障的常见来源。
示例代码已托管至 GitHub:https://github.com/example/java-date-legacy-demo