Java中日期的加減&String Date Calendar的相互轉(zhuǎn)換方式
最近在 Java 中遇到這樣一個需求:對字符串日期加減數(shù)天,比如:
- “20220815” 加 1 天變?yōu)?“20220816”
- “20220901” 減 1 天變?yōu)?“20220831”
- “20240228” 加 2 天變?yōu)?“20240301”
等等。不熟悉 API 的我愣了,于是經(jīng)學(xué)習(xí)整理出本文,希望能幫到讀者。本文會梳理 String Date Calendar 的基本用法及相互轉(zhuǎn)換。
基本思路
先說實現(xiàn)對字符串加減數(shù)日的需求,需要這樣的方法:
String addDay(String str, int num)
但 Java 中沒有方法能直接把字符串看作日期并對其加減若干天,所以先把格式五花八門的 String 解析成唯一的、能夠代表一個時刻的 Date, 然后對 Date 一番操作,加數(shù)天也好減數(shù)月也好,再按希望的格式轉(zhuǎn)回 String, 這就是基本思路。
而在這個過程中,涉及到 String Date Calendar 三種類型的對象的相互轉(zhuǎn)換。如下:
String →simple.parse(str)→
Date →calendar.setTime(date)→
Calendar →calendar.getTime()→
Date →simple.format(date)→
String
接下來是面向 0 基礎(chǔ)的逐步講解:
String ← Date
Java 中一個 Date 類型對象可以表示一個瞬時時刻,最高精確到毫秒。
public static void main(String[] args) {
Date date = new Date();
System.out.println(date.toString()); // Mon Aug 15 18:19:55 CST 2022
}new Date() 能夠獲得一個表示當(dāng)前時刻的 Date 對象,直接輸出之即可。(本文會在非 String 類型對象輸出時加上 toString() 方法,便于理解)
如果不想輸出默認字符串,可以借助:SimpleDateFormat 類自定義輸出字符串的格式:
public static void main(String[] args) {
Date date = new Date();
System.out.println(date.toString()); // Mon Aug 15 18:19:55 CST 2022
SimpleDateFormat f = new SimpleDateFormat("yyyy/MM/dd");
System.out.println(f.format(date)); // 2022/08/15
}public final String format(Date date) 方法能按照調(diào)用對象指定的格式返回一個 date 存儲的時刻對應(yīng)的字符串。這里定義格式 “年/月/日” 并存儲在 f 對象中。
指定格式的方法如下表所示:
| 格式 | 解釋 | 舉例 |
|---|---|---|
| yyyy | 年 | 2022 |
| MM | 月 | 08 |
| dd | 日 | 15 |
| E | 周 | Mon |
| HH | 小時 | 18 |
| mm | 分鐘 | 19 |
| ss | 秒 | 55 |
格式還有很多,比如說 M MM MMM 甚至分別表示 8 08 Aug, 所以很靈活。你甚至可以模仿默認格式……
public static void main(String[] args) {
Date date = new Date();
System.out.println(date.toString()); // Mon Aug 15 18:19:55 CST 2022
SimpleDateFormat f2 = new SimpleDateFormat("E MMM d HH:mm:ss zz yyyy", Locale.ENGLISH);
System.out.println(f2.format(date)); // Mon Aug 15 18:19:55 CST 2022
}不過常用的就是上表的那些。
String → Date
若要解析 String → Date, 同樣可以借助 SimpleDateFormat, 用另一個方法:parse().
public static void main(String[] args) {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(f.parse("2022-08-15").toString());
}public Date parse(String source) 方法按照調(diào)用者指定的格式返回一個與字符串參數(shù)對應(yīng)時刻相同的 Date 類型的對象。
但要注意上面這樣是會報錯的,因為假設(shè)你將來沒有按照 2022-08-15 輸入,Java 應(yīng)拋出異常,用 try/catch 包圍代碼吧。
public static void main(String[] args) {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
try {
System.out.println(f.parse("2022-08-15").toString()); // Mon Aug 15 00:00:00 CST 2022
} catch (ParseException e) {
throw new RuntimeException(e);
}
}因為沒有指定時分秒,就按全為 0 輸出了。這不重要,重要的是我們確實成功得到了一個 Date 類型對象。
如果格式不匹配會怎樣呢?如圖,拋出了 java.text.ParseException 異常。
public static void main(String[] args) {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
try {
System.out.println(f.parse("20220815").toString());
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
到此為止就實現(xiàn)了任意格式字符串與 Date 的互轉(zhuǎn)。
Date ↔ Calendar
得到一個 Date 對象后,如何對其進行加減?這需要抽象類 Calendar 的幫助。其實 Calendar 能在許多場景替換 Date, 不過似乎卻不能不借助 Date 和 SimpleDateFormat 來與 String 轉(zhuǎn)換,所以先梳理了上文。
總之,Calendar 也可以表示一個瞬時時刻,不過不能像 Date 那樣直接輸出,需要先借助 getTime() 轉(zhuǎn)換為 Date.
public static void main(String[] args) {
Date date = new Date();
System.out.println(date.toString()); // Mon Aug 15 18:19:55 CST 2022
Calendar badExample = Calendar.getInstance();
System.out.println(badExample.toString()); // java.util.GregorianCalendar[time=....非常長,后面省略
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getTime().toString()); // Mon Aug 15 18:19:55 CST 2022
}因為是抽象類,所以借助 public static Calendar getInstance() 方法得到一個表示當(dāng)前時刻的 Calendar 對象。
public final Date getTime() 方法可以直接返回一個表示此調(diào)用者存儲的時間值的 Date 對象。相似的,public final void setTime(Date date) 同理。沒錯,Date 和 Calendar 類互轉(zhuǎn)非常簡單。
并且 Calendar 類是比較強大的,借助 public int get(int field) 方法可以返回指定時間字段的值,public void set(int field, int value) 方法可以設(shè)置指定時間字段的值。時間字段代表是年,還是月,還是日,使用 Calendar 的靜態(tài)成員變量即可。
舉例:
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR); // 2022
int month = calendar.get(Calendar.MONTH); // 7
int day = calendar.get(Calendar.DAY_OF_MONTH); // 15
calendar.set(Calendar.YEAR, 2333); // 年份從 2022 變?yōu)?2333
}注意:month ∈ [0, 11], 比人類習(xí)慣的 [1, 12] 少 1.
加減日期
截止目前已經(jīng)完成了 String Date Calendar 互轉(zhuǎn)了。(Calendar 到 String 恐怕只能通過 Date 中轉(zhuǎn)一下,我沒有發(fā)現(xiàn)任何無需借助 Date 的方法)
接下來該實現(xiàn)按格式輸入字符串日期,任意加減天數(shù)的需求了,用到 Calendar 的成員方法:public abstract void add(int field, int amount).
它能在 field 代表的時間字段上加 amount 個單位(可以為負數(shù))。字段同樣使用 Calendar 的靜態(tài)成員變量。結(jié)合例子很容易理解:
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getTime().toString()); // Mon Aug 15 18:19:55 CST 2022
calendar.add(Calendar.YEAR, 2); // Mon Aug 15 18:19:55 CST 2024
calendar.add(Calendar.MONTH, -6); // Thu Feb 15 18:19:55 CST 2024
calendar.add(Calendar.DAY_OF_MONTH, 14); // Thu Feb 29 18:19:55 CST 2024
System.out.println(calendar.getTime().toString()); // Thu Feb 29 18:19:55 CST 2024
}最后,把上面的內(nèi)容連起來,筆者終于完成了:按指定格式 “yyyyMMdd” 傳入字符串與加減天數(shù),返回同樣格式字符串的方法:String addDay(String str, int num). 如下:
public class Main {
/**
* 對日期加減數(shù)天
*
* @param yyyyMMdd 形如 "20240228"
* @param day 形如 2(支持負數(shù))
* @return 形如 "20240301"
*/
public static String addDay(String yyyyMMdd, int day) {
// String to Date
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
Date date;
try {
date = format.parse(yyyyMMdd);
} catch (ParseException e) {
throw new RuntimeException(e);
}
// Change Date
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, day);
date = calendar.getTime();
// Date to String
yyyyMMdd = format.format(date);
return yyyyMMdd;
}
public static void main(String[] args) {
System.out.println(addDay("20240228", 2)); // 20240301
}
}即使天數(shù)很多也沒問題:
System.out.println(addDay("20240228", 2333)); // 20300719也可以完全同理實現(xiàn)加減年/月/時/分/秒,等等,只需更改 field 為 Calendar.XXX 即可,不一而足。
總結(jié)
1、三者互轉(zhuǎn):

