Java 中的所有時間操作類詳解及使用實戰(zhàn)
一、早期時間類
1.java.util.Date
- 簡介:最早的時間類,表示某一時刻。
- 常用方法:
getTime():返回自1970年1月1日00:00:00 GMT以來的毫秒數(shù)。toString():返回日期字符串。before(Date date)/after(Date date):比較日期先后。
- 缺點:大部分方法已廢棄,線程不安全,易出錯。
Date date = new Date(); System.out.println(date); // 當(dāng)前時間
2.java.util.Calendar
- 簡介:用于更復(fù)雜的日期計算(如加減天數(shù)),是抽象類,常用子類
GregorianCalendar。 - 常用方法:
add(int field, int amount):增加指定時間字段的值。get(int field):獲取指定字段的值(如 YEAR, MONTH)。set(int field, int value):設(shè)置指定字段的值。
- 缺點:API設(shè)計復(fù)雜,線程不安全。
Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, 5); // 當(dāng)前日期加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 引入的現(xiàn)代時間API(推薦)
所有類都在 java.time 包下,線程安全,易于使用。
1.LocalDate
- 簡介:只表示日期(不含時間),如 2024-06-01。
- 常用方法:
now():當(dāng)前日期。of(int year, int month, int dayOfMonth):指定日期。plusDays(long days):加天數(shù)。minusDays(long days):減天數(shù)。getYear(),getMonth(),getDayOfMonth():獲取年月日。
LocalDate today = LocalDate.now(); LocalDate tomorrow = today.plusDays(1);
2.LocalTime
- 簡介:只表示時間(不含日期),如 14:30:00。
- 常用方法:
now():當(dāng)前時間。of(int hour, int minute, int second):指定時間。plusHours(long hours):加小時。
LocalTime time = LocalTime.now(); LocalTime later = time.plusHours(2);
3.LocalDateTime
- 簡介:表示日期和時間,不含時區(qū)。
- 常用方法:
now():當(dāng)前日期時間。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
- 簡介:日期時間+時區(qū)。
- 常用方法:
now(ZoneId zone):當(dāng)前時區(qū)的日期時間。of(...):指定日期時間和時區(qū)。
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));5.Instant
- 簡介:時間戳,精確到納秒,表示自1970年1月1日00:00:00 UTC的瞬間。
- 常用方法:
now():當(dāng)前時間戳。ofEpochMilli(long epochMilli):通過毫秒數(shù)創(chuàng)建。
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:時區(qū)ID。ZoneOffset:時區(qū)偏移量。
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZoneOffset offset = ZoneOffset.of("+08:00");三、其他相關(guān)類
1.java.sql.Date、java.sql.Time、java.sql.Timestamp
- 用于數(shù)據(jù)庫操作,繼承自
java.util.Date,通常用于 JDBC。
四、時間類關(guān)系圖
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五、常用時間操作示例??????
// 當(dāng)前日期時間
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"));
// 字符串轉(zhuǎn)日期
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();六、建議
- 新項目優(yōu)先使用
java.time包下的類,線程安全、功能豐富、易用。 - 舊項目如果使用了
Date、Calendar,建議逐步遷移到新的時間API。 - 格式化和解析請用
DateTimeFormatter,避免SimpleDateFormat的線程安全問題。
七. 各時間類詳細用法與實戰(zhàn)場景
1.1 LocalDate
場景:只關(guān)心日期(如生日、節(jié)假日、賬單日期)
????????????
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
場景:只關(guān)心時間(如打卡時間、會議時間)
LocalTime startTime = LocalTime.of(9, 0, 0); LocalTime endTime = LocalTime.of(18, 0, 0); // 判斷是否在工作時間內(nèi) LocalTime now = LocalTime.now(); boolean isWorkTime = !now.isBefore(startTime) && !now.isAfter(endTime); // 時間加減 LocalTime lunchTime = startTime.plusHours(4);
1.3 LocalDateTime
場景:關(guān)心日期和時間(如訂單創(chuàng)建時間、日志時間)
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
場景:全球化應(yīng)用,關(guān)心時區(qū)(如國際會議、航班時間)
ZonedDateTime shanghaiTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
ZonedDateTime newYorkTime = shanghaiTime.withZoneSameInstant(ZoneId.of("America/New_York"));
// 獲取時區(qū)
ZoneId zoneId = shanghaiTime.getZone();1.5 Instant
場景:存儲時間戳(如數(shù)據(jù)庫、消息隊列)、高精度時間計算
Instant now = Instant.now(); long timestamp = now.toEpochMilli(); // 毫秒時間戳 // Instant與LocalDateTime互轉(zhuǎn) 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兼容與轉(zhuǎn)換
Date <-> LocalDateTime
// Date轉(zhuǎn)LocalDateTime Date date = new Date(); Instant instant = date.toInstant(); LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); // LocalDateTime轉(zhuǎn)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. 時區(qū)處理
// 獲取所有可用時區(qū)
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
// 當(dāng)前時間在不同地區(qū)
ZonedDateTime utcTime = ZonedDateTime.now(ZoneId.of("UTC"));
ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));6. 常見坑與注意事項
- 月份從1開始(不是0)
LocalDateTime沒有時區(qū)信息,存儲時要注意轉(zhuǎn)換SimpleDateFormat線程不安全,推薦用DateTimeFormatterDuration不能用于日期(用Period)Date和Calendar已過時,避免新項目使用- 時間操作建議統(tǒng)一使用一種API,避免混用造成混亂
7. 進階用法
7.1 時間區(qū)間判斷
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 按天、月、年循環(huán)
// 按天循環(huán)
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. 代碼片段匯總
// 獲取當(dāng)前時間戳(秒/毫秒)
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"));
// 時間區(qū)間
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. 時間操作常見應(yīng)用場景實戰(zhàn)
9.1 時間區(qū)間的交集與重疊判斷
在預(yù)訂系統(tǒng)、排班系統(tǒng)等場景,經(jīng)常需要判斷兩個時間段是否有重疊。
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 日期的周期性操作(如每周一的定時任務(wù))
// 獲取本周的所有日期
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 獲取某天的開始和結(jié)束時間
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 標(biāo)準(zhǔn)格式,如
"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 不同區(qū)域的日期格式
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. 時間工具類封裝示例
你可以將常用操作封裝為工具類,便于項目復(fù)用:
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 轉(zhuǎn)換為 LocalDateTime?
- 如何計算兩個日期之間的天數(shù)?
- 如何格式化為“剛剛”、“幾分鐘前”?
14. 未來趨勢和常用第三方庫
- 推薦只用 java.time 包,避免 Date、Calendar。
- 主流 ORM 框架(如 JPA、MyBatis)已支持 Java 8 時間類。
- 如果需要更高級的日歷功能,可用 Joda-Time(但現(xiàn)在已被 java.time 替代)。
- 時間處理相關(guān)的第三方庫如 Hutool、Apache Commons Lang 也有豐富的工具類。
15. 其他常見問題與補充
- 時間戳存儲建議用 UTC,顯示時再轉(zhuǎn)換為本地時區(qū)。
- 跨時區(qū)應(yīng)用注意夏令時(DST)變化。
- 數(shù)據(jù)庫時間字段建議用標(biāo)準(zhǔn)時間(如 UTC),避免因時區(qū)導(dǎo)致數(shù)據(jù)混亂。
到此這篇關(guān)于Java 中的所有時間操作類詳解及使用實戰(zhàn)的文章就介紹到這了,更多相關(guān)java時間操作類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot2底層注解@ConfigurationProperties配置綁定
這篇文章主要介紹了SpringBoot2底層注解@ConfigurationProperties配置綁定,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05
Intellj Idea中的maven工程Java文件顏色不對,未被識別的解決
這篇文章主要介紹了Intellj Idea中的maven工程Java文件顏色不對,未被識別的解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
SpringBoot用@Async注解實現(xiàn)異步任務(wù)
這篇文章主要介紹了SpringBoot用@Async注解實現(xiàn)異步任務(wù),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
SpringBoot整合Flink CDC實現(xiàn)實時追蹤mysql數(shù)據(jù)變動
我們將整合Spring Boot和Apache Flink CDC(Change Data Capture)來實現(xiàn)實時數(shù)據(jù)追蹤,下面是一個基本的實踐流程代碼,包括搭建Spring Boot項目、整合Flink CDC以及實現(xiàn)數(shù)據(jù)變動的實時追蹤,需要的朋友可以參考下2024-07-07
如何基于ThreadPoolExecutor創(chuàng)建線程池并操作
這篇文章主要介紹了如何基于ThreadPoolExecutor創(chuàng)建線程池并操作,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-11-11

