Java 中的所有时间操作类详解及使用实战
作者:猩火燎猿
Java时间处理API演进与应用指南,本文系统介绍了Java中时间处理API的发展历程和实用技巧,结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
一、早期时间类
1.java.util.Date
- 简介:最早的时间类,表示某一时刻。
- 常用方法:
getTime():返回自1970年1月1日00:00:00 GMT以来的毫秒数。toString():返回日期字符串。before(Date date)/after(Date date):比较日期先后。
- 缺点:大部分方法已废弃,线程不安全,易出错。
Date date = new Date(); System.out.println(date); // 当前时间
2.java.util.Calendar
- 简介:用于更复杂的日期计算(如加减天数),是抽象类,常用子类
GregorianCalendar。 - 常用方法:
add(int field, int amount):增加指定时间字段的值。get(int field):获取指定字段的值(如 YEAR, MONTH)。set(int field, int value):设置指定字段的值。
- 缺点:API设计复杂,线程不安全。
Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, 5); // 当前日期加5天 Date newDate = cal.getTime();
3.java.text.SimpleDateFormat
- 简介:用于日期格式化和解析。
- 常用方法:
format(Date date):格式化日期为字符串。parse(String source):解析字符串为日期对象。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(new Date());
Date date = sdf.parse("2024-06-01 12:00:00");二、Java 8 引入的现代时间API(推荐)
所有类都在 java.time 包下,线程安全,易于使用。
1.LocalDate
- 简介:只表示日期(不含时间),如 2024-06-01。
- 常用方法:
now():当前日期。of(int year, int month, int dayOfMonth):指定日期。plusDays(long days):加天数。minusDays(long days):减天数。getYear(),getMonth(),getDayOfMonth():获取年月日。
LocalDate today = LocalDate.now(); LocalDate tomorrow = today.plusDays(1);
2.LocalTime
- 简介:只表示时间(不含日期),如 14:30:00。
- 常用方法:
now():当前时间。of(int hour, int minute, int second):指定时间。plusHours(long hours):加小时。
LocalTime time = LocalTime.now(); LocalTime later = time.plusHours(2);
3.LocalDateTime
- 简介:表示日期和时间,不含时区。
- 常用方法:
now():当前日期时间。of(int year, int month, int day, int hour, int minute, int second):指定日期时间。plusDays(),plusHours():加天/小时。
LocalDateTime ldt = LocalDateTime.now(); LocalDateTime future = ldt.plusDays(3).plusHours(5);
4.ZonedDateTime
- 简介:日期时间+时区。
- 常用方法:
now(ZoneId zone):当前时区的日期时间。of(...):指定日期时间和时区。
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));5.Instant
- 简介:时间戳,精确到纳秒,表示自1970年1月1日00:00:00 UTC的瞬间。
- 常用方法:
now():当前时间戳。ofEpochMilli(long epochMilli):通过毫秒数创建。
Instant instant = Instant.now(); long epochMilli = instant.toEpochMilli();
6.Duration&Period
Duration:表示两个时间点之间的时间量(秒、纳秒),适用于LocalTime、LocalDateTime、Instant。Period:表示两个日期之间的时间量(年、月、日),适用于LocalDate。
Duration duration = Duration.between(LocalTime.now(), LocalTime.now().plusHours(2)); Period period = Period.between(LocalDate.now(), LocalDate.now().plusDays(10));
7.DateTimeFormatter
- 简介:格式化和解析日期时间,线程安全。
- 常用方法:
format(TemporalAccessor temporal):格式化为字符串。parse(CharSequence text):解析字符串为日期时间对象。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String str = formatter.format(LocalDateTime.now());
LocalDateTime ldt = LocalDateTime.parse("2024-06-01 12:00:00", formatter);8.ZoneId&ZoneOffset
ZoneId:时区ID。ZoneOffset:时区偏移量。
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZoneOffset offset = ZoneOffset.of("+08:00");三、其他相关类
1.java.sql.Date、java.sql.Time、java.sql.Timestamp
- 用于数据库操作,继承自
java.util.Date,通常用于 JDBC。
四、时间类关系图
java.util.Date
├─ java.sql.Date
├─ java.sql.Time
└─ java.sql.Timestamp
java.util.Calendar
└─ java.util.GregorianCalendar
java.text.SimpleDateFormat
java.time.LocalDate
java.time.LocalTime
java.time.LocalDateTime
java.time.ZonedDateTime
java.time.Instant
java.time.Duration
java.time.Period
java.time.DateTimeFormatter
java.time.ZoneId
java.time.ZoneOffset五、常用时间操作示例
// 当前日期时间
LocalDateTime now = LocalDateTime.now();
// 日期加减
LocalDateTime tomorrow = now.plusDays(1);
LocalDateTime lastWeek = now.minusWeeks(1);
// 日期格式化
String str = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
// 字符串转日期
LocalDateTime ldt = LocalDateTime.parse("2024-06-01 12:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
// 时间差
Duration duration = Duration.between(now, tomorrow);
long hours = duration.toHours();六、建议
- 新项目优先使用
java.time包下的类,线程安全、功能丰富、易用。 - 旧项目如果使用了
Date、Calendar,建议逐步迁移到新的时间API。 - 格式化和解析请用
DateTimeFormatter,避免SimpleDateFormat的线程安全问题。
七. 各时间类详细用法与实战场景
1.1 LocalDate
场景:只关心日期(如生日、节假日、账单日期)
LocalDate birthday = LocalDate.of(1995, 6, 1); LocalDate today = LocalDate.now(); // 判断是否是今天 boolean isToday = birthday.equals(today); // 获取本月第一天 LocalDate firstDay = today.withDayOfMonth(1); // 获取本月最后一天 LocalDate lastDay = today.withDayOfMonth(today.lengthOfMonth()); // 日期加减 LocalDate nextWeek = today.plusWeeks(1); LocalDate lastYear = today.minusYears(1);
1.2 LocalTime
场景:只关心时间(如打卡时间、会议时间)
LocalTime startTime = LocalTime.of(9, 0, 0); LocalTime endTime = LocalTime.of(18, 0, 0); // 判断是否在工作时间内 LocalTime now = LocalTime.now(); boolean isWorkTime = !now.isBefore(startTime) && !now.isAfter(endTime); // 时间加减 LocalTime lunchTime = startTime.plusHours(4);
1.3 LocalDateTime
场景:关心日期和时间(如订单创建时间、日志时间)
LocalDateTime orderTime = LocalDateTime.now(); LocalDateTime expireTime = orderTime.plusHours(2); // 比较先后 boolean isExpired = LocalDateTime.now().isAfter(expireTime); // 获取年月日时分秒 int year = orderTime.getYear(); int month = orderTime.getMonthValue(); int day = orderTime.getDayOfMonth(); int hour = orderTime.getHour(); int minute = orderTime.getMinute();
1.4 ZonedDateTime
场景:全球化应用,关心时区(如国际会议、航班时间)
ZonedDateTime shanghaiTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
ZonedDateTime newYorkTime = shanghaiTime.withZoneSameInstant(ZoneId.of("America/New_York"));
// 获取时区
ZoneId zoneId = shanghaiTime.getZone();1.5 Instant
场景:存储时间戳(如数据库、消息队列)、高精度时间计算
Instant now = Instant.now(); long timestamp = now.toEpochMilli(); // 毫秒时间戳 // Instant与LocalDateTime互转 LocalDateTime ldt = LocalDateTime.ofInstant(now, ZoneId.systemDefault()); Instant instant = ldt.atZone(ZoneId.systemDefault()).toInstant();
1.6 Duration & Period
场景:计算时间差
// Duration: 时间点之间的差(如秒、纳秒) Duration duration = Duration.between(ldt1, ldt2); long seconds = duration.getSeconds(); long minutes = duration.toMinutes(); // Period: 日期之间的差(如年、月、日) Period period = Period.between(date1, date2); int days = period.getDays(); int months = period.getMonths(); int years = period.getYears();
2. 时间比较与排序
LocalDateTime t1 = LocalDateTime.of(2024, 6, 1, 12, 0); LocalDateTime t2 = LocalDateTime.of(2024, 6, 2, 12, 0); boolean isBefore = t1.isBefore(t2); // true boolean isAfter = t1.isAfter(t2); // false boolean isEqual = t1.isEqual(t2); // false // 排序 List<LocalDateTime> list = Arrays.asList(t1, t2); list.sort(Comparator.naturalOrder());
3. 与旧API兼容与转换
Date <-> LocalDateTime
// Date转LocalDateTime Date date = new Date(); Instant instant = date.toInstant(); LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); // LocalDateTime转Date LocalDateTime ldt2 = LocalDateTime.now(); Instant instant2 = ldt2.atZone(ZoneId.systemDefault()).toInstant(); Date date2 = Date.from(instant2);
4. 时间格式化与解析(自定义格式)
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
// 格式化
String str = LocalDateTime.now().format(fmt);
// 解析
LocalDateTime ldt = LocalDateTime.parse("2024/06/01 13:45:30", fmt);5. 时区处理
// 获取所有可用时区
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
// 当前时间在不同地区
ZonedDateTime utcTime = ZonedDateTime.now(ZoneId.of("UTC"));
ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));6. 常见坑与注意事项
- 月份从1开始(不是0)
LocalDateTime没有时区信息,存储时要注意转换SimpleDateFormat线程不安全,推荐用DateTimeFormatterDuration不能用于日期(用Period)Date和Calendar已过时,避免新项目使用- 时间操作建议统一使用一种API,避免混用造成混乱
7. 进阶用法
7.1 时间区间判断
LocalDateTime now = LocalDateTime.now(); LocalDateTime start = LocalDateTime.of(2024, 6, 1, 9, 0); LocalDateTime end = LocalDateTime.of(2024, 6, 1, 18, 0); boolean inRange = !now.isBefore(start) && !now.isAfter(end);
7.2 按天、月、年循环
// 按天循环
LocalDate start = LocalDate.of(2024, 6, 1);
LocalDate end = LocalDate.of(2024, 6, 10);
for (LocalDate d = start; !d.isAfter(end); d = d.plusDays(1)) {
System.out.println(d);
}7.3 时间差友好显示
Duration duration = Duration.between(ldt1, ldt2); long hours = duration.toHours(); long minutes = duration.toMinutes() % 60; System.out.println(hours + "小时" + minutes + "分钟");
8. 代码片段汇总
// 获取当前时间戳(秒/毫秒)
long epochSecond = Instant.now().getEpochSecond();
long epochMilli = Instant.now().toEpochMilli();
// 时间加减
LocalDateTime t = LocalDateTime.now().plusDays(3).minusHours(2);
// 时间格式化
String s = t.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
// 时间解析
LocalDateTime parsed = LocalDateTime.parse("2024-06-01 12:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
// 时间区间
LocalDate start = LocalDate.of(2024, 6, 1);
LocalDate end = LocalDate.of(2024, 6, 10);
for (LocalDate d = start; !d.isAfter(end); d = d.plusDays(1)) {
// ...
}9. 时间操作常见应用场景实战
9.1 时间区间的交集与重叠判断
在预订系统、排班系统等场景,经常需要判断两个时间段是否有重叠。
public static boolean isOverlap(LocalDateTime start1, LocalDateTime end1,
LocalDateTime start2, LocalDateTime end2) {
return !start1.isAfter(end2) && !start2.isAfter(end1);
}
// 示例
LocalDateTime s1 = LocalDateTime.of(2024, 6, 1, 10, 0);
LocalDateTime e1 = LocalDateTime.of(2024, 6, 1, 12, 0);
LocalDateTime s2 = LocalDateTime.of(2024, 6, 1, 11, 0);
LocalDateTime e2 = LocalDateTime.of(2024, 6, 1, 13, 0);
boolean overlap = isOverlap(s1, e1, s2, e2); // true9.2 日期的周期性操作(如每周一的定时任务)
// 获取本周的所有日期
LocalDate monday = LocalDate.now().with(DayOfWeek.MONDAY);
for (int i = 0; i < 7; i++) {
LocalDate d = monday.plusDays(i);
System.out.println(d + " " + d.getDayOfWeek());
}9.3 计算某月的第一天和最后一天
LocalDate now = LocalDate.now(); LocalDate firstDay = now.withDayOfMonth(1); LocalDate lastDay = now.withDayOfMonth(now.lengthOfMonth());
9.4 获取某天的开始和结束时间
LocalDate date = LocalDate.of(2024, 6, 1); LocalDateTime startOfDay = date.atStartOfDay(); LocalDateTime endOfDay = date.atTime(LocalTime.MAX); // 23:59:59.999999999
9.5 时间格式化为友好字符串(如“刚刚”、“1分钟前”、“1天前”)
public static String friendlyTime(LocalDateTime time) {
Duration duration = Duration.between(time, LocalDateTime.now());
long seconds = duration.getSeconds();
if (seconds < 60) return "刚刚";
if (seconds < 3600) return (seconds / 60) + "分钟前";
if (seconds < 86400) return (seconds / 3600) + "小时前";
return (seconds / 86400) + "天前";
}9.6 日期时间的序列化与反序列化(如 JSON)
- 推荐用 ISO 标准格式,如
"2024-06-01T12:00:00"。 - Jackson、Gson 等主流 JSON 库在 Java 8 后已支持直接序列化/反序列化
LocalDateTime、LocalDate等类型。 - 若需自定义格式,可用注解:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime;
10. 时间操作的性能与线程安全
新 API(java.time)都是不可变对象,线程安全。
旧 API(Date、Calendar、SimpleDateFormat)都非线程安全。
示例:多线程格式化日期时,推荐如下写法:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
Runnable task = () -> {
String formatted = LocalDateTime.now().format(formatter);
System.out.println(formatted);
};
new Thread(task).start();11. 时间的国际化与本地化
11.1 不同区域的日期格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日", Locale.CHINA);
String str = LocalDate.now().format(formatter); // 2024年06月01日11.2 不同国家的周起始日
LocalDate date = LocalDate.now(); DayOfWeek firstDayOfWeek = WeekFields.of(Locale.US).getFirstDayOfWeek(); // SUNDAY DayOfWeek firstDayOfWeekCN = WeekFields.of(Locale.CHINA).getFirstDayOfWeek(); // MONDAY
12. 时间工具类封装示例
你可以将常用操作封装为工具类,便于项目复用:
public class DateTimeUtils {
public static String format(LocalDateTime time, String pattern) {
return time.format(DateTimeFormatter.ofPattern(pattern));
}
public static LocalDateTime parse(String str, String pattern) {
return LocalDateTime.parse(str, DateTimeFormatter.ofPattern(pattern));
}
public static long diffMinutes(LocalDateTime start, LocalDateTime end) {
return Duration.between(start, end).toMinutes();
}
// 更多方法...
}13. 时间操作常见面试题
- 如何获取某个月的最后一天?
- 如何判断两个时间段是否有重叠?
- 如何将 Date 转换为 LocalDateTime?
- 如何计算两个日期之间的天数?
- 如何格式化为“刚刚”、“几分钟前”?
14. 未来趋势和常用第三方库
- 推荐只用 java.time 包,避免 Date、Calendar。
- 主流 ORM 框架(如 JPA、MyBatis)已支持 Java 8 时间类。
- 如果需要更高级的日历功能,可用 Joda-Time(但现在已被 java.time 替代)。
- 时间处理相关的第三方库如 Hutool、Apache Commons Lang 也有丰富的工具类。
15. 其他常见问题与补充
- 时间戳存储建议用 UTC,显示时再转换为本地时区。
- 跨时区应用注意夏令时(DST)变化。
- 数据库时间字段建议用标准时间(如 UTC),避免因时区导致数据混乱。
到此这篇关于Java 中的所有时间操作类详解及使用实战的文章就介绍到这了,更多相关java时间操作类内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
