Java DateTimeFormatter

DateTimeFormatter 是 Java 8 引入的類別,用於格式化和解析日期時間物件。它是執行緒安全且不可變的。

引入套件

import java.time.format.DateTimeFormatter;

預定義格式

LocalDateTime dt = LocalDateTime.of(2024, 12, 25, 14, 30, 45);

// ISO 格式
System.out.println(dt.format(DateTimeFormatter.ISO_LOCAL_DATE));       // 2024-12-25
System.out.println(dt.format(DateTimeFormatter.ISO_LOCAL_TIME));       // 14:30:45
System.out.println(dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));  // 2024-12-25T14:30:45
System.out.println(dt.format(DateTimeFormatter.ISO_DATE));             // 2024-12-25

// 基本 ISO 格式(無分隔符)
System.out.println(dt.format(DateTimeFormatter.BASIC_ISO_DATE));  // 20241225

自訂格式

使用 ofPattern

LocalDateTime dt = LocalDateTime.of(2024, 12, 25, 14, 30, 45);

DateTimeFormatter f1 = DateTimeFormatter.ofPattern("yyyy/MM/dd");
System.out.println(dt.format(f1));  // 2024/12/25

DateTimeFormatter f2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
System.out.println(dt.format(f2));  // 2024年12月25日 14:30:45

DateTimeFormatter f3 = DateTimeFormatter.ofPattern("yy-M-d H:m");
System.out.println(dt.format(f3));  // 24-12-25 14:30

常用格式符號

符號說明範例
yyyyy=2024, yy=24
MMM=12, M=12, MMM=Dec, MMMM=December
ddd=25, d=25
E星期E=Wed, EEEE=Wednesday
H時(24小時制)HH=14, H=14
h時(12小時制)hh=02, h=2
mmm=30, m=30
sss=45, s=45
S毫秒SSS=123
aAM/PMa=PM
z時區名稱z=CST
Z時區偏移Z=+0800, ZZ=+08:00

格式化範例

LocalDateTime dt = LocalDateTime.of(2024, 12, 25, 14, 30, 45, 123000000);

// 日期格式
DateTimeFormatter.ofPattern("yyyy-MM-dd")          // 2024-12-25
DateTimeFormatter.ofPattern("dd/MM/yyyy")          // 25/12/2024
DateTimeFormatter.ofPattern("yyyy年M月d日")         // 2024年12月25日

// 時間格式
DateTimeFormatter.ofPattern("HH:mm:ss")            // 14:30:45
DateTimeFormatter.ofPattern("hh:mm a")             // 02:30 PM
DateTimeFormatter.ofPattern("HH:mm:ss.SSS")        // 14:30:45.123

// 完整日期時間
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") // 2024-12-25 14:30:45
DateTimeFormatter.ofPattern("EEEE, MMMM d, yyyy")  // Wednesday, December 25, 2024

指定 Locale

LocalDateTime dt = LocalDateTime.of(2024, 12, 25, 14, 30);

// 英文
DateTimeFormatter enFormatter = DateTimeFormatter
    .ofPattern("EEEE, MMMM d, yyyy", Locale.ENGLISH);
System.out.println(dt.format(enFormatter));  // Wednesday, December 25, 2024

// 繁體中文
DateTimeFormatter zhFormatter = DateTimeFormatter
    .ofPattern("yyyy年M月d日 EEEE", Locale.TAIWAN);
System.out.println(dt.format(zhFormatter));  // 2024年12月25日 星期三

// 日文
DateTimeFormatter jpFormatter = DateTimeFormatter
    .ofPattern("yyyy年M月d日(E)", Locale.JAPAN);
System.out.println(dt.format(jpFormatter));  // 2024年12月25日(水)

解析字串

基本解析

// 解析日期
LocalDate date = LocalDate.parse("2024-12-25");  // 預設 ISO 格式
System.out.println(date);  // 2024-12-25

// 解析時間
LocalTime time = LocalTime.parse("14:30:45");
System.out.println(time);  // 14:30:45

// 解析日期時間
LocalDateTime dt = LocalDateTime.parse("2024-12-25T14:30:45");
System.out.println(dt);  // 2024-12-25T14:30:45

使用自訂格式解析

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");

LocalDateTime dt = LocalDateTime.parse("2024/12/25 14:30:45", formatter);
System.out.println(dt);  // 2024-12-25T14:30:45

// 只解析日期
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate date = LocalDate.parse("25-12-2024", dateFormatter);
System.out.println(date);  // 2024-12-25

DateTimeFormatterBuilder

使用 Builder 建立更複雜的格式化器:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR, 4)
    .appendLiteral('-')
    .appendValue(ChronoField.MONTH_OF_YEAR, 2)
    .appendLiteral('-')
    .appendValue(ChronoField.DAY_OF_MONTH, 2)
    .toFormatter();

LocalDate date = LocalDate.of(2024, 12, 25);
System.out.println(date.format(formatter));  // 2024-12-25

設定預設值

// 解析時若缺少時間,使用預設值
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .appendPattern("yyyy-MM-dd")
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
    .toFormatter();

LocalDateTime dt = LocalDateTime.parse("2024-12-25", formatter);
System.out.println(dt);  // 2024-12-25T00:00

實用範例

常用格式化方法

public class DateTimeUtils {
    private static final DateTimeFormatter DATE_FORMAT = 
        DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter DATETIME_FORMAT = 
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter DISPLAY_FORMAT = 
        DateTimeFormatter.ofPattern("yyyy年M月d日 HH:mm");
    
    public static String formatDate(LocalDate date) {
        return date.format(DATE_FORMAT);
    }
    
    public static String formatDateTime(LocalDateTime dateTime) {
        return dateTime.format(DATETIME_FORMAT);
    }
    
    public static String formatForDisplay(LocalDateTime dateTime) {
        return dateTime.format(DISPLAY_FORMAT);
    }
    
    public static LocalDate parseDate(String str) {
        return LocalDate.parse(str, DATE_FORMAT);
    }
    
    public static LocalDateTime parseDateTime(String str) {
        return LocalDateTime.parse(str, DATETIME_FORMAT);
    }
}

相對時間顯示

public static String formatRelative(LocalDateTime dateTime) {
    LocalDateTime now = LocalDateTime.now();
    Duration duration = Duration.between(dateTime, now);
    
    if (duration.isNegative()) {
        return "未來";
    }
    
    long seconds = duration.getSeconds();
    if (seconds < 60) return "剛剛";
    if (seconds < 3600) return (seconds / 60) + " 分鐘前";
    if (seconds < 86400) return (seconds / 3600) + " 小時前";
    
    long days = duration.toDays();
    if (days == 1) return "昨天";
    if (days < 7) return days + " 天前";
    if (days < 30) return (days / 7) + " 週前";
    if (days < 365) return (days / 30) + " 個月前";
    
    return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}

重點整理

  • DateTimeFormatter 是執行緒安全的
  • 使用 ofPattern() 建立自訂格式
  • 支援多種 Locale 進行在地化
  • 格式化使用 format(),解析使用 parse()
  • 常用格式建議定義為 static final 常數重複使用