Appearance
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 类不是线程安全的,在多线程环境下使用可能会导致问题。
解决方案
在方法内部创建 SimpleDateFormat 对象:每次使用时创建新的实例
使用 ThreadLocal:为每个线程维护一个 SimpleDateFormat 实例
使用 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);最佳实践
选择合适的日期时间 API:
- Java 8 及以上:使用 java.time 包中的类
- Java 7 及以下:使用 Date 和 SimpleDateFormat
处理线程安全问题:
- 在方法内部创建 SimpleDateFormat 实例
- 使用 ThreadLocal
- 使用 Java 8 的 DateTimeFormatter
正确处理异常:
- 解析日期字符串时捕获 ParseException
设置正确的时区:
- 根据需要设置合适的时区
使用清晰的日期格式:
- 选择易于理解的日期格式
- 对于国际化应用,考虑使用标准格式
总结
Date 和 SimpleDateFormat 是 Java 中用于处理日期和时间的类:
Date 类:
- 表示特定的瞬间,精确到毫秒
- 提供获取和设置时间戳的方法
- 提供日期比较方法
SimpleDateFormat 类:
- 用于格式化日期为字符串
- 用于解析字符串为日期
- 支持自定义日期格式
线程安全问题:
- SimpleDateFormat 不是线程安全的
- 可以使用 ThreadLocal 或 Java 8 的 DateTimeFormatter 解决
Java 8 日期时间 API:
- 提供了更强大、更灵活的日期时间处理功能
- 线程安全
- 更易于使用
通过合理使用这些类,可以方便地处理各种日期和时间相关的操作。
