Java 日期和时间
⚡ 智能摘要
Java 日期和时间处理结合了传统的 java.util.Date 和 SimpleDateFormat 类以及在 中引入的现代 java.time API。 Java 8,为开发人员提供不可变、线程安全的类型,以实现精确的日历工作。

处理日期和时间 Java 这是构建调度逻辑、记录时间戳、生成报告和审计跟踪的常规步骤。在编写任何代码之前,了解构成日期的参数很有帮助:
- 此 年 (两位数或四位数)
- 此 月 (可以是两位数字、月份的前三个字母,或者完整的月份名称)。
- 此 日期 (实际的日期)。
- 此 天 (给定日期的星期名称,例如星期日、星期一、星期二)。
Java 它还公开了描述时间线上某一时刻的许多其他参数,包括时代、一年中的第几周、时区和偏移量。以下各节将通过可运行的示例逐一介绍这些参数。
显示日期 Java
Java 提供了一个 Date 在课堂上 java.util 该类存储精确到毫秒的特定时间点,并提供用于打印、比较和格式化该时间点的辅助方法。要获取当前日期和时间,请使用其默认构造函数实例化该类:
import java.util.Date; class Date_Ex1 { public static void main(String args[]) { // Instantiate a Date object by invoking its constructor Date objDate = new Date(); // Display the Date and Time using toString() System.out.println(objDate.toString()); } }
输出:
Wed Nov 29 06:36:22 UTC 2017
示例以默认的 toString 格式打印日期。要以不同的格式显示同一时间点,首先需要了解格式化字母。 Java 用途。
SimpleDateFormat:解析和格式化日期
此 SimpleDateFormat 上课 java.text 转换一个 Date 将对象转换为格式化字符串,并将格式化字符串解析回对象。 Date它使用与日期或时间部分对应的模式字母。下表列出了所有支持的字母:
| 博客 | 日期或时间组件 | 例如: |
|---|---|---|
| G | 纪元指示符 | AD |
| y | 年份 | 2026 |
| M | 月份 | 七月或Jul或07 |
| w | 一年中的第几周 | 27 |
| W | 月中的周数 | 2 |
| D | 一年中的某一天 | 189 |
| d | 月中天数 | 10 |
| F | 每月中的星期几 | 2 |
| E | 星期几名称 | 周二或周二 |
| u | 星期几(1 = Monday(7 = 星期日) | 1 |
| a | 上午或下午标记 | PM |
| H | 一天中的小时数(0-23) | 0 |
| k | 一天中的小时数(1-24) | 24 |
| K | 上午或下午时间(0-11) | 0 |
| h | 上午或下午时间(1-12) | 12 |
| m | 一小时内的分钟数 | 30 |
| s | 分钟内第二 | 55 |
| S | 毫秒 | 978 |
| z | 时区(名称) | 太平洋标准时间;PST;GMT-08:00 |
| Z | 时区(RFC 822 偏移量) | -0800 |
| X | 时区(ISO 8601 偏移量) | -08 或 -0800 或 -08:00 |
您无需记住整张表格。每次创建新图案时,只需参考它即可。
如何使用 SimpleDateFormat
SimpleDateFormat 是的子类 DateFormat 这样,您就可以使用上面的模式字母来格式化和解析日期。组合这些字母即可描述您想要生成或读取的确切字符串。
例如:
- 日期格式要求: 2012.10.23 20:20:45 太平洋标准时间合适的格式模式是
yyyy.MM.dd HH:mm:ss zzz. - 日期格式要求: 09:30:00 AM 23-May-2012合适的格式模式是
hh:mm:ss a dd-MMM-yyyy.
提示: 手表字母大小写。大写 M 月份,小写 m 很小。大写 H 是一个 24 小时制时钟,小写 h 这是一个12小时制时钟。将它们混淆会产生无声的错误输出。
以下程序会打印两次当前日期,一次使用默认格式,一次使用 SimpleDateFormat 模式:
import java.text.SimpleDateFormat; import java.util.Date; class TestDates_Format { public static void main(String args[]) { // Current system date and time is assigned to objDate Date objDate = new Date(); System.out.println(objDate); // Build the target pattern and format the date String strDateFormat = "hh:mm:ss a dd-MMM-yyyy"; SimpleDateFormat objSDF = new SimpleDateFormat(strDateFormat); System.out.println(objSDF.format(objDate)); } }
输出:
Wed Nov 29 06:31:41 UTC 2017 06:31:41 AM 29-Nov-2017
比较日期示例
订购两件商品最可靠的方法是 Date 对象是 compareTo() 该方法会在调用者时间早于目标时间时返回负整数,在两个时间点相同时返回零,在调用者时间晚于目标时间时返回正整数。以下代码片段解析两个日期字符串并打印它们的相对顺序:
import java.text.SimpleDateFormat; import java.text.ParseException; import java.util.Date; class TestDates_Compare { public static void main(String args[]) throws ParseException { SimpleDateFormat objSDF = new SimpleDateFormat("dd-MM-yyyy"); Date dt_1 = objSDF.parse("20-08-1981"); Date dt_2 = objSDF.parse("12-10-2012"); System.out.println("Date1 : " + objSDF.format(dt_1)); System.out.println("Date2 : " + objSDF.format(dt_2)); // compareTo returns > 0 when dt_1 is after dt_2 if (dt_1.compareTo(dt_2) > 0) { System.out.println("Date 1 occurs after Date 2"); } // compareTo returns < 0 when dt_1 is before dt_2 else if (dt_1.compareTo(dt_2) < 0) { System.out.println("Date 1 occurs before Date 2"); } // compareTo returns 0 when both dates are equal else { System.out.println("Both are the same date"); } } }
输出:
Date1 : 20-08-1981 Date2 : 12-10-2012 Date 1 occurs before Date 2
注意: 原始代码使用了以下模式 dd-mm-yyyy小写字母 mm 字母代表分钟,而不是月份,因此解析器默默地生成了错误的月份值。上面的修复方法使用了大写字母。 MM 月份的字母是正确的模式字母。
Java 8 现代日期和时间 API (java.time)
Java 8 引入了 java.time 该软件包是一个重新设计的 API,其灵感来源于 Joda-Time 库。新的类是不可变的、线程安全的,并将人类日历与机器时间线分离。最常见的类型有:
LocalDate日期不包含时间或时区(例如,生日)。LocalTime适用于没有日期或时区的挂钟时间。LocalDateTime指定日期和时间,不指定时区。ZonedDateTime指定日期和时间以及特定时区。OffsetDateTime日期和时间具有 UTC 偏移量,但没有指定时区。Instant机器时间戳,从 UNIX 纪元开始计算。Duration和Period适用于基于时间和日期的金额。
以下示例使用现代 API 打印当前日期、时间、时间戳和时区:
import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZonedDateTime; import java.time.Instant; import java.time.ZoneId; class ModernDateDemo { public static void main(String args[]) { LocalDate today = LocalDate.now(); LocalDateTime now = LocalDateTime.now(); ZonedDateTime zoned = ZonedDateTime.now(ZoneId.of("Asia/Kolkata")); Instant epoch = Instant.now(); System.out.println("LocalDate : " + today); System.out.println("LocalDateTime : " + now); System.out.println("ZonedDateTime : " + zoned); System.out.println("Instant : " + epoch); } }
每种类型都有工厂方法(now, of, parse)和不可变操作(plusDays, minusHours, withYear返回一个新值,而不是改变原始对象。
DateTimeFormatter:在现代语言中格式化日期 Java
DateTimeFormatter in java.time.format 取代 SimpleDateFormat它使用相同的模式字母样式,是不可变的,并且可以安全地在线程间共享而无需额外的同步。该类还公开了现成的常量,例如: ISO_LOCAL_DATE 和 ISO_ZONED_DATE_TIME 适用于标准格式。
import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; class FormatterDemo { public static void main(String args[]) { LocalDateTime now = LocalDateTime.now(); DateTimeFormatter iso = DateTimeFormatter.ISO_LOCAL_DATE_TIME; DateTimeFormatter human = DateTimeFormatter.ofPattern("hh:mm:ss a dd-MMM-yyyy"); System.out.println(now.format(iso)); System.out.println(now.format(human)); LocalDateTime parsed = LocalDateTime.parse("2026-07-04T09:30:00", iso); System.out.println("Parsed back : " + parsed); } }
要使用现代 API 比较两个日期,请调用 isBefore, isAfter 或 isEqual这些方法比……读起来更清晰。 compareTo 并与每个人合作 java.time 类。
螺纹安全与最佳实践 Java 日期和时间
以上皆是 java.util.Date 和 SimpleDateFormat 早于现代并发 Java每种方法都有其已知的缺陷。请遵循以下实践,以确保生产代码中的日期处理正确无误:
- 优先使用 java.time 而不是 Date 和 Calendar。 新类型是不可变的,并且是线程安全的,它们可以更准确地模拟领域(没有时间的日期,没有时区的时间等等)。
- 不要在不同线程间共享 SimpleDateFormat。 该类存储内部解析状态,并且不是线程安全的。请将其包装在一个……
ThreadLocal同步实例,或切换到DateTimeFormatter. - 务必指定语言环境。 月份和日期名称会随着 JVM 默认区域设置而变化,这使得诸如此类的模式变得复杂。
MMM和EEE不具备可移植性。请显式传递区域设置(例如,Locale.ENGLISH). - 务必明确说明时区。
LocalDateTime没有区域,所以转换为ZonedDateTimeorInstant在需要精确把握时机的时候,特别是对于日志、数据库列和网络有效载荷而言。 - 请谨慎地在两个 API 之间进行转换。 绝大部分储备使用
date.toInstant(),Date.from(instant)和calendar.toInstant().atZone(zone)处于传统代码和现代代码的交界处。 - 以UTC格式存储时间戳。 坚持不懈 transmit 日期以 UTC 为准(
Instant或者 ISO 8601 字符串)并在显示时转换为用户区域。


