Java 遗留日期类
在Java 8引入新的日期时间API之前,Java提供了一组用于处理日期和时间的类,主要包括java.util.Date
、java.util.Calendar
和java.text.SimpleDateFormat
。虽然这些类现在被认为是"遗留"API,但在许多现有代码中仍然广泛使用,因此了解它们的工作原理对于Java开发人员来说依然重要。
Date类
java.util.Date
是Java最早用于表示日期和时间的类,创建于JDK 1.0。
基本用法
// 创建代表当前时间的Date对象
Date currentDate = new Date();
System.out.println("当前时间: " + currentDate);
// 创建特定时间点的Date对象(不推荐,已过时)
Date specificDate = new Date(121, 0, 15); // 2021年1月15日
System.out.println("特定日期: " + specificDate);
// 获取时间戳(毫秒)
long timeInMillis = currentDate.getTime();
System.out.println("时间戳(毫秒): " + timeInMillis);
// 从时间戳创建Date
Date dateFromTimestamp = new Date(timeInMillis);
System.out.println("从时间戳创建的日期: " + dateFromTimestamp);
输出示例:
当前时间: Mon Jul 11 15:30:45 CST 2023
特定日期: Fri Jan 15 00:00:00 CST 2021
时间戳(毫秒): 1689063045123
从时间戳创建的日期: Mon Jul 11 15:30:45 CST 2023
Date
类有许多过时的方法(如getYear()
、getMonth()
等)不应再使用。此外,Date
构造函数中的年份参数需要减去1900,月份从0开始(即0表示一月),这些设计容易导致错误。
Calendar类
java.util.Calendar
是在JDK 1.1中引入的,目的是解决Date
类的一些局限性。它是一个抽象类,提供了更丰富的日期操作功能。
基本用法
// 获取Calendar实例
Calendar calendar = Calendar.getInstance();
// 设置日期
calendar.set(2023, Calendar.JULY, 11); // 2023年7月11日
// 获取日期信息
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // 月份从0开始,所以要加1
int day = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println("日期: " + year + "-" + month + "-" + day);
// 日期计算
Calendar futureDate = Calendar.getInstance();
futureDate.add(Calendar.DAY_OF_MONTH, 30); // 30天后
System.out.println("30天后: " + futureDate.getTime());
// Calendar转Date
Date date = calendar.getTime();
System.out.println("Calendar转Date: " + date);
输出示例:
日期: 2023-7-11
30天后: Thu Aug 10 15:30:45 CST 2023
Calendar转Date: Tue Jul 11 15:30:45 CST 2023
时区处理
// 使用特定时区的Calendar
Calendar japanCalendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Tokyo"));
System.out.println("东京时间: " + japanCalendar.getTime());
// 设置时区
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println("纽约时间: " + calendar.getTime());
SimpleDateFormat类
java.text.SimpleDateFormat
用于格式化和解析日期字符串,是DateFormat
的一个具体子类。
基本用法
// 创建日期格式化对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 格式化日期
Date now = new Date();
String formattedDate = sdf.format(now);
System.out.println("格式化后的日期: " + formattedDate);
// 解析日期字符串
try {
String dateStr = "2023-07-11 10:30:00";
Date parsedDate = sdf.parse(dateStr);
System.out.println("解析后的日期: " + parsedDate);
} catch (ParseException e) {
e.printStackTrace();
}
输出示例:
格式化后的日期: 2023-07-11 15:30:45
解析后的日期: Tue Jul 11 10:30:00 CST 2023
常用格式模式
符号 | 描述 | 示例 |
---|---|---|
y | 年 | 2023 |
M | 月 | 7或07或Jul |
d | 日 | 11或11 |
H | 小时(24小时制) | 15 |
h | 小时(12小时制) | 3 |
m | 分钟 | 30 |
s | 秒 | 45 |
S | 毫秒 | 678 |
E | 星期 | Tue或Tuesday |
a | 上午/下午 | AM或PM |
z | 时区 | CST或GMT+8:00 |
格式化示例
Date now = new Date();
// 不同的日期格式
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy/MM/dd");
System.out.println(sdf1.format(now)); // 2023/07/11
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日");
System.out.println(sdf2.format(now)); // 2023年07月11日
SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println(sdf3.format(now)); // 2023-07-11 15:30:45.678
SimpleDateFormat sdf4 = new SimpleDateFormat("E, MMMM dd yyyy");
System.out.println(sdf4.format(now)); // Tue, July 11 2023
SimpleDateFormat
不是线程安全的,如果在多线程环境中使用同一个实例可能会导致意外结果。在多线程环境中,应该为每个线程创建单独的实例,或使用线程安全的替代方案,如Java 8中的DateTimeFormatter
。
遗留日期API的问题
Java的遗留日期API存在许多问题,这也是为什么在Java 8中引入了全新的日期时间API:
- 设计不直观:月份从0开始(0=一月),年份需要加上1900。
- 可变性:
Date
和Calendar
对象是可变的,这在多线程环境中可能导致问题。 - 格式化不灵活:日期格式化和解析的支持有限。
- 线程安全性:
SimpleDateFormat
不是线程安全的。 - API不一致:方法命名和行为不一致。
- 时区处理复杂:处理不同时区的日期时间比较繁琐。
实际应用案例
案例1:计算两个日期之间的天数
public static long daysBetween(Date startDate, Date endDate) {
Calendar startCal = Calendar.getInstance();
startCal.setTime(startDate);
// 重置时分秒为0
startCal.set(Calendar.HOUR_OF_DAY, 0);
startCal.set(Calendar.MINUTE, 0);
startCal.set(Calendar.SECOND, 0);
startCal.set(Calendar.MILLISECOND, 0);
Calendar endCal = Calendar.getInstance();
endCal.setTime(endDate);
// 重置时分秒为0
endCal.set(Calendar.HOUR_OF_DAY, 0);
endCal.set(Calendar.MINUTE, 0);
endCal.set(Calendar.SECOND, 0);
endCal.set(Calendar.MILLISECOND, 0);
// 计算毫秒差,然后转换为天数
long diffMillis = endCal.getTimeInMillis() - startCal.getTimeInMillis();
return diffMillis / (24 * 60 * 60 * 1000);
}
// 使用示例
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date start = sdf.parse("2023-07-01");
Date end = sdf.parse("2023-07-11");
long days = daysBetween(start, end);
System.out.println("两个日期之间的天数: " + days);
} catch (ParseException e) {
e.printStackTrace();
}
输出:
两个日期之间的天数: 10
案例2:生成指定格式的日期报表
public static void generateDateReport(Date startDate, int days) {
SimpleDateFormat dateSdf = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat daySdf = new SimpleDateFormat("EEEE", Locale.ENGLISH);
Calendar cal = Calendar.getInstance();
cal.setTime(startDate);
System.out.println("日期报表");
System.out.println("--------------------");
for (int i = 0; i < days; i++) {
String dateStr = dateSdf.format(cal.getTime());
String dayOfWeek = daySdf.format(cal.getTime());
System.out.println(dateStr + " (" + dayOfWeek + ")");
cal.add(Calendar.DAY_OF_MONTH, 1);
}
System.out.println("--------------------");
}
// 使用示例
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date start = sdf.parse("2023-07-10");
generateDateReport(start, 5);
} catch (ParseException e) {
e.printStackTrace();
}
输出:
日期报表
--------------------
2023-07-10 (Monday)
2023-07-11 (Tuesday)
2023-07-12 (Wednesday)
2023-07-13 (Thursday)
2023-07-14 (Friday)
--------------------
总结
Java的遗留日期API由Date
、Calendar
和SimpleDateFormat
三个主要类组成:
- Date类:提供基本的日期时间表示,但大多数方法已经过时。
- Calendar类:提供了更多的日期操作功能,如日期计算和字段提取。
- SimpleDateFormat类:用于日期格式化和解析,但不是线程安全的。
虽然这些类存在设计缺陷,但在许多遗留系统中仍然使用。对于新的开发,建议使用Java 8引入的日期时间API(java.time包),它提供了更直观、不可变且线程安全的类来处理日期和时间。
练习
- 使用
Calendar
类创建一个方法,计算给定日期是一年中的第几天。 - 创建一个方法,使用
SimpleDateFormat
将日期格式从"yyyy-MM-dd"转换为"MM/dd/yyyy"。 - 编写一个程序,使用
Calendar
计算下个月的第一个星期一的日期。 - 创建一个方法,判断给定的两个日期是否在同一周内。
附加资源
- Oracle Java Documentation - Date
- Oracle Java Documentation - Calendar
- Oracle Java Documentation - SimpleDateFormat
- Java 8 Date and Time API Tutorial - 学习现代替代方案
学习完遗留日期API后,建议进一步学习Java 8中新引入的java.time包下的日期时间API,如LocalDate、LocalTime、LocalDateTime、ZonedDateTime等类,它们设计更合理且易用。