蓝桥杯JAVA-8.日期时间处理详解

本文最后更新于:April 1, 2022 pm

积土成山,风雨兴焉;积水成渊,蛟龙生焉;积善成德,而神明自得,圣心备焉。故不积跬步,无以至千里,不积小流无以成江海。齐骥一跃,不能十步,驽马十驾,功不在舍。面对悬崖峭壁,一百年也看不出一条裂缝来,但用斧凿,能进一寸进一寸,能进一尺进一尺,不断积累,飞跃必来,突破随之。

目录

1.Date类

java.util 包提供了 Date 类来封装当前的日期和时间。 Date 类提供两个构造函数来实例化 Date 对象。

  1. 使用当前日期和时间来初始化对象。Date date = new Date();
1
2
3
4
//获取当前系统时间
Date date = new Date();
System.out.println(date;
System.out.println(date.toString());
  1. 接收一个参数,该参数是从 1970 年 1 月 1 日起的毫秒数。
1
2
3
Date date = new Date(10000000);
System.out.println(date); //Thu Jan 01 10:46:40 CST 1970
System.out.println(date.toString()); //Thu Jan 01 10:46:40 CST 1970

但需要注意时区的问题,我们是东8区,所以需要减去8个小时。或者设置时区:

1
2
3
4
5
long ms = nextLong();
Date date = new Date(ms);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("UTC")); //设置时区
System.out.println(sdf.format(date));

1.0 日期比较

Date 对象创建以后,可以调用下面的方法。

序号 方法和描述
1 boolean after(Date date) 若当调用此方法的Date对象在指定日期之后返回true,否则返回false。
2 boolean before(Date date) 若当调用此方法的Date对象在指定日期之前返回true,否则返回false。
3 Object clone( ) 返回此对象的副本。
4 int compareTo(Date date) 比较当调用此方法的Date对象和指定日期。两者相等时候返回0。调用对象在指定日期之前则返回负数。调用对象在指定日期之后则返回正数。
5 int compareTo(Object obj) 若obj是Date类型则操作等同于compareTo(Date) 。否则它抛出ClassCastException。
6 boolean equals(Object date) 当调用此方法的Date对象和指定日期相等时候返回true,否则返回false。
7 long getTime( ) 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
8 int hashCode( ) 返回此对象的哈希码值。
9 void setTime(long time) 用自1970年1月1日00:00:00 GMT以后time毫秒数设置时间和日期。
10 String toString( ) 把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。

Java使用以下三种方法来比较两个日期:

  • 使用 getTime() 方法获取两个日期(自1970年1月1日经历的毫秒数值),然后比较这两个值。
  • 使用方法 before(),after() 和 equals()。例如,一个月的12号比18号早,则 new Date(99, 2, 12).before(new Date (99, 2, 18)) 返回true。
  • 使用 compareTo() 方法,它是由 Comparable 接口定义的,Date 类实现了这个接口。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) throws Exception {
String s1 = "2021-7-24";
String s2 = "2021-7-23";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = sdf.parse(s1);
Date d2 = sdf.parse(s2);
if(d1.before(d2)){ //d1比d2早
System.out.println("s1比s2早");
}else if(d1.equals(d2)){
System.out.println("s1与s2一样");
}else if(d1.after(d2)){ //d1比d2晚
System.out.println("s1比s2晚");
}
}

1.1 日期和时间的格式化编码

使用 SimpleDateFormat 格式化日期。SimpleDateFormat 是一个以语言环境敏感的方式来格式化和分析日期的类。SimpleDateFormat 允许你选择任何用户自定义日期时间格式来运行。

1
2
3
Date date = new Date(120000000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(date));

自定义格式:

