Java 日期/时间

java.text.SimpleDateFormat 类

SimpleDateFormat 类是 Java 中用于日期时间与字符串之间相互转换的类,它基于 DateFormat 抽象类进行实现的,支持自定义格式化时的格式模式,例如 yyyy-MM-dd HH:mm:ss 格式模式将日期格式化为类似“2024-09-12 12:20:40”格式的字符串。在 JDK 1.8 之前,是处理日期格式化的主要工具。

java.text.SimpleDateFormat 类

SimpleDateFormat 的核心作用是:

  • 将 Date 或 Calendar 对象格式化为指定模式的字符串(格式化)

  • 将字符串按指定模式解析为 Date 对象(解析)

示例:下面示例介绍了 SimpleDateFormat 的基础用法

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleDateFormatExample {
    public static void main(String[] args) {
        // 1. 定义日期格式模式(区分大小写,常用字母:y-年, M-月, d-日, H-24时, h-12时, m-分, s-秒)
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        
        // 2. 格式化:Date -> String
        Date now = new Date();
        String formattedDate = sdf.format(now);
        System.out.println("格式化后的日期: " + formattedDate); // 例如:2023-10-05 14:30:25
        
        // 3. 解析:String -> Date(需处理ParseException异常)
        String dateStr = "2024-02-29 08:15:30";
        try {
            Date parsedDate = sdf.parse(dateStr);
            System.out.println("解析后的Date对象: " + parsedDate); // 输出对应时间的Date
        } catch (ParseException e) {
            // 当字符串格式与模式不匹配时抛出异常
            System.out.println("日期解析失败: " + e.getMessage());
        }
        
        // 演示其他格式
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日 a hh:mm");
        System.out.println("其他格式: " + sdf2.format(now)); // 例如:2023年10月05日 下午 02:30
    }
}

运行结果:

格式化后的日期: 2025-09-01 22:43:20
解析后的Date对象: Thu Feb 29 08:15:30 CST 2024
其他格式: 2025年09月01日 下午 10:43

示例说明:

  • 模式字母区分大小写(如 M 代表月份,m 代表分钟)

  • 格式化(format()):将 Date 对象转换为指定格式的字符串

  • 解析(parse()):将字符串按指定格式转换为 Date 对象,需捕获 ParseException

  • 常见模式示例:

    • yyyy-MM-dd → 2023-10-05

    • HH:mm:ss → 14:30:25

    • yyyy年MM月dd日 → 2023 年 10 月 05 日

注意:SimpleDateFormat 是非线程安全的,多线程环境下需额外处理或使用 DateTimeFormatter(Java 8+ 推荐)。

常用格式模式符

格式化时需使用特定字符表示日期时间元素,常用模式符如下:

  • y:年(如 yyyy 表示 4 位年,yy 表示 2 位年)

  • M:月(MM 表示 2 位月,MMM 表示英文月份缩写)

  • d:日(dd 表示 2 位日)

  • H:24 小时制小时(HH)

  • h:12 小时制小时(hh)

  • m:分钟(mm)

  • s:秒(ss)

  • S:毫秒(SSS)

  • a:上午 / 下午(如 AM/PM)

常用方法及示例

格式化(format(Date date))

format() 方法用于将 Date 对象转换为指定格式的字符串。示例:

import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleDateFormatExample1 {
    public static void main(String[] args) {
        // 创建格式化对象,指定模式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        
        // 格式化当前时间
        Date now = new Date();
        String formattedDate = sdf.format(now);
        System.out.println("格式化结果:" + formattedDate); // 如:2023-10-05 14:30:25
    }
}

运行结果:

格式化结果:2025-09-01 22:49:54

解析(parse(String source))

parse() 方法用于将字符串按指定模式解析为 Date 对象(需处理 ParseException)。示例:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleDateFormatExample2 {
    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        String dateStr = "2024年03月15日";
        
        try {
            // 解析字符串为Date对象
            Date date = sdf.parse(dateStr);
            System.out.println("解析结果:" + date); // 如:Fri Mar 15 00:00:00 CST 2024
        } catch (ParseException e) {
            e.printStackTrace(); // 解析失败时处理异常
        }
    }
}

运行结果:

解析结果:Fri Mar 15 00:00:00 CST 2024

设置时区(setTimeZone(TimeZone zone))

