一、前言
獲取兩個時間一前一后之間的跨度,相隔幾年幾月幾日幾時幾分幾秒,例如下:
2022-04-20 13:58:30 至 2022-04-20 14:00:05 :1分35秒
2022-02-20 12:58:30 至 2022-03-05 14:00:05 :13日1時1分35秒
2021-02-20 12:58:30 至 2022-03-05 14:00:05 :1年0月13日1時1分35秒
二、實現
1,秒
情況1,startTime的秒數 < endTime的秒數,則相隔的秒數為:endTime的秒數 - startTime的秒數,如:
2022-03-05 14:00:05 至 2022-04-20 13:58:30 --> 30-05=25;
情況2,startTime的秒數 >= endTime的秒數,則相隔的秒數為:endTime的秒數 + (借分鍾)60秒 - startTime的秒數,如:
2022-03-05 14:00:30 至 2022-04-20 13:58:05 -->
2022-03-05 14:00:30 至 2022-04-20 13:57:65 -->
回到情況1 --> 65-30=35;


java代碼使用Calendar很方便,可以獲取時間的秒數,如:
2022-03-05 14:00:30的秒數是30,
2022-04-20 13:58:05的秒數是5;
也可以很方便的獲得時間少了一分鍾的時間,如:
2022-04-20 13:58:05少了一分鍾是2022-04-20 13:57:05,
2022-04-20 13:00:05少了一分鍾是2022-04-20 12:59:05,更極端的
2022-01-01 00:00:05少了一分鍾是2021-12-31 23:59:05,如下圖:

2,分、時、日、月
分、時、日、月和秒的計算方式相同道理。
相隔多少分鍾,如:
2022-04-20 13:57:xx 至 2022-04-20 15:50:xx -->
2022-04-20 13:57:xx 至 2022-04-20 14:110:xx -->
相隔 50 + 借(1個小時=60分鍾)- 57 = 53 分鍾;
時、日、月同理,如下圖:

三、代碼
import java.util.Calendar; import java.util.Date; public static String formatDuration(Date startTime, Date endTime) { if (null == startTime || null == endTime || startTime.after(endTime)) { return null; } Calendar startCalendar = Calendar.getInstance(); startCalendar.setTime(startTime); Calendar endCalendar = Calendar.getInstance(); endCalendar.setTime(endTime); int secondDiff = endCalendar.get(Calendar.SECOND) - startCalendar.get(Calendar.SECOND); if (secondDiff < 0) { endCalendar.add(Calendar.MINUTE, -1); secondDiff = secondDiff + 60; } int minuteDiff = endCalendar.get(Calendar.MINUTE) - startCalendar.get(Calendar.MINUTE); if (minuteDiff < 0) { endCalendar.add(Calendar.HOUR_OF_DAY, -1); minuteDiff = minuteDiff + 60; } int hourDiff = endCalendar.get(Calendar.HOUR_OF_DAY) - startCalendar.get(Calendar.HOUR_OF_DAY); if (hourDiff < 0) { endCalendar.add(Calendar.DAY_OF_MONTH, -1); hourDiff = hourDiff + 24; } int dayDiff = endCalendar.get(Calendar.DAY_OF_MONTH) - startCalendar.get(Calendar.DAY_OF_MONTH); if (dayDiff < 0) { endCalendar.add(Calendar.MONTH, -1); dayDiff = dayDiff + endCalendar.getActualMaximum(Calendar.DAY_OF_MONTH); } int monthDiff = endCalendar.get(Calendar.MONTH) - startCalendar.get(Calendar.MONTH); if (monthDiff < 0) { endCalendar.add(Calendar.YEAR, -1); monthDiff = monthDiff + 12; } int yearDiff = endCalendar.get(Calendar.YEAR) - startCalendar.get(Calendar.YEAR); int[] values = new int[]{yearDiff, monthDiff, dayDiff, hourDiff, minuteDiff, secondDiff}; String[] labels = new String[]{"年", "月", "日", "時", "分", "秒"}; // 標識是否停止檢測0
boolean isStopCheckZero = false; StringBuilder builder = new StringBuilder(); for (int i = 0; i < values.length; i++) { if (!isStopCheckZero && 0 == values[i]) { continue; } isStopCheckZero = true; builder.append(values[i]).append(labels[i]); } return builder.toString(); }
四、總結
獲取兩個時間一前一后之間的跨度,相隔幾年幾月幾日幾時幾分幾秒,和進位制差不多,和鬧鍾差不多;
秒針還沒走到無限接近正上方刻度的時候,分針不會動;
秒針剛走到正上方刻度的時候,分鍾向前走一步,秒針則歸零。
兩個時間的跨度,就像兩個鬧鍾分別對應兩個時間,落后的鬧鍾開始走,另外的鬧鍾不動,一直走到另一個鬧鍾的那個時刻,這之間走了多少年多少月多少日多少時多少分多少秒。過程如下:
將落后的鬧鍾的秒針撥回到正上方刻度,撥了多少秒,則另外一個鬧鍾也撥回多少秒,另外一個鬧鍾得有倒着走的機制才行(鬧鍾能正着走,我想稍微改造一下,倒着走應該也不難);
然后讓落后的鬧鍾開始正着走:
秒針還沒走到無限接近正上方刻度的時候,分針不會動,記比如59秒;秒針剛走到60秒的時候,分鍾向前走一步,秒針則歸零,記1分鍾;秒針再走30秒,記1分30秒;
分針還沒走到無限接近60分鍾的時候,時針不會動,記比如59分;分針剛走到60分鍾的時候,時鍾向前走一步,分針則歸零,記1小時;分針再走30分鍾,記1小時30分鍾;
時針還沒走到無限接近24小時的時候,天不會動,記比如23小時;時針剛走到24小時的時候,天向前走一步,時針則歸零,記1天;時針再走5小時,記1天5小時;
天還沒走到無限接近當前月的天數(比如1月31天,閏年2月29天,非閏年2月28天)的時候,月不會動,記比如30天;天剛走到31天的時候,月向前走一步,天則歸零,記1月;天再走5天,記1個月零5天;
月還沒走到無限接近12個月的時候,年不會動,記比如11月;月剛走到12個月的時候,年向前走一步,月則歸零,記1年;月再走5個月,記1年零5個月;
60是秒的模;
60是分鍾的模;
24是小時的模;
當前月的天數是天的模;
12是月的模;
年沒有模,無窮無盡了,年年歲歲花相似,歲歲年年人不同。
五、補充
1,簡要說明目的及基本方案一種基於java技術實現倒計時的方法,指定兩個時間點,計算出時間間隔。比如,當前時刻2022-08-11 10:26:30,未來時刻2099-12-31 23:59:59,則倒計時時間為:77年4月20日13時33分29秒。該方法統一處理了月份有28天、29天、30天、31天的情況,以及未來時間點的秒針、分針、時針、日、月比當前時間點的秒針、分針、時針、日、月小的情況,模擬了未來時刻倒計時到當前時刻的完整過程。
2,相關術語解釋
時刻:時間點;
時間:時間段、時間跨度;
Calendar:java jdk自帶的一個日歷工具類,可以將時刻拆成年、月、周、日、時、分、秒等維度。
3,詳細介紹背景知識
生活中人們很多事情是按照計划行事的,比如6點起床、9點上班、18點下班、23點睡覺,計划中很重要的一個元素就是時刻。如果計划是需要准備的,那么當事人不僅需要知道計划的時刻,還需要知道截止到該時刻的時間跨度。
4,數學減法的借位法
本方法完全參考數學減法的借位法,如下圖:

