Skip to content

16.3 Date / SimpleDateFormat 日期类

Date 类的概念

Date 类是 Java 中用于表示日期和时间的类,位于 java.util 包中。它表示特定的瞬间,精确到毫秒。

Date 类的使用

创建 Date 对象

java
import java.util.Date;

// 创建表示当前时间的 Date 对象
Date now = new Date();

// 创建指定时间戳的 Date 对象(时间戳是从 1970 年 1 月 1 日 00:00:00 GMT 开始的毫秒数)
Date specificDate = new Date(1234567890000L);

Date 类的常用方法

获取时间戳

java
long timestamp = new Date().getTime(); // 获取从 1970 年 1 月 1 日 00:00:00 GMT 开始的毫秒数

比较日期

java
Date date1 = new Date();
Date date2 = new Date(System.currentTimeMillis() + 1000); // 1秒后的时间

boolean before = date1.before(date2); // date1 是否在 date2 之前
boolean after = date1.after(date2); // date1 是否在 date2 之后
int compare = date1.compareTo(date2); // 比较两个日期,返回负数、零或正数

设置时间

java
Date date = new Date();
date.setTime(System.currentTimeMillis() + 3600000); // 设置为 1 小时后的时间

SimpleDateFormat 类的概念

SimpleDateFormat 类是 Java 中用于格式化和解析日期的类,位于 java.text 包中。它允许我们将日期对象格式化为字符串,或将字符串解析为日期对象。

SimpleDateFormat 类的使用

创建 SimpleDateFormat 对象

java
import java.text.SimpleDateFormat;

// 创建 SimpleDateFormat 对象,指定日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

日期格式模式

模式含义示例
yyyy年份2023
MM月份(01-12)09
dd日期(01-31)15
HH小时(00-23)14
mm分钟(00-59)30
ss秒(00-59)45
SSS毫秒(000-999)123
E星期几星期四
z时区CST
Z时区偏移+0800

格式化日期

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

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date now = new Date();
String formattedDate = sdf.format(now);
System.out.println("格式化后的日期: " + formattedDate);

解析字符串为日期

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

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
    Date date = sdf.parse("2023-09-15");
    System.out.println("解析后的日期: " + date);
} catch (ParseException e) {
    e.printStackTrace();
}

示例:Date 和 SimpleDateFormat 的应用

示例 1:格式化当前日期

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

public class FormatDateExample {
    public static void main(String[] args) {
        // 创建不同格式的 SimpleDateFormat
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdf2 = new SimpleDateFormat("HH:mm:ss");
        SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat sdf4 = new SimpleDateFormat("yyyy年MM月dd日 E HH:mm:ss");
        
        Date now = new Date();
        
        System.out.println("日期: " + sdf1.format(now));
        System.out.println("时间: " + sdf2.format(now));
        System.out.println("日期时间: " + sdf3.format(now));
        System.out.println("带星期的日期时间: " + sdf4.format(now));
    }
}

示例 2:解析日期字符串

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

public class ParseDateExample {
    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        
        try {
            // 解析日期字符串
            Date date = sdf.parse("2023-09-15");
            System.out.println("解析后的日期: " + date);
            
            // 格式化解析后的日期
            String formattedDate = sdf.format(date);
            System.out.println("格式化后的日期: " + formattedDate);
        } catch (ParseException e) {
            System.out.println("解析日期失败: " + e.getMessage());
        }
    }
}

示例 3:计算日期差

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

public class DateDifferenceExample {
    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        
        try {
            // 解析两个日期
            Date date1 = sdf.parse("2023-01-01");
            Date date2 = sdf.parse("2023-12-31");
            
            // 计算时间差(毫秒)
            long diffInMillies = Math.abs(date2.getTime() - date1.getTime());
            
            // 转换为天数
            long diffInDays = diffInMillies / (24 * 60 * 60 * 1000);
            
            System.out.println("两个日期之间的天数差: " + diffInDays);
        } catch (ParseException e) {
            System.out.println("解析日期失败: " + e.getMessage());
        }
    }
}

示例 4:日期时间的加减

java
import java.util.Date;

public class DateAddSubtractExample {
    public static void main(String[] args) {
        Date now = new Date();
        System.out.println("当前时间: " + now);
        
        // 增加 1 天
        Date tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000);
        System.out.println("明天: " + tomorrow);
        
        // 减少 1 小时
        Date oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);
        System.out.println("1小时前: " + oneHourAgo);
        
        // 增加 30 分钟
        Date thirtyMinutesLater = new Date(now.getTime() + 30 * 60 * 1000);
        System.out.println("30分钟后: " + thirtyMinutesLater);
    }
}

