Java日期处理
引言
在各种语言编程中,日期和时间的处理都是一个常见的需求。Java中还特殊一点,在Java8 前后提供了不同的日期和时间 API,它们在设计和使用上有很大的差异。本文主要介绍 Java8 前后日期转化的方法、优缺点和一些示例。
Java8 以前的日期处理
常用类
在 Java 8 以前,主要使用
java.util.Date
处理日期java.util.Calendar
处理时间java.text.SimpleDateFormat
用于日期的格式化和解析。
优缺点
- 优点
- 早期的 Java 项目中广泛使用,基本能满足简单的日期处理需求。
- 缺点
Date
类的大部分方法已被弃用,设计不够合理,比如年份从 1900 开始计算,月份从 0 开始计算,容易导致混淆。Calendar
类的 API 比较复杂,使用起来不够简洁。- 非线程安全,在多线程环境下使用
SimpleDateFormat
可能会导致数据不一致或抛出异常。
常用 API
SimpleDateFormat.parse(String source)
:将字符串解析为Date
对象。SimpleDateFormat.format(Date date)
:将Date
对象格式化为字符串。Calendar.getInstance()
:获取当前系统时间的Calendar
实例。Calendar.set(int field, int value)
:设置Calendar
的指定字段的值。
示例
日期和时间戳
// 1. 当前日期的对象
Date date1 = new Date();
// 2. 日期对象转毫秒(1970-01-01 00:00:00)
// 日期比较大小,就是使用的转毫秒后的比较
long time1 = date1.getTime();
// 3. 毫秒转日期对象
Date date2 = new Date(time1 + 3600000);
// 4. 日期对象设置具体一个时间戳 void
// 注意这里date1对象就发生了变化
date1.setTime(System.currentTimeMillis() + 1800000);
日期格式化
// sdf 对象,日期格式和给定字符串格式要一致,否则该Java日期类会出意想不到的bug
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = "1971-08-05 20:10:12";
try {
// 1. 字符串格式解析为Date对象
Date date = sdf.parse(dateStr);
System.out.println(date);
// 2. 日期对象转为字符串格式
String dateStr1 = sdf.format(date);
System.out.println(dateStr1);
// 3. format也支持时间戳转换字符串格式
String dateStr2 = sdf.format(date.getTime());
} catch (ParseException e) {
e.printStackTrace();
}
日期比较大小
日期对象转成毫秒时间戳比较
时间类 Calendar
Calendar 可以方便的获取和修改 年、月、日、时、分、秒这些属性
// 日历对象 包含所有时间信息
Calendar calendar = Calendar.getInstance();
// calendar 转成 date 对象
Date date = calendar.getTime();
// calendar 获取毫秒
long timeInMillis = calendar.getTimeInMillis();
// date对象,转成calendar对象
calendar.setTime(new Date());
// 获取 年月日 时分秒,传入Calendar内常量
int year = calendar.get(Calendar.YEAR);
// 月比较特殊,从0开始,1月份是0
int month = calendar.get(Calendar.MONTH);
// 每月几号
int day = calendar.get(Calendar.DATE);
// 增加、减少时间
// 增加30天 calendar对象发生了变化(非不可变对象)
calendar.add(Calendar.DAY_OF_MONTH, 30);
// 上2个月
calendar.add(Calendar.MONTH, -3);
// 设置指定日期
calendar.set(Calendar.DATE, 29);
Java8 以后的日期处理
常用类
Java8 引入了新的日期和时间 API,位于 java.time
包下,主要包括
LocalDate
年月日 星期LocalTime
时分秒 纳秒LocalDateTime
都包含了DateTimeFormatter
等类。
优缺点
- 优点
- 设计更加合理,API 更加简洁易懂,避免了旧 API 的一些问题,如年份和月份的计算方式。
- 线程安全,
DateTimeFormatter
是不可变的,在多线程环境下可以安全使用。 - 支持更多的日期和时间操作,如日期加减、比较等。
示例
LocalDate、LocalTime、LocalDateTime
API 比较类似,方法名都比较清爽直观。
LocalDateTime
包含了LocalDate
和 LocalTime
,使用的也更多。
// ======= LocalDate =======
// 当前日期 年月日星期
LocalDate now = LocalDate.now();
// 年
int year = now.getYear();
// 几月 从1开始,不同于Date
int monthValue = now.getMonthValue();
// 几号
int dayOfMonth = now.getDayOfMonth();
// 星期几
DayOfWeek dayOfWeek = now.getDayOfWeek();
// withXxx 修改指定年月日 生成新的对象,不修改原来的对象;或者 of方法指定
LocalDate localDate = now.withYear(2099).withMonth(12).withDayOfMonth(31);
// plusXxx 增加年月日
LocalDate localDate1 = now.plusYears(1).plusMonths(2).plusDays(2);
// minusXxx 减少年月日
LocalDate localDate2 = now.minusYears(1).minusMonths(2).minusDays(5);
// 比较日期
boolean before = localDate1.isBefore(localDate2);
boolean after = localDate2.isAfter(localDate1);
boolean equal = localDate2.isEqual(localDate1);
// ======= LocalTime =======
// 当前时间 时分秒 纳秒
LocalTime now = LocalTime.now();
// 小时
int hour = now.getHour();
// 分
int minute = now.getMinute();
// 秒
int second = now.getSecond();
// withXxx 修改
LocalTime localTime = now.withHour(1).withMinute(2).withSecond(3);
// plusXxx minusXxxx 增加 减少
LocalTime localTime1 = now.plusHours(2).minusMinutes(2);
// 比较日期
boolean before = localTime.isBefore(localTime1);
boolean after = localTime.isAfter(localTime1);
// ======= LocalDateTime =======
// 用法综合以上API
// 当前日期时间 时分秒 纳秒
LocalDateTime now = LocalDateTime.now();
// 转 LocalDate、LocalTime
LocalDate localDate = now.toLocalDate();
LocalTime localTime = now.toLocalTime();
// 构造 LocalDateTime
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
字符串日期格式转成日期对象
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// DateTimeFormatter 提供的format方法
String format = formatter.format(localDateTime);
// LocalDateTime 本身也有format方法
String format1 = localDateTime.format(formatter);
// 字符串格式回 LocalDateTime 对象
String dateStr = "2013-08-02 20:10:12";
LocalDateTime parseTime = LocalDateTime.parse(dateStr, formatter);
Java8 以后的日期对象和 Java8 之前的日期对象的转换
Date
转 LocalDate
、LocalDateTime
Date date = new Date();
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
// Date 对象转 LocalDate、 LocalDateTime
LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
LocalDate localDate = instant.atZone(zoneId).toLocalDate();
LocalDateTime
转 Date
先将 LocalDateTime 转换为 Instant(表示时间线上的一个瞬时点),再结合系统默认时区信息将 Instant 转换为 Date。
// LocalDateTime 对象
LocalDateTime localDateTime = LocalDateTime.now();
// 将 LocalDateTime 转换为 ZonedDateTime,使用系统默认时区
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
// 将 ZonedDateTime 转换为 Instant
Instant instant = zonedDateTime.toInstant();
// 将 Instant 转换为 Date
Date date = Date.from(instant);
总结
Java8 引入的新日期和时间 API 解决了旧 API 的很多问题,提供了更加简洁方便、安全和强大的日期处理功能。在新的项目中,建议优先使用Java 8 以后的日期和时间API。对于旧项目,如果需要兼容旧的代码,也可以通过转换方法在新旧日期对象之间进行转换。