(SimpleDateFormat 對象和 Calendar 對象用 s c 簡寫)
2、實現(xiàn)日期字符串的加減:
String → Date → Calendar → Date → String.
核心是對 Calendar 對象使用 add() 方法。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring security實現(xiàn)記住我下次自動登錄功能過程詳解
這篇文章主要介紹了Spring security實現(xiàn)記住我下次自動登錄功能過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03
深入理解JavaWeb中過濾器與監(jiān)聽器的應(yīng)用
這篇文章主要介紹了JavaWeb中過濾器與監(jiān)聽器的應(yīng)用,過濾器能夠?qū)ζヅ涞恼埱蟮竭_目標(biāo)之前或返回響應(yīng)之后增加一些處理代碼,監(jiān)聽器是一個接口內(nèi)容由我們實現(xiàn),會在特定時間被調(diào)用,感興趣想要詳細了解可以參考下文2023-05-05
SpringCloud組件OpenFeign之?dāng)r截器解讀
這篇文章主要介紹了SpringCloud組件OpenFeign之?dāng)r截器用法。具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04
SpringBoot集成單點登錄CAS的方法實現(xiàn)
本文主要介紹了SpringBoot集成單點登錄CAS的方法實現(xiàn),包括CAS的基本概念、集成步驟、具體代碼示例等,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03
解決Spring Boot 多模塊注入訪問不到j(luò)ar包中的Bean問題
這篇文章主要介紹了解決Spring Boot 多模塊注入訪問不到j(luò)ar包中的Bean問題。具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
mybatis攔截器實現(xiàn)數(shù)據(jù)庫數(shù)據(jù)權(quán)限隔離方式
通過Mybatis攔截器,在執(zhí)行SQL前添加條件實現(xiàn)數(shù)據(jù)權(quán)限隔離,特別是對于存在用戶ID區(qū)分的表,攔截器會自動添加如user_id=#{userId}的條件,確保SQL在執(zhí)行時只能操作指定用戶的數(shù)據(jù),此方法主要應(yīng)用于Mybatis的四個階段2024-11-11

