一、前言
获取两个时间一前一后之间的跨度,相隔几年几月几日几时几分几秒,例如下:
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)模拟了时间行走或者倒走的过程,没有孤立时间跨度各个维度(年、月、日、时、分、秒)之间的关系;