5,技術方案的詳細闡述
本方法模擬了未來時刻倒走到當前時刻的過程。
秒針倒走:
| 當前時刻 |
|
|||||
| 年 |
月 |
日 |
時 |
分 |
秒 |
|
| x |
x |
x |
x |
x |
30 |
|
| 未來時刻 |
|
|||||
| 年 |
月 |
日 |
時 |
分 |
秒 |
|
| x |
x |
x |
x |
x |
45 |
情況1,秒值大於等於 |
| x |
x |
x |
x |
40 |
15 |
情況2,秒值小於 |
當前時刻的秒值和未來時刻的秒值存在兩種關系:
情況1:未來時刻的秒值大於等於當前時刻的秒值,則倒走的秒值為未來時刻的秒值減去當前時刻的秒值;比如上圖,當前時刻的秒值為30,未來時刻的秒值為45,則倒走的秒值為45減去30等於15秒;
情況2:未來時刻的秒值小於當前時刻的秒值,則未來時刻的秒值需要先向分值借1分鍾(60秒),則倒走的秒值為未來時刻的秒值先加上60(秒)再減去當前時刻的秒值;比如上圖,當前時刻的秒值為30,未來時刻的秒值為15,則倒走的秒值為15加上60減去30等於45秒;需要注意的是,這種情況下,分值需要減去1,比如上圖分值原先為40,處理秒值后變為40減去1等於39;不用擔心分值為0(借位或者連續借位)的情況,通過Calendar函數可以獲取時刻減去1分鍾的時刻值;
分針倒走:
| 當前時刻 |
|
|||||
| 年 |
月 |
日 |
時 |
分 |
秒 |
|
| x |
x |
x |
x |
30 |
x |
|
| 未來時刻 |
|
|||||
| 年 |
月 |
日 |
時 |
分 |
秒 |
|
| x |
x |
x |
x |
45 |
x |
情況1,分值大於等於 |
| x |
x |
x |
18 |
15 |
x |
情況2,分值小於 |
當前時刻的分值和未來時刻的分值存在兩種關系:
情況1:未來時刻的分值大於等於當前時刻的分值,則倒走的分值為未來時刻的分值減去當前時刻的分值;比如上圖,當前時刻的分值為30,未來時刻的分值為45,則倒走的分值為45減去30等於15分;
情況2:未來時刻的分值小於當前時刻的分值,則未來時刻的分值需要先向時值借1小時(60分鍾),則倒走的分值為未來時刻的分值先加上60(分鍾)再減去當前時刻的分值;比如上圖,當前時刻的分值為30,未來時刻的分值為15,則倒走的分值為15加上60減去30等於45分;需要注意的是,這種情況下,時值需要減去1,比如上圖時值原先為18,處理分值后變為18減去1等於17;不用擔心時值為0(借位或者連續借位)的情況,通過Calendar函數可以獲取時刻減去1小時的時刻值;
時針、日、月倒走的過程則與秒針、分針相同;
年值為以上秒、分、時、日、月都處理后,未來時刻的年值減去當前時刻的年值;
完整的流程如下圖:


6,構思的關鍵點
(1)將數學減法中的借位法應用到了計算機對時間跨度的計算中;
(2)模擬了時間行走或者倒走的過程,沒有孤立時間跨度各個維度(年、月、日、時、分、秒)之間的關系;