setTimeZone() 方法用来指定格式化 / 解析时使用的时区(默认使用系统时区)。示例:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class SimpleDateFormatExample3 {
    public static void main(String[] args) {
        Date now = new Date();

        // 默认时区,东八区,北京时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间:" + sdf.format(now));
        
        // 设置为UTC时区
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf2.setTimeZone(TimeZone.getTimeZone("UTC"));
        System.out.println("UTC时间:" + sdf2.format(now));
    }
}

运行结果:

当前时间:2025-09-01 22:48:26
UTC时间:2025-09-01 14:48:26

自定义复杂格式

包含毫秒和上午 / 下午标识,例如:

import java.text.SimpleDateFormat;
import java.util.Date;

public class DateFormatExample4 {
    public static void main(String[] args) {
        // 创建SimpleDateFormat实例,指定格式为"年/月/日 时:分:秒.毫秒 上午/下午"
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSS a");
        
        // 获取当前日期时间
        Date currentDate = new Date();
        
        // 格式化日期时间
        String formattedDate = sdf.format(currentDate);
        
        // 输出格式化结果
        System.out.println("格式化后的日期时间: " + formattedDate);
        
        // 演示不同时间的格式化
        demonstrateDifferentDates();
    }
    
    // 演示不同日期的格式化效果
    private static void demonstrateDifferentDates() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSS a");
        
        // 创建几个不同的时间点(使用时间戳)
        Date morning = new Date(1696500000000L);  // 2023年10月5日 上午
        Date afternoon = new Date(1696550000000L); // 2023年10月5日 下午
        Date midnight = new Date(1696454400000L);  // 2023年10月5日 午夜
        
        System.out.println("\n不同时间点的格式化示例:");
        System.out.println("上午时间: " + sdf.format(morning));
        System.out.println("下午时间: " + sdf.format(afternoon));
        System.out.println("午夜时间: " + sdf.format(midnight));
    }
}

运行结果:

格式化后的日期时间: 2025/09/01 10:47:39.006 下午

不同时间点的格式化示例:
上午时间: 2023/10/05 06:00:00.000 下午
下午时间: 2023/10/06 07:53:20.000 上午
午夜时间: 2023/10/05 05:20:00.000 上午

缺陷及问题

  1. 线程不安全:SimpleDateFormat 的内部状态会被格式化 / 解析操作修改,多线程共享实例时会导致数据错乱。解决方式:

    1. 每个线程创建独立实例

    2. 使用 ThreadLocal 存储实例

import java.text.SimpleDateFormat;
import java.util.Date;

public class ThreadSafeDateFormatter {
    // 使用ThreadLocal存储SimpleDateFormat实例,确保线程安全
    private static final ThreadLocal<SimpleDateFormat> sdfThreadLocal =
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
    
    /**
     * 将日期格式化为"yyyy-MM-dd"字符串
     * @param date 要格式化的日期
     * @return 格式化后的日期字符串
     */
    public static String formatDate(Date date) {
        // 从ThreadLocal中获取当前线程的SimpleDateFormat实例
        return sdfThreadLocal.get().format(date);
    }
    
    /**
     * 清理当前线程的ThreadLocal资源
     * 注意:在使用线程池时,建议在任务结束时调用此方法
     */
    public static void clean() {
        sdfThreadLocal.remove();
    }
    
    public static void main(String[] args) {
        // 演示多线程环境下使用
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    // 每个线程获取当前日期并格式化
                    Date currentDate = new Date();
                    String formattedDate = formatDate(currentDate);
                    System.out.println("线程 " + Thread.currentThread().getName() + " 格式化结果: " + formattedDate);
                    // 模拟线程处理其他任务
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 清理资源
                    clean();
                }
            }).start();
        }
    }
}

运行结果:

线程 Thread-2 格式化结果: 2025-09-01
线程 Thread-4 格式化结果: 2025-09-01
线程 Thread-1 格式化结果: 2025-09-01
线程 Thread-0 格式化结果: 2025-09-01
线程 Thread-3 格式化结果: 2025-09-01
  1. 解析异常处理繁琐:parse() 方法强制抛出 ParseException,即使格式正确也需显式处理,增加代码冗余。

  2. 对新日期类支持不足:不直接支持 JDK 1.8 引入的 java.time 类(如 LocalDateTime),需通过中间对象转换。

总结

SimpleDateFormat 是传统日期格式化工具,但因线程不安全和设计缺陷,JDK 1.8 后推荐使用 java.time.format.DateTimeFormatter,它是线程安全的,且支持新日期时间 API,使用更简洁可靠。

 

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号