1
2
3
Date date = new Date(120000000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss");
System.out.println(sdf.format(date));

其中 yyyy 是完整的公元年,MM 是月份,dd 是日期,HH:mm:ss 是时、分、秒。

注意:有的格式大写,有的格式小写,例如 MM 是月份,mm 是分;HH 是 24 小时制,而 hh 是 12 小时制。

时间模式字符串用来指定时间格式。在此模式中,所有的 ASCII 字母被保留为模式字母,定义如下:

字母 描述 示例
G 纪元标记 AD
y 四位年份 2001
M 月份 July or 07
d 一个月的日期 10
h A.M./P.M. (1~12)格式小时 12
H 一天中的小时 (0~23) 22
m 分钟数 30
s 秒数 55
S 毫秒数 234
E 星期几 Tuesday
D 一年中的日子 360
F 一个月中第几周的周几 2 (second Wed. in July)
w 一年中第几周 40
W 一个月中第几周 1
a A.M./P.M. 标记 PM
k 一天中的小时(1~24) 24
K A.M./P.M. (0~11)格式小时 10
z 时区 Eastern Standard Time
文字定界符 Delimiter
单引号 `

示例:

1
2
3
4
5
6
7
8
9
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒SSS毫秒");
System.out.println(sdf.format(date));
SimpleDateFormat sdf2 = new SimpleDateFormat("E 一年中第w周的第D天 一个月中的第W周的周F 一天中的24制的第k小时(点)12制的第K小时(点)");
System.out.println(sdf2.format(date));

//输出
20211214145359997毫秒
星期二 一年中第51周的第348天 一个月中的第3周的周2 一天中的24制的第14小时(点)12制的第2小时(点)

1.3 System类中的currentTimeMillis()

返回一个long型的数值,这个数值是当下时间与1970年1月1日零时的时间差,以毫秒为单位。最简单的一个运用是可以计算一个程序的运行时间。

1
2
3
long start = System.currentTimeMillis();
long end = System.currentTimeMillis();
long t = end - start;

1.2 printf格式化日期

printf 方法可以很轻松地格式化时间和日期。使用两个字母格式,它以 %t 开头并且以下面表格中的一个字母结尾。

转 换 符 说 明 示 例
c 包括全部日期和时间信息 星期六 十月 27 14:21:20 CST 2007
F “年-月-日”格式 2007-10-27
D “月/日/年”格式 10/27/07
r “HH:MM:SS PM”格式(12时制) 02:25:51 下午
T “HH:MM:SS”格式(24时制) 14:28:16
R “HH:MM”格式(24时制) 14:28

示例:(%n表示换行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Date date = new Date();
//c的使用
System.out.printf("全部日期和时间信息:%tc%n",date);
//f的使用
System.out.printf("年-月-日格式:%tF%n",date);
//d的使用
System.out.printf("月/日/年格式:%tD%n",date);
//r的使用
System.out.printf("HH:MM:SS PM格式(12时制):%tr%n",date);
//t的使用
System.out.printf("HH:MM:SS格式(24时制):%tT%n",date);
//R的使用
System.out.printf("HH:MM格式(24时制):%tR",date);

//输出
全部日期和时间信息:星期二 十二月 14 14:59:05 CST 2021
年-月-日格式:2021-12-14
月/日/年格式:12/14/21
HH:MM:SS PM格式(12时制):02:59:05 下午
HH:MM:SS格式(24时制):14:59:05
HH:MM格式(24时制):14:59

1.4 字符串转换为时间

SimpleDateFormat 类有一些附加的方法,特别是parse(),它试图按照给定的SimpleDateFormat 对象的格式化存储来解析字符串。format()将Date对象格式化为字符串(1.1中可见)。

示例:

1
2
3
4
5
6
7
8
String tm = "2021年7月13日";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");//用来解析字符串
Date date = sdf.parse(tm);
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy/MM/dd"); //按照格式输出时间字符串
System.out.printf(sdf2.format(date));

//输出
2021/07/13

2.Calendar类(📅日历类)

Calendar类是一个抽象类,可以方便的设置(加减)和获取日期数据的特定部分。它还有个已知的子类GregorianCalendar。

Calender的月份MONTH是从0开始,也就是1-12月对应 0-11,但日期和年份是从1开始的。DAY_OF_WEEK从1开始,也就是周日到周六对应 1-7。

2.1 创建Calendar对象

当前日期的Calendar对象:

1
Calendar c = Calendar.getInstance();//默认是当前日期,创建一个代表系统当前日期的Calendar对象

指定日期的Calendar对象。使用Calendar类代表特定的时间,需要首先创建一个Calendar的对象,然后再设定该对象中的年月日参数来完成。

1
2
3
//创建一个代表2021年7月13日的Calendar对象
Calendar c1 = Calendar.getInstance();
c1.set(2021, 7 - 1, 13);

2.2 Calendar类对象字段类型

Calendar类中用以下这些常量表示不同的意义,jdk内的很多类其实都是采用的这种思想。

常量 描述
Calendar.YEAR 年份
Calendar.MONTH 月份
Calendar.DATE 日期
Calendar.DAY_OF_MONTH 日期,和上面的字段意义完全相同
Calendar.HOUR 12小时制的小时
Calendar.HOUR_OF_DAY 24小时制的小时
Calendar.MINUTE 分钟
Calendar.SECOND
Calendar.DAY_OF_WEEK 星期几

2.3 Calendar类对象信息的设置

1
Calendar c1 = Calendar.getInstance();

1.设值(Set)

  1. public final void set(int year,int month,int date)
1
c1.set(2021, 7, 13);//把Calendar对象c1的年月日分别设这为:2021、7、13
  1. 利用字段类型设置,只设定某个字段。public void set(int field,int value)

把 c1对象代表的日期设置为10号,其它所有的数值会被重新计算:

1
c1.set(Calendar.DATE,10);

把c1对象代表的年份设置为2008年,其他的所有数值会被重新计算:

1
c1.set(Calendar.YEAR,2008);

其他字段属性set的用法以此类推。

2.设值(Add)

1
Calendar c1 = Calendar.getInstance();

把c1对象的日期加上10,也就是c1也就表示为10天后的日期,其它所有的数值会被重新计算:

1
c1.add(Calendar.DATE, 10);

其他字段属性的add的意义以此类推。

3.取值(get)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Calendar c1 = Calendar.getInstance();
// 获得年份
int year = c1.get(Calendar.YEAR);
// 获得月份
int month = c1.get(Calendar.MONTH) + 1; //因为是从0开始的,所以要加1
// 获得日期
int date = c1.get(Calendar.DATE);
// 获得小时
int hour = c1.get(Calendar.HOUR_OF_DAY);
// 获得分钟
int minute = c1.get(Calendar.MINUTE);
// 获得秒
int second = c1.get(Calendar.SECOND);
// 获得星期几(注意(这个与Date类是不同的):1代表星期日、2代表星期1、3代表星期二,以此类推)
int day = c1.get(Calendar.DAY_OF_WEEK);

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    public static void main(String[] args) throws Exception {

Calendar c1 = Calendar.getInstance();
c1.set(2021,7,13,13,14,23);
c1.set(Calendar.DAY_OF_WEEK,1); //1表示星期天,2表示星期1,....

int year = c1.get(Calendar.YEAR);
int month = c1.get(Calendar.MONTH) + 1;
int date = c1.get(Calendar.DATE);
int hour = c1.get(Calendar.HOUR_OF_DAY);
int minute = c1.get(Calendar.MINUTE);
int second = c1.get(Calendar.SECOND);
int day = c1.get(Calendar.DAY_OF_WEEK);
System.out.println(year+"年"+month+"月"+date+"日 "+"星期"+day+" "+hour+"点"+minute+"分"+second+"秒");
}

//输出
2021815日 星期1 131423

2.4 GregorianCalendar类

Calendar类实现了公历日历,GregorianCalendar是Calendar类的一个具体实现。

Calendar 的getInstance()方法返回一个默认用当前的语言环境和时区初始化的GregorianCalendar对象。GregorianCalendar定义了两个字段:AD和BC。这是代表公历定义的两个时代。

  1. GregorianCalendar对象的几个构造方法:
序号 构造函数和说明
1 GregorianCalendar() 在具有默认语言环境的默认时区内使用当前时间构造一个默认的 GregorianCalendar。
2 GregorianCalendar(int year, int month, int date) 在具有默认语言环境的默认时区内构造一个带有给定日期设置的 GregorianCalendar
3 GregorianCalendar(int year, int month, int date, int hour, int minute) 为具有默认语言环境的默认时区构造一个具有给定日期和时间设置的 GregorianCalendar。
4 GregorianCalendar(int year, int month, int date, int hour, int minute, int second) 为具有默认语言环境的默认时区构造一个具有给定日期和时间设置的 GregorianCalendar。
5 GregorianCalendar(Locale aLocale) 在具有给定语言环境的默认时区内构造一个基于当前时间的 GregorianCalendar。
6 GregorianCalendar(TimeZone zone) 在具有默认语言环境的给定时区内构造一个基于当前时间的 GregorianCalendar。
7 GregorianCalendar(TimeZone zone, Locale aLocale) 在具有给定语言环境的给定时区内构造一个基于当前时间的 GregorianCalendar。
  1. GregorianCalendar 类提供的一些有用的方法列表:
序号 方法和说明
1 void add(int field, int amount) 根据日历规则,将指定的(有符号的)时间量添加到给定的日历字段中。
2 protected void computeFields() 转换UTC毫秒值为时间域值
3 protected void computeTime() 覆盖Calendar ,转换时间域值为UTC毫秒值
4 boolean equals(Object obj) 比较此 GregorianCalendar 与指定的 Object。
5 int get(int field) 获取指定字段的时间值
6 int getActualMaximum(int field) 返回当前日期,给定字段的最大值
7 int getActualMinimum(int field) 返回当前日期,给定字段的最小值
8 int getGreatestMinimum(int field) 返回此 GregorianCalendar 实例给定日历字段的最高的最小值。
9 Date getGregorianChange() 获得格里高利历的更改日期。
10 int getLeastMaximum(int field) 返回此 GregorianCalendar 实例给定日历字段的最低的最大值
11 int getMaximum(int field) 返回此 GregorianCalendar 实例的给定日历字段的最大值。
12 Date getTime() 获取日历当前时间。
13 long getTimeInMillis() 获取用长整型表示的日历的当前时间
14 TimeZone getTimeZone() 获取时区。
15 int getMinimum(int field) 返回给定字段的最小值。
16 int hashCode() 重写hashCode.
17 boolean isLeapYear(int year) 确定给定的年份是否为闰年。
18 void roll(int field, boolean up) 在给定的时间字段上添加或减去(上/下)单个时间单元,不更改更大的字段。
19 void set(int field, int value) 用给定的值设置时间字段。
20 void set(int year, int month, int date) 设置年、月、日的值。
21 void set(int year, int month, int date, int hour, int minute) 设置年、月、日、小时、分钟的值。
22 void set(int year, int month, int date, int hour, int minute, int second) 设置年、月、日、小时、分钟、秒的值。
23 void setGregorianChange(Date date) 设置 GregorianCalendar 的更改日期。
24 void setTime(Date date) 用给定的日期设置Calendar的当前时间。
25 void setTimeInMillis(long millis) 用给定的long型毫秒数设置Calendar的当前时间。
26 void setTimeZone(TimeZone value) 用给定时区值设置当前时区。
27 String toString() 返回代表日历的字符串。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public static void main(String[] args) {
String months[] = {
"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"};

int year;
// 初始化 Gregorian 日历
// 使用当前时间和日期
// 默认为本地时间和时区
GregorianCalendar gcalendar = new GregorianCalendar();
// 显示当前时间和日期的信息
System.out.print("Date: ");
System.out.print(months[gcalendar.get(Calendar.MONTH)]);
System.out.print(" " + gcalendar.get(Calendar.DATE) + " ");
System.out.println(year = gcalendar.get(Calendar.YEAR));
System.out.print("Time: ");
System.out.print(gcalendar.get(Calendar.HOUR) + ":");
System.out.print(gcalendar.get(Calendar.MINUTE) + ":");
System.out.println(gcalendar.get(Calendar.SECOND));

// 测试当前年份是否为闰年
if(gcalendar.isLeapYear(year)) {
System.out.println("当前年份是闰年");
}
else {
System.out.println("当前年份不是闰年");
}
}

//输出
Date: Dec 14 2021
Time: 3:51:32
当前年份不是闰年

2.5 日期的加减

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    public static void main(String[] args) {
Calendar c1 = Calendar.getInstance();
c1.set(2021, 1, 1);
System.out.println(c1.get(Calendar.YEAR)
+"-"+c1.get(Calendar.MONTH)
+"-"+c1.get(Calendar.DATE));
c1.set(2021, 1, 0);
System.out.println(c1.get(Calendar.YEAR)
+"-"+c1.get(Calendar.MONTH)
+"-"+c1.get(Calendar.DATE));
}

//输出
2021-1-1 //实际为2021-2-1
2021-0-31 //实际为2021-1-31

通过上面的代码可见,将日期设为0以后,月份变成了上个月,但月份可以为0。再如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    public static void main(String[] args) {
Calendar c1 = Calendar.getInstance();
c1.set(2021, 2, 1);
System.out.println(c1.get(Calendar.YEAR)
+"-"+c1.get(Calendar.MONTH)
+"-"+c1.get(Calendar.DATE));
c1.set(2021, 2, 0);
System.out.println(c1.get(Calendar.YEAR)
+"-"+c1.get(Calendar.MONTH)
+"-"+c1.get(Calendar.DATE));
}

//输出
2021-2-1 //实际为2021-3-1
2021-1-28 //实际为2021-2-28

可以看到上个月的最后一天是28号,所以Calendar.MONTH为1的时候实际上是2月。既然日期设为0表示上个月的最后一天,那是不是可以设为负数呢?答案是可以的。如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    public static void main(String[] args) {
Calendar c1 = Calendar.getInstance();
c1.set(2021, 2, 1);
System.out.println(c1.get(Calendar.YEAR)
+"-"+c1.get(Calendar.MONTH)
+"-"+c1.get(Calendar.DATE));
c1.set(2021, 2, -10);
System.out.println(c1.get(Calendar.YEAR)
+"-"+c1.get(Calendar.MONTH)
+"-"+c1.get(Calendar.DATE));
}

//输出
2021-2-1
2021-1-18

所以日期是可以自由加减的。当然了,月份也可以是负数,规则与日期一样,这里就不再写了,原理一样。

将年份设为非正数时,会自动变为绝对值+1。

问题:为什么当Calender的年份设置为非正数时,会自动变为绝对值+1?

说实话,我具体也不知道原因,我只能按照我自己的理解来记录一下这个原因,所以,这个只能是仅供参考理解。

我觉得原理可能是类似与一个对称轴,一个向右(正,从1开始),一个向左(负,从0开始)。如图。

反正我感觉是这样的,也是这样理解的。后面如果知道了原理,我再回来修改吧。

3.星期

通过算法公式来获取星期。

3.1 蔡勒公式

公式:

1582.10.4及之前: w = (y + y/4 + c/4 -2c + (13(m+1))/5 + d + 2) % 7;

1582.10.4之后 : w = (y + y/4 + c/4 - 2c + (26(m+1))/10 + d - 1) % 7;

1
2
3
4
5
6
7
8
9
10
11
12
public static int week(int y, int m, int d)   //1582.10.4之后星期的计算
{
if (m < 3) {
m += 12;
y--;
}
int c = y / 100;
y = y - c*100;
int w = (y + y/4 + c/4 - 2*c + (26*(m+1))/10 + d - 1) % 7;
w = (w + 7) % 7;
return w;
}

3.2 基姆拉尔森

公式:(d + 2m + 3(m + 1) / 5 + y + y / 4 - y / 100 + y / 400 + 1) % 7

1
2
3
4
5
int y,m,d; //2021/12/14
y = 2021;
m = 12;
d = 14;
System.out.println((d + 2*m + 3*(m + 1) / 5 + y + y / 4 - y / 100 + y / 400 + 1) % 7);

📢注意:

  • d 为日期,范围是1-31。
  • m 为月份,范围是3-14,当年的1,2月需处理为上一年的13,14月。
  • y为年份,当月份为1,2时,y需减一。
  • 结果为0-6,星期日用0表示,星期一为1,以此类推,星期六为6

示例:

  • 2020年1月1日 (1 + 2 x 13 + 3(13 + 1) / 5 + 2019 + 2019/4 - 2019/100 + 2019/400 + 1) % 7 = 3
  • 2020年3月1日(1 + 2 x 3 + 3(3 + 1) / 5 + 2020 + 2020/4 - 2020/100 + 2020/400 + 1) % 7 = 0
  • 2020年8月1日(1 + 2 x 8 + 3(8 + 1) / 5 + 2020 + 2020/4 - 2020/100 + 2020/400 + 1) % 7 = 6
  • 2021年1月1日(1 + 2 x 13 + 3(13 + 1) / 5 + 2021 + 2021/4 - 2021/100 + 2021/400 + 1) % 7 = 5

模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//y-年,m-月,d-日期
public static String CaculateWeekDay(int y,int m, int d)
{
if(m==1||m==2) {
m+=12;
y--;
}
int week=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7;
String weekstr="";
switch(week)
{
case 1: weekstr="星期一";
break;
case 2: weekstr="星期二";
break;
case 3: weekstr="星期三";
break;
case 4: weekstr="星期四";
break;
case 5: weekstr="星期五";
break;
case 6: weekstr="星期六";
break;
case 0: weekstr="星期日";
break;
}
return weekstr;
}

4.两个时间间隔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    public static void main(String[] args) throws Exception {
String startTime = "2013-7-13 13:14:23";
String endTime = "2021-7-13 13:14:24";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d1 = format.parse(startTime);
Date d2 = format.parse(endTime);
long diff = Math.abs(d1.getTime() - d2.getTime());
System.out.println("相差 " + diff + " 毫秒");
long diffSeconds = diff / 1000 / 60; //秒
long diffMinutes = diff / (60 * 1000) % 60; //分钟
long diffHours = diff / (60 * 60 * 1000) % 24; //小时
long diffDays = diff / (24 * 60 * 60 * 1000); //天
System.out.print("两个时间相差:");
System.out.print(diffDays + " 天, ");
System.out.print(diffHours + " 小时, ");
System.out.print(diffMinutes + " 分钟, ");
System.out.println(diffSeconds + " 秒.");
System.out.println("相差 " + diffDays / 365 + " 年");
closeAll();
}

//输出
相差 252460801000 毫秒
两个时间相差:2922 天, 0 小时, 0 分钟, 1 秒.
相差 8

5.常用模板

5.1 求两个时间的间隔

返回毫秒值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static long getStartToEndTime(String start,String end) throws Exception{
String startTime = start;
String endTime = end;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //时间格式根据需要变动
Date d1 = format.parse(startTime);
Date d2 = format.parse(endTime);
long diff = Math.abs(d1.getTime() - d2.getTime());

System.out.println("相差 " + diff + " 毫秒");
long diffSeconds = diff / 1000 % 60; //秒
long diffMinutes = diff / (60 * 1000) % 60; //分钟
long diffHours = diff / (60 * 60 * 1000) % 24; //小时
long diffDays = diff / (24 * 60 * 60 * 1000); //天
System.out.print("两个时间相差:");
System.out.print(diffDays + " 天, ");
System.out.print(diffHours + " 小时, ");
System.out.print(diffMinutes + " 分钟, ");
System.out.println(diffSeconds + " 秒.");
System.out.println("相差 " + diffDays / 365 + " 年");
return diff;
}

5.2 求日期的天数、周数、星期数

1
2
3
4
5
6
7
8
9
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒SSS毫秒");
System.out.println(sdf.format(date));
SimpleDateFormat sdf2 = new SimpleDateFormat("E 一年中的第w周、第D天 一个月中的第W周的周F 一天中的24制的第k小时(点)12制的第K小时(点)");
System.out.println(sdf2.format(date));

//输出
20211214171542407毫秒
星期二 一年中的第51周、第348天 一个月中的第3周的周2 一天中的24制的第17小时(点)12制的第5小时(点)

📢注意:这里的第几周不能按平常的一周7天来算。是按照的日历中的一行来算的。如下