1. DateTimeFormatter:它是什么,为什么需要
在实际程序中,日期很少只存在于代码内部。通常我们需要:
- 将其转换为字符串,用于输出到控制台、屏幕或文件(例如,"01.06.2025 14:30")。
- 解析字符串,也就是把用户输入或来自文件的字符串转换回日期/时间对象。
为此,Java 提供了一个强大且易用的工具——类 java.time.format.DateTimeFormatter。
可以把 DateTimeFormatter 看作对象时间(LocalDate、LocalDateTime、ZonedDateTime、Instant 等)与字符串之间的“翻译器”。它可以:
- 将日期/时间对象转换为所需格式的字符串(format —— 格式化)。
- 将字符串转换为日期/时间对象(parse —— 解析)。
2. 标准格式化器:快速又简单
Java 贴心地为我们准备了一组标准格式化器,覆盖最常用的 ISO 格式(日期与时间的国际标准)。
例如:
| 格式化器 | 字符串示例 | 说明 |
|---|---|---|
|
2025-06-01 | 仅日期(年-月-日) |
|
14:30:00 | 仅时间(时:分:秒) |
|
2025-06-01T14:30:00 | 日期与时间(无时区) |
|
2025-06-01T14:30:00+03:00[Europe/Minsk] | 日期、时间与时区 |
使用标准格式化器的示例
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class FormatterDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
// 将日期格式化为字符串
String text = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(text); // 例如:2025-06-01
// 将字符串解析回日期
LocalDate parsed = LocalDate.parse("2025-06-01", DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(parsed); // 2025-06-01
}
}
类比
如果把 Java 比作一家咖啡店,标准格式化器就像“美式咖啡”、“拿铁”和“意式浓缩”。快捷、标准,但有时你会想要点特别的!
3. 自定义模板:DateTimeFormatter.ofPattern
有时标准格式还不够。例如,你需要输出 "01.06.2025 14:30",而不是 "2025-06-01T14:30:00"。为此我们可以通过方法 DateTimeFormatter.ofPattern(String pattern) 创建自己的模板。
模板语法
模板中使用特定的字母:
- y — 年(yyyy —— 2025)
- M — 月(MM —— 06)
- d — 日(dd —— 01)
- H — 小时(24 小时制,HH —— 14)
- m — 分(mm —— 30)
- s — 秒(ss —— 00)
模板示例
| 模板 | 示例结果 |
|---|---|
|
01.06.2025 |
|
2025/06/01 |
|
01.06.2025 14:30 |
|
2025-06-01 14:30:00 |
|
2025年6月1日(俄语本地化时) |
示例:日期和时间的格式化
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class CustomFormatDemo {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2025, 6, 1, 14, 30);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
String text = dt.format(formatter);
System.out.println(text); // 01.06.2025 14:30
}
}
示例:将字符串解析为日期
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class ParseDemo {
public static void main(String[] args) {
String input = "01.06.2025 14:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
LocalDateTime dt = LocalDateTime.parse(input, formatter);
System.out.println(dt); // 2025-06-01T14:30
}
}
注意:模板必须与字符串完全匹配!如果字符串里有秒——请在模板中添加 :ss。
4. 格式化:把日期/时间变为字符串
通用流程
- 创建所需的对象(LocalDate、LocalDateTime、ZonedDateTime 等)。
- 创建或选择合适的格式化器。
- 调用对象的 format(DateTimeFormatter) 方法,得到字符串。
示例:以不同格式输出日期
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class MultiFormatDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2025, 6, 1);
// 标准 ISO
System.out.println(date.format(DateTimeFormatter.ISO_LOCAL_DATE)); // 2025-06-01
// 自定义格式
DateTimeFormatter rusFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy");
System.out.println(date.format(rusFormat)); // 01.06.2025
// 英语风格
DateTimeFormatter usFormat = DateTimeFormatter.ofPattern("MM/dd/yyyy");
System.out.println(date.format(usFormat)); // 06/01/2025
}
}
时间格式化
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class TimeFormatDemo {
public static void main(String[] args) {
LocalTime time = LocalTime.of(14, 30, 5);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(time.format(formatter)); // 14:30:05
}
}
5. 解析:把字符串变为日期/时间
通用流程
- 获取字符串(例如来自用户)。
- 根据字符串的模板创建格式化器。
- 调用静态方法 parse() 或格式化器对象的 parse() 方法。
示例:解析日期
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class ParseDateDemo {
public static void main(String[] args) {
String input = "01.06.2025";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
LocalDate date = LocalDate.parse(input, formatter);
System.out.println(date); // 2025-06-01
}
}
示例:解析日期和时间
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class ParseDateTimeDemo {
public static void main(String[] args) {
String input = "01.06.2025 14:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(input, formatter);
System.out.println(dateTime); // 2025-06-01T14:30
}
}
6. 解析错误处理
解析很“挑剔”。如果字符串不符合模板,Java 会抛出异常 DateTimeParseException。这很常见,例如用户输入了错误的日期。
示例:解析时的错误处理
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
public class ParseErrorDemo {
public static void main(String[] args) {
String input = "32.13.2025"; // 非法日期
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
try {
LocalDate date = LocalDate.parse(input, formatter);
System.out.println(date);
} catch (DateTimeParseException ex) {
System.out.println("解析错误: " + ex.getMessage());
}
}
}
重要:处理用户输入时,一定要捕获并处理此类错误!
7. 实战:为用户转换日期
假设在我们的教学应用中有这样一个任务:用户以 "dd.MM.yyyy" 格式输入生日,程序需要将日期输出为 "yyyy/MM/dd" 格式,并给出星期几。
示例
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Scanner;
public class BirthdayFormatDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入出生日期 (dd.MM.yyyy): ");
String input = scanner.nextLine();
DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy");
DateTimeFormatter outputFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd");
try {
LocalDate birthday = LocalDate.parse(input, inputFormat);
String formatted = birthday.format(outputFormat);
System.out.println("您的日期的新格式: " + formatted);
System.out.println("星期几: " + birthday.getDayOfWeek()); // 例如:SATURDAY
} catch (DateTimeParseException ex) {
System.out.println("错误:日期格式不正确!");
}
}
}
8. 本地化:语言如何影响格式化
使用 DateTimeFormatter 不仅可以调整数字顺序,还可以用文字输出月份、星期几等;这取决于本地化(语言与区域)。
示例:用俄语输出月份名称
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocaleDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2025, 6, 1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMMM yyyy", new Locale("ru"));
System.out.println(date.format(formatter)); // 2025 年 6 月 1 日
}
}
示例:英文 Locale
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocaleEnDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2025, 6, 1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.ENGLISH);
System.out.println(date.format(formatter)); // 1 June 2025
}
}
小窍门:如果希望月份和星期几显示为指定语言——请显式设置所需的 Locale!
9. 格式化与解析日期的常见错误
错误 1:模板与字符串不匹配。
如果字符串是 "01.06.2025 14:30",而模板是 "dd.MM.yyyy",解析会失败。模板必须与字符串完全一致。
错误 2:混淆了模板符号。
MM —— 月份,mm —— 分钟。若写成 "dd.mm.yyyy",Java 会认为你指的是分钟,从而报错。表示月份请始终使用大写 M。
错误 3:解析时未处理异常。
如果不捕获 DateTimeParseException,程序在用户输入不正确时可能突然终止。务必处理此类异常。
错误 4:在使用月份/星期文字时未指定 Locale。
如果使用带有月份文字的模板(MMMM),但未指定 Locale,Java 可能会使用默认语言(例如英语)。请始终显式设置所需的 Locale。
错误 5:在新项目中使用旧类(SimpleDateFormat、Date)。
请记住:在现代代码中使用 java.time 和 DateTimeFormatter。
GO TO FULL VERSION