线程安全问题

SimpleDateFormat 类不是线程安全的,在多线程环境下使用可能会导致问题。

解决方案

  1. 在方法内部创建 SimpleDateFormat 对象:每次使用时创建新的实例

  2. 使用 ThreadLocal:为每个线程维护一个 SimpleDateFormat 实例

  3. 使用 DateTimeFormatter:Java 8 引入的线程安全的日期时间格式化类

示例:使用 ThreadLocal 解决线程安全问题

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

public class ThreadLocalSimpleDateFormat {
    // 使用 ThreadLocal 存储 SimpleDateFormat 实例
    private static final ThreadLocal<SimpleDateFormat> sdf = ThreadLocal.withInitial(
        () -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    );
    
    public static String format(Date date) {
        return sdf.get().format(date);
    }
    
    public static void main(String[] args) {
        Date now = new Date();
        System.out.println("格式化后的日期: " + format(now));
    }
}

Java 8 日期时间 API

Java 8 引入了新的日期时间 API,位于 java.time 包中,提供了更强大、更灵活的日期时间处理功能。

主要类

  • LocalDate:表示日期(年、月、日)
  • LocalTime:表示时间(时、分、秒)
  • LocalDateTime:表示日期和时间
  • DateTimeFormatter:线程安全的日期时间格式化类

示例:使用 Java 8 日期时间 API

java
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Java8DateTimeExample {
    public static void main(String[] args) {
        // 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前日期时间: " + now);
        
        // 格式化日期时间
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedDateTime = now.format(formatter);
        System.out.println("格式化后的日期时间: " + formattedDateTime);
        
        // 解析日期时间字符串
        LocalDateTime parsedDateTime = LocalDateTime.parse("2023-09-15 14:30:45", formatter);
        System.out.println("解析后的日期时间: " + parsedDateTime);
    }
}

常见问题

1. 解析日期字符串失败

症状:调用 parse() 方法时抛出 ParseException

解决方案:确保日期字符串的格式与 SimpleDateFormat 中指定的格式完全匹配

示例

java
// 错误:日期字符串格式与指定格式不匹配
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// Date date = sdf.parse("2023/09/15"); // 抛出 ParseException

// 正确:日期字符串格式与指定格式匹配
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("2023-09-15"); // 解析成功

2. 线程安全问题

症状:在多线程环境下使用 SimpleDateFormat 导致日期解析错误或其他问题

解决方案:使用 ThreadLocal 或 Java 8 的 DateTimeFormatter

示例

java
// 错误:在多线程环境下共享 SimpleDateFormat 实例
// private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

// 正确:使用 ThreadLocal
private static final ThreadLocal<SimpleDateFormat> sdf = ThreadLocal.withInitial(
    () -> new SimpleDateFormat("yyyy-MM-dd")
);

3. 时区问题

症状:日期时间显示与预期不符

解决方案:设置正确的时区

示例

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

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 设置为上海时区
Date now = new Date();
String formattedDate = sdf.format(now);
System.out.println("格式化后的日期: " + formattedDate);

最佳实践

  1. 选择合适的日期时间 API

    • Java 8 及以上:使用 java.time 包中的类
    • Java 7 及以下:使用 Date 和 SimpleDateFormat
  2. 处理线程安全问题

    • 在方法内部创建 SimpleDateFormat 实例
    • 使用 ThreadLocal
    • 使用 Java 8 的 DateTimeFormatter
  3. 正确处理异常

    • 解析日期字符串时捕获 ParseException
  4. 设置正确的时区

    • 根据需要设置合适的时区
  5. 使用清晰的日期格式

    • 选择易于理解的日期格式
    • 对于国际化应用,考虑使用标准格式

总结

DateSimpleDateFormat 是 Java 中用于处理日期和时间的类:

  1. Date 类

    • 表示特定的瞬间,精确到毫秒
    • 提供获取和设置时间戳的方法
    • 提供日期比较方法
  2. SimpleDateFormat 类

    • 用于格式化日期为字符串
    • 用于解析字符串为日期
    • 支持自定义日期格式
  3. 线程安全问题

    • SimpleDateFormat 不是线程安全的
    • 可以使用 ThreadLocal 或 Java 8 的 DateTimeFormatter 解决
  4. Java 8 日期时间 API

    • 提供了更强大、更灵活的日期时间处理功能
    • 线程安全
    • 更易于使用

通过合理使用这些类,可以方便地处理各种日期和时间相关的操作。

© 2026 编程马·菜鸟教程 版权所有