嘘~ 小破站正在拼命加载中 . . .

Java日期时间的前世今生


前言

日常开发中,日期和时间是我们经常遇到并且需要处理的。由于日期时间的复杂性,随着Java的发展,也诞生了三代日期处理API。接下来就让我们一起来探究下Java日期时间的前世今生。

一、基本概念

1.1 日期与时间

日期是指某一天,它不是连续变化的;而时间分为带日期的时间和不带日期的时间
带日期的时间能唯一确定某个时刻,不带日期的时间是无法确定一个唯一时刻的

日期如下

  • 2022-05-20
  • 1992-09-13

时间如下

  • 2022-11-20 08:01:59
  • 08:01:59

1.2 本地时间

当前时刻是2022年11月20日早上8:08,我们实际上说的是本地时间,也就是北京时间。
在这里插入图片描述
有点常识的我们都知道,如果这一个时间点,地球是不同地区的小伙伴看手表,看到的本地时间是不同的。
在这里插入图片描述
不同的时区,在同一时刻,本地时间是不同的。

1.3 时区

由于本地时间没法确定一个准确时刻,所以时区的概念就出现了
全球一共分为24个时区伦敦所在的时区称为标准时区
其他时区按东/西偏移的小时区分,北京所在的时区是东八区

时区的三种表示方式

  • 以GMT或者UTC加时区偏移表示

    GMT是前世界标准时,UTC是现世界标准时,UTC 比 GMT更精准,以原子时计时,每隔几年会有一个闰秒,我们在开发程序的时候可以忽略两者的误差

例如:GMT+08:00或者UTC+08:00 表示东八区 UTC/GMT +9:00 表示东九区

  • 以缩写表示
    例如:CST表示China Standard Time,也就是中国标准时间
  • 以洲/城市表示
    例如:Asia/Shanghai,表示上海所在地的时区。城市名称不是任意的城市,而是由国际标准组织规定的城市。

这里好学的小伙伴就会问了,中国的时区为什么是Asia/Shanghai,而不是Asia/Beijing 呢?
北京和上海处于同一时区(东八区),只能保留一个。而作为时区代表上海已经足够具有代表性。
东八区

注:虽然身处不同时区的两个小伙伴,同一时刻表上显示的本地时间不同,但两个表示的时刻是相同的

1.4 夏令时

是夏天开始的时候,把时间往后拨1小时,夏天结束的时候,再把时间往前拨1小时

夏令时是比时区更为复杂的计算方式,很多地区都是不执行夏令时的,我国也在1992年就废除了
在这里插入图片描述
在这里插入图片描述

二、Java三代日期时间API

  • 第一代日期时间类定义在java.util包下,主要包含DateSimpleDateFormat
  • 第二代日期时间类也是定义在java.util包下,主要是CalendarTimeZone
  • 第三代日期时间类是在Java 8引入的,定义在java.time 包下,主要包含LocalDateTimeZonedDateTimeZoneIdDateTimeFormatter

此时,小伙伴可能会问了

为什么会出现三代日期时间类呢?
答:历史遗留问题,早期的API存在着很多问题,所以java在不断迭代更新,引入了新的API。更加方便我们处理日期时间

既然早期API存在诸多问题,我们能不能直接使用最新API呢?

答:如果是新项目,就建议使用最新API。因为新的API中的类是不变对象,并且是线程安全的;
如果读者和我一样苦逼,还得维护JDK1.6 这样的遗留代码,就必须对一二代API有所了解。

如果要维护历史遗留代码,新旧API可以相互转换吗?
答:当然了,新旧API之间也是可以相互转换的。

三、 第一代日期时间Date

3.1 继承关系

在这里插入图片描述

3.2 获取实例对象

在这里插入图片描述
从上图可以看出,已经弃用了好多。这里我们说一说常用的两种

  • Date()
    创建的对象可以获取本地当前时间,精确到毫秒
  • Date(long date)
    以从1970 年 1 月 1 日 0 时 0 分 0 秒 开始的毫秒数初始化时间对象
import java.util.Date;

public class DateTest {
    public static void main(String[] args) {
        Date date1 = new Date();
        System.out.println(date1);
        Date date2 = new Date(15000);
        System.out.println(date2);
      
    }
}
//输出
Sun Nov 20 09:55:58 CST 2022
Thu Jan 01 08:00:15 CST 1970

3.3 常用方法

在这里插入图片描述
我们发现好多也是已弃用了,这里面的很多方法将会被第二代日期时间中的方法取代

3.3 获取当前年月日时分秒

getYear()getMonth()date.getDate()getHours()getMinutes()getSeconds()
toString()toGMTString()toLocaleString()

注:

  • getYear()返回的年份必须加上1900
  • getMonth() 返回的月份是0-11 分别表示1-12月,所以要+1
  • getDate() 返回的日期范围是1~31,不能加1
import java.util.Date;

public class DateTest {
    public static void main(String[] args) {
        //获取当前时间
        Date date = new Date();
        //获取当前年份
        System.out.println((date.getYear() + 1900));
        //获取当前月份
        System.out.println((date.getMonth() + 1));
        //获取当前日
        System.out.println(date.getDate());
        //获取小时
        System.out.println(date.getHours());
        //获取分钟
        System.out.println(date.getMinutes());
        //获取秒
        System.out.println(date.getSeconds());
    }
}
//输出
2022
11
20
10
17
1

3.4 日期时间转换

toString()toGMTString()toLocaleString()

import java.util.Date;

public class DateTest {
    public static void main(String[] args) {
        //获取当前时间
        Date date = new Date();
        //转换为字符串
        System.out.println(date.toString());
        //转换为GMT时区
        System.out.println(date.toGMTString());
        //转换为本地时区
        System.out.println(date.toLocaleString());
    }
}
//输出
Sun Nov 20 10:19:25 CST 2022
20 Nov 2022 02:19:25 GMT
2022-11-20 10:19:25

3.5 日期时间格式化

格式化日期表示将日期/时间格式转换为预先定义的日期/时间格式;
例如将 Sun Nov 20 13:48:40 CST 2022 格式化为 2022-11-20 13:48:40

3.5.1 DateFormat 类 进行格式化

日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并解析日期或时间

在这里插入图片描述
创建 DateFormat 对象时不能使用 new 关键字,而应该使用 DateFormat 类中的静态方法 getDateInstance()

getDateInstance()的变种有以下形式
| 方法 | 描述 |
| ———————————————————— | ———————————————————— |
| static DateFormat getDateInstance() | 获取具有默认格式化风格和默认语言环境的日期格式 |
| static DateFormat getDateInstance(int style) | 获取具有指定格式化风格和默认语言环境的日期格式 |
| static DateFormat getDateInstance(int style, Locale locale) | 获取具有指定格式化风格和指定语言环境的日期格式 |
| static DateFormat getDateTimeInstance() | 获取具有默认格式化风格和默认语言环境的日期/时间 格式 |
| static DateFormat getDateTimeInstance(int dateStyle,int timeStyle) | 获取具有指定日期/时间格式化风格和默认语言环境的 日期/时间格式 |
| static DateFormat getDateTimeInstance(int dateStyle,int timeStyle,Locale locale) | 获取具有指定日期/时间格式化风格和指定语言环境的 日期/时间格式 |
| static DateFormat getTimeInstance() | 获取具有默认格式化风格和默认语言环境的时间格式 |
| static DateFormat getTimeInstance(int style) | 获取具有指定格式化风格和默认语言环境的时间格式 |
| static DateFormat getTimeInstance(int style, Locale locale) | 获取具有指定格式化风格和指定语言环境的时间格式 |

格式化样式主要通过 DateFormat 常量设置。将不同的常量传入getDateInstance()的方法中,以控制结果的长度。
DateFormat 类的常量有以下几种

  • SHORT:完全为数字,如 12.5.10 或 5:30pm。
  • MEDIUM:较长,如 May 10,2016。
  • LONG:更长,如 May 12,2016 或 11:15:32am。
  • FULL:是完全指定,如 Tuesday、May 10、2012 AD 或 11:l5:42am CST

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

public class DateTest {
    public static void main(String[] args) {
        Date date = new Date();
        // 获取不同格式化风格和中国环境的日期
        DateFormat df1 = DateFormat.getDateInstance(DateFormat.SHORT, Locale.CHINA);
        DateFormat df2 = DateFormat.getDateInstance(DateFormat.FULL, Locale.CHINA);
        DateFormat df3 = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.CHINA);
        DateFormat df4 = DateFormat.getDateInstance(DateFormat.LONG, Locale.CHINA);
       // 获取不同格式化风格和中国环境的时间
        DateFormat df5 = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.ENGLISH);
        DateFormat df6 = DateFormat.getTimeInstance(DateFormat.FULL, Locale.CHINA);
        DateFormat df7 = DateFormat.getTimeInstance(DateFormat.MEDIUM, Locale.CHINA);
        DateFormat df8 = DateFormat.getTimeInstance(DateFormat.LONG, Locale.CHINA);

        // 将不同格式化风格的日期格式化为日期字符串
        String date1 = df1.format(date);
        String date2 = df2.format(date);
        String date3 = df3.format(date);
        String date4 = df4.format(date);
       // 将不同格式化风格的时间格式化为时间字符串
        String time1 = df5.format(date);
        String time2 = df6.format(date);
        String time3 = df7.format(date);
        String time4 = df8.format(date);
        // 输出日期
        System.out.println("SHORT格式:" + date1 + " " + time1);
        System.out.println("FULL格式:" + date2 + " " + time2);
        System.out.println("MEDIUM格式:" + date3 + " " + time3);
        System.out.println("LONG格式:" + date4 + " " + time4);
    }
}
//输出
SHORT格式:22-11-20 2:24 PM
FULL格式:20221120日 星期日 下午022459秒 CST
MEDIUM格式:2022-11-20 14:24:59
LONG格式:20221120日 下午022459
3.5.2 SimpleDateFormat 类进行格式化

DateFormat 类的子类,具有更加强大的日期格式化功能;DateFormat 只能单独对日期或时间格式化,而 SimpleDateFormat 可以选择任何用户定义的日期/时间格式的模式
在这里插入图片描述
SimpleDateFormat 类主要有如下 3 种构造方法。

  • SimpleDateFormat():用默认的格式和默认的语言环境构造 SimpleDateFormat。
  • SimpleDateFormat(String pattern):用指定的格式和默认的语言环境构造 SimpleDateFormat。
  • SimpleDateFormat(String pattern,Locale locale):用指定的格式和指定的语言环境构造 SimpleDateF ormat。

在这里插入图片描述

字母 描述 示例
G 纪元标记 根据语言环境显示 Locale.CHINA 语言环境下,如:公元;Locale.US语言环境下,如:AD
y 年份。yy表示2位年份,yyyy表示4位年份 使用yy 表示年份,如22;使用yyyy表示年份,例如2022
M 月份 一般用 MM 表示月份,如果使用 MMM,则会根据语言环境显示不同语言的月份 使用 MM 表示的月份,如 11; 使用 MMM 表示月份,在 Locale.CHINA语言环境下,如“十月”;在 Locale.US环境下 如Nov
d 月份中的天数。一般用dd表示天数 使用dd表示天数 例如:20
h 一天中的小时(1~12)。 一般使用hh表示小时 如 10 (注意 10 有可能是 10 点,也可能是 22 点)
H 一天中的小时 (0~23)。 如:22
m 分钟数 。一般用mm表示分钟数 使用mm表示分钟数,如:59
s 秒数。一般使用ss表示秒数 使用ss表示秒数,如:55
S 毫秒数 。一般使用SSS 表示毫秒数 使用SSS表示毫秒数,如:234
E 星期几 。 会根据语言环境的不同,显示不同语言的星期几 Locale.CHINA 语言环境下,如:星期日;在 Locale.US 语言下,如:Sun
D 一年中的日子。 324 一年中的第324天
F 一个月中第几周。 3 表示一个月中的第三周
w 一年中第几周 。 48 表示一年中的第48周
W 一个月中第几周 1
a A.M./P.M. 或上午/下午标记。根据语言环境不同,显示不同 Locale.CHINA 语言环境下,如:下午 Locale.US语言环境下,如:PM
k 一天中的小时(1~24) 15 一天中的第15小时
K 一天中的小时(1~12) 3 下午3小时
z 时区 中国的东八区 如:+0800

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;


public class DateTest {
    public static void main(String[] args)  {
        SimpleDateFormat sdf1 = new SimpleDateFormat("今天是:"+"yyyy年MM月dd日 HH点mm分ss秒 SSS 毫秒 E ", Locale.CHINA);
        System.out.println(sdf1.format(new Date()));

        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss", Locale.CHINA);
        System.out.println(sdf2.format(new Date()));
    }
}
//输出
今天是:20221120152737091 毫秒 星期日 
2022-27-20 03:27:37

3.6 日期字符串互转

3.6.1 DateFormat 类实现
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //将日期转为字符串
        Date date1 = new Date();
        DateFormat df1 = DateFormat.getDateInstance(DateFormat.MEDIUM);
        String strdate = df1.format(date1);
        System.out.println(strdate);

        //将字符串转日期
        DateFormat df2 = DateFormat.getDateInstance(DateFormat.MEDIUM);
        Date date2 = df2.parse("1998-19-13");
        System.out.println(date2);

    }
}
//输出
2022-11-20
Tue Jul 13 00:00:00 CST 1999
3.6.2 SimpleDateFormat 类实现
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class DateTest {
    public static void main(String[] args) throws ParseException {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        //日期转字符串
        Date date1 = new Date();
        String strdate1 = sdf.format(date1);
        System.out.println(strdate1);

        //字符串转日期
        Date date2 = sdf.parse("1992-09-13 08:34:45");
        System.out.println(date2.toString());

    }
}
//输出
2022-11-20 03:32:21
Sun Sep 13 08:34:45 CST 1992

3.7 日期时间比较

boolean before(Date when)boolean after(Date when)boolean equals(Object obj)int compareTo(Date anotherDate)


public class DateTest {
    public static void main(String[] args) throws ParseException {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        Date date1 = sdf.parse("1992-10-08 11:23:59");
        Date date2 = sdf.parse("1992-09-13 08:34:45");
        Date date3 = sdf.parse("1992-09-13 08:34:45");

        System.out.println("date1:" + sdf.format(date1));
        System.out.println("date2:" + sdf.format(date2));
        System.out.println("date3:" + sdf.format(date3));
        System.out.println("********************************************************************");
        //compareTo方法比较
        System.out.println("compareTo方法比较结果1:"+date1.compareTo(date2));
        System.out.println("compareTo方法比较结果2:"+date2.compareTo(date3));
        System.out.println("compareTo方法比较结果2:"+date2.compareTo(date1));
        System.out.println("-------------------------------------------------------------------");
        //equals方法比较
        System.out.println("equals方法比较结果1:"+date1.equals(date2));
        System.out.println("equals方法比较结果2:"+date2.equals(date3));
        System.out.println("equals方法比较结果2:"+date2.equals(date1));
        System.out.println("-------------------------------------------------------------------");
        //before方法比较
        System.out.println("before方法比较结果1:"+date1.before(date2));
        System.out.println("before方法比较结果2:"+date2.before(date3));
        System.out.println("before方法比较结果2:"+date2.before(date1));
        System.out.println("-------------------------------------------------------------------");
        //after方法比较
        System.out.println("after方法比较结果1:"+date1.after(date2));
        System.out.println("after方法比较结果2:"+date2.after(date3));
        System.out.println("after方法比较结果2:"+date2.after(date1));
    }
}
//输出
date1:1992-10-08 11:23:59
date2:1992-09-13 08:34:45
date3:1992-09-13 08:34:45
********************************************************************
compareTo方法比较结果1:1
compareTo方法比较结果2:0
compareTo方法比较结果2:-1
-------------------------------------------------------------------
equals方法比较结果1:false
equals方法比较结果2:true
equals方法比较结果2:false
-------------------------------------------------------------------
before方法比较结果1:false
before方法比较结果2:false
before方法比较结果2:true
-------------------------------------------------------------------
after方法比较结果1:true
after方法比较结果2:false
after方法比较结果2:false

四、 第二代日期时间类

由于第一代日期时间类Date 存在几个严重问题:

  • 不能转换时区。除了toGMTString()可以按GMT+0:00输出外,
  • Date总是以当前计算机系统的默认时区为基础进行输出。
  • 我们也很难对日期和时间进行加减,计算两个日期相差多少天,计算某个月第一个星期一的日期等。

由于以上诸多问题,第二代日期时间类Calendar 便来了。上一小节中我们发现Date 类下的很多方法都废弃了,当然了在Calendar 中有新的方法可以取代

4.1 继承关系

在这里插入图片描述

在这里插入图片描述

4.2 获取实例对象

因为 Calendar 类是一个抽象类,创建 Calendar 对象不能使用 new 关键字,但是它提供了一个 getInstance() 方法来获得 Calendar类的对象

//默认是当前日期
Calendar c = Calendar.getInstance();  

4.3 TimeZone 时区

CalendarDate相比,提供了时区类TimeZone

import java.text.ParseException;
import java.util.TimeZone;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        // 当前时区
        TimeZone tzDefault = TimeZone.getDefault();
        System.out.println("当前时区:" + tzDefault.getID());

        //获取纽约时区
        TimeZone tzNY = TimeZone.getTimeZone("America/New_York");
        System.out.println("纽约时区:" + tzNY.getID());
    }
}
//输出
当前时区:Asia/Shanghai
纽约时区:America/New_York
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        // 当前时间:
        Calendar c = Calendar.getInstance();
        // 设置为纽约时区:
        c.setTimeZone(TimeZone.getTimeZone("America/New_York"));
        // 格式化显示时间:
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf1.setTimeZone(TimeZone.getTimeZone("America/New_York"));
        System.out.println("纽约时间:"+sdf1.format(c.getTime()));
        
        // 设置为北京时区:
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        // 格式化显示时间:
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf2.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        System.out.println("北京时间:"+sdf2.format(c.getTime()));
    }
}
//输出
纽约时间:2022-11-22 18:49:08
北京时间:2022-11-23 07:49:08

4.4 常用时间点的获取

注:

  • 与中国人习惯不同,一年中1月的值为0。
  • 与中国人的习惯不同, 一周中的第一天为 周日. 一周的顺序依次为: 周日(1), 周一(2), 周二(3), 周三(4), 周四(5), 周五(6), 周六(7)

Calendar类中各个常量含义
|常量|含义|
|–|–|
|Calendar.YEAR|年份|
|Calendar.MONTH |月份|
|Calendar.DAY_OF_MONTH|日期|
|Calendar.DATE |日期,和上面的字段意义完全相同|
|Calendar.HOUR |12小时制的小时|
|Calendar.HOUR_OF_DAY |24小时制的小时|
|Calendar.MINUTE |分钟|
|Calendar.SECOND|秒|
|Calendar.MILLISECOND|毫秒|
|Calendar.DAY_OF_WEEK|星期几 周日(1), 周一(2), 周二(3), 周三(4), 周四(5), 周五(6), 周六(7) |
|Calendar.WEEK_OF_YEAR| 一年中第几周|
|Calendar.WEEK_OF_MONTH|一月中第几周|

//获取时间点
import java.text.ParseException;
import java.util.Calendar;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //获取当前时间
        Calendar c = Calendar.getInstance();
        //获取年份
        System.out.println("获取年份:"+c.get(Calendar.YEAR));
        //获取月份
        System.out.println("获取月份:"+(c.get(Calendar.MONTH) + 1));
        //获取一月中的天
        System.out.println("获取一月中的天:"+c.get(Calendar.DAY_OF_MONTH));
        System.out.println("获取一月中的天:"+c.get(Calendar.DATE));
        //获取一天中的小时 24小时制
        System.out.println("获取一天中的小时(24小时制):"+c.get(Calendar.HOUR_OF_DAY));
        //获取一天中的小时 12小时制
        System.out.println("获取一天中的小时(12小时制):"+c.get(Calendar.HOUR));
        //获取分钟
        System.out.println("获取分钟:"+c.get(Calendar.MINUTE));
        //获取秒
        System.out.println("获取秒:" + c.get(Calendar.SECOND));
        //获取毫秒
        System.out.println("获取毫秒:" + c.get(Calendar.MILLISECOND));
        //获取一周中星期几
        System.out.println("获取一周中星期几:"+ c.get(Calendar.DAY_OF_WEEK));
        //获取一年中星期几
        System.out.println("获取一年中第几周:"+c.get(Calendar.WEEK_OF_YEAR));
        //获取一月中第几周
        System.out.println("获取一月中第几周:"+c.get(Calendar.WEEK_OF_MONTH));

        System.out.println("当前时间:"+(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-"+ c.get(Calendar.DAY_OF_MONTH) +
                " "+ c.get(Calendar.HOUR_OF_DAY) + ':' + c.get(Calendar.MINUTE) + ':' + c.get(Calendar.SECOND) +
                ':' + c.get(Calendar.MILLISECOND) ));
    }
}
//输出
获取年份:2022
获取月份:11
获取一月中的天:20
获取一月中的天:20
获取一天中的小时(24小时制):16
获取一天中的小时(12小时制):4
获取分钟:39
获取秒:37
获取毫秒:238
获取一周中星期几:1
获取一年中第几周:48
获取一月中第几周:4
当前时间:2022-11-20 16:39:37:238

4.5 常用时间点设置

注:在使用set方法之前,必须先clear一下,否则很多信息会继承自系统当前时间

4.5.1 分别对年、月、日、时、分、秒每个值进行设置
//设置时间点 
import java.text.ParseException;
import java.util.Calendar;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //初始化Calendar类
        Calendar c = Calendar.getInstance();
        //将时间设置成1992-09-13 23:35:59:123
        c.clear();  //先clear一下,否则很多信息会继承自系统当前时间
        c.set(Calendar.YEAR,1992);
        c.set(Calendar.MONTH,9);
        c.set(Calendar.DAY_OF_MONTH,13);
        c.set(Calendar.HOUR_OF_DAY,23);
        c.set(Calendar.MINUTE,35);
        c.set(Calendar.SECOND,59);
        c.set(Calendar.MILLISECOND,123);

        System.out.println("设置好的时间为:"+(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-"+ c.get(Calendar.DAY_OF_MONTH) +
                " "+ c.get(Calendar.HOUR_OF_DAY) + ':' + c.get(Calendar.MINUTE) + ':' + c.get(Calendar.SECOND) +
                ':' + c.get(Calendar.MILLISECOND) ));

    }
}
//输出
设置好的时间为:1992-10-13 23:35:59:123
4.5.2 一起设置年月日、年月日时分、年月日时分秒

set(int year ,int month,int date)
set(int year ,int month,int date,int hour,int minute)
set(int year ,int month,int date,int hour,int minute,int second)

import java.text.ParseException;
import java.util.Calendar;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //初始化Calendar类
        Calendar c = Calendar.getInstance();
        System.out.println("当前时间为:"+(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-"+ c.get(Calendar.DAY_OF_MONTH) +
                " "+ c.get(Calendar.HOUR_OF_DAY) + ':' + c.get(Calendar.MINUTE) + ':' + c.get(Calendar.SECOND) +
                ':' + c.get(Calendar.MILLISECOND) ));
        //将时间设置成1992-09-13 23:35:59
        c.clear();
        c.set(1992,9,13,23,35,59);

        System.out.println("设置好的时间为:"+(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-"+ c.get(Calendar.DAY_OF_MONTH) +
                " "+ c.get(Calendar.HOUR_OF_DAY) + ':' + c.get(Calendar.MINUTE) + ':' + c.get(Calendar.SECOND) +
                ':' + c.get(Calendar.MILLISECOND) ));
    }
}
//输出
当前时间为:2022-11-20 17:29:27:98
设置好的时间为:1992-10-13 23:35:59:0

4.6 时间计算

Calendar.add() 对时间进行加减运算

import java.text.ParseException;
import java.util.Calendar;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //初始化Calendar类
        Calendar c = Calendar.getInstance();
        System.out.println("当前时间是:"+(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-"+ c.get(Calendar.DAY_OF_MONTH) +
                " "+ c.get(Calendar.HOUR_OF_DAY) + ':' + c.get(Calendar.MINUTE) + ':' + c.get(Calendar.SECOND) +
                ':' + c.get(Calendar.MILLISECOND) ));
        c.add(Calendar.DATE,5);
        System.out.println("当前日期+5天后:"+(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-"+ c.get(Calendar.DAY_OF_MONTH) +
                " "+ c.get(Calendar.HOUR_OF_DAY) + ':' + c.get(Calendar.MINUTE) + ':' + c.get(Calendar.SECOND) +
                ':' + c.get(Calendar.MILLISECOND) ));

        c.add(Calendar.DATE,-15);
        System.out.println("当前日期-15天后:"+(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-"+ c.get(Calendar.DAY_OF_MONTH) +
                " "+ c.get(Calendar.HOUR_OF_DAY) + ':' + c.get(Calendar.MINUTE) + ':' + c.get(Calendar.SECOND) +
                ':' + c.get(Calendar.MILLISECOND) ));

    }
}
//输出
当前时间是:2022-11-20 17:23:57:406
当前日期+5天后:2022-11-25 17:23:57:406
当前日期-15天后:2022-11-10 17:23:57:406

4.7 获取时间戳( 获取当前毫秒数)

import java.text.ParseException;
import java.util.Calendar;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //初始化Calendar类
        Calendar c = Calendar.getInstance();
        //获取毫秒数
        System.out.println(c.getTimeInMillis());
    }
}
//输出
1668936885795

4.8 时间日期比较

Calender.before()Calender.after()Calender.compareTo()Calender.equals()

import java.text.ParseException;
import java.util.Calendar;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //初始化Calendar类
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        Calendar c3 = Calendar.getInstance();

        c1.clear();
        c2.clear();
        c3.clear();

        //c1设置为1992-09-13 23:35:59
        c1.set(1992,8,13 ,23,35,59);
        //c2设置为1992-10-08 21:21:55
        c2.set(1992,9,8 ,21,21,55);
        //c3设置为1992-10-08 21:21:55
        c3.set(1992,9,8 ,21,21,55);

        System.out.println("c1日期值:"+(c1.get(Calendar.YEAR) + "-" + (c1.get(Calendar.MONTH) + 1) + "-"+ c1.get(Calendar.DAY_OF_MONTH) +
                " "+ c1.get(Calendar.HOUR_OF_DAY) + ':' + c1.get(Calendar.MINUTE) + ':' + c1.get(Calendar.SECOND) +
                ':' + c1.get(Calendar.MILLISECOND) ));
        System.out.println("c2日期值:"+(c2.get(Calendar.YEAR) + "-" + (c2.get(Calendar.MONTH) + 1) + "-"+ c2.get(Calendar.DAY_OF_MONTH) +
                " "+ c2.get(Calendar.HOUR_OF_DAY) + ':' + c2.get(Calendar.MINUTE) + ':' + c2.get(Calendar.SECOND) +
                ':' + c2.get(Calendar.MILLISECOND) ));

        System.out.println("c3日期值:"+(c3.get(Calendar.YEAR) + "-" + (c3.get(Calendar.MONTH) + 1) + "-"+ c3.get(Calendar.DAY_OF_MONTH) +
                " "+ c3.get(Calendar.HOUR_OF_DAY) + ':' + c3.get(Calendar.MINUTE) + ':' + c3.get(Calendar.SECOND) +
                ':' + c3.get(Calendar.MILLISECOND) ));

        System.out.println("******************************************************************");

        //Calender.compareTo() 方法比较
        System.out.println("compareTo方法比较结果1:"+c1.compareTo(c2));
        System.out.println("compareTo方法比较结果2:"+c2.compareTo(c3));
        System.out.println("compareTo方法比较结果3:"+c2.compareTo(c1));

        System.out.println("------------------------------------------------------------------");
        //Calender.equals() 方法比较
        System.out.println("equals方法比较结果1:"+c1.equals(c2));
        System.out.println("equals方法比较结果2:"+c2.equals(c3));
        System.out.println("equals方法比较结果3:"+c2.equals(c1));

        System.out.println("------------------------------------------------------------------");
        //Calender.before() 方法比较
        System.out.println("before方法比较结果1:"+c1.before(c2));
        System.out.println("before方法比较结果2:"+c2.before(c3));
        System.out.println("before方法比较结果3:"+c2.before(c1));

        System.out.println("------------------------------------------------------------------");
        //Calender.after() 方法比较
        System.out.println("after方法比较结果1:"+c1.after(c2));
        System.out.println("after方法比较结果2:"+c2.after(c3));
        System.out.println("after方法比较结果3:"+c2.after(c1));

    }
}
//输出
c1日期值:1992-9-13 23:35:59:0
c2日期值:1992-10-8 21:21:55:0
c3日期值:1992-10-8 21:21:55:0
******************************************************************
compareTo方法比较结果1-1
compareTo方法比较结果20
compareTo方法比较结果31
------------------------------------------------------------------
equals方法比较结果1false
equals方法比较结果2true
equals方法比较结果3false
------------------------------------------------------------------
before方法比较结果1true
before方法比较结果2false
before方法比较结果3false
------------------------------------------------------------------
after方法比较结果1false
after方法比较结果2false
after方法比较结果3true

五、 第三代日期时间

由于第二代日期类也存在着以下问题

  • 可变性:像日期这样的类应该时不可变的
  • 偏移性:年份是从1900开始的,而月份从0开始
  • 格式化:格式化只对Date类有用,Calendar则不行,要格式化只能将Calendar 转换为Date
  • 线程安全性:都不是线程安全的
  • 时区问题:时区处理麻烦
  • 闰秒问题:不能处理闰秒(每隔2天,多出1s)
    所以在JDK8中出现了第三代日期时间类,第三代日期时间API具有以下特点
  • 线程安全性: 是线程安全的。不仅没有 setter 方法,而且任何对实例的变更都会返回一个新的实例,保证原来的实例不变
  • 方便性: − 提供了大量的方法,简化了日期时间的处理
  • 时区问题:引入了 域 ( domain ) 这个概念对时区进行处理

5.1 继承关系

  • java.time.LocalDate 用于表示 “本地日期”,无 “时间”。LocalDate 不承载时区信息。

  • java.time.LocalTime 用于表示 “本地时间”,无 “日期”。LocalTime 不承载时区信息。

  • java.time.LocalDateTime 用于表示 “本地日期与时间”。LocalDateTime 不承载时区信息。

  • java.time.ZonedDateTime 用于表示承载时区信息的时间

  • java.time.ZoneId 是引入的新的时区类

  • LocalDate 实例与 LocalTime 实例能够共同构建 LocalDateTime 实例;

  • LocalDateTime 实例能够获取 LocalDate 实例与 LocalTime 实例。

  • 可以简单地把ZonedDateTime理解成LocalDateTimeZoneId
    LocalDateTime

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

5.2 获取实例对象

  • 通过静态方法now()(获取的时间是系统当前的时间
  • 通过静态方法of()(方法参数可以指定时间
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前日期时间:"+now);

        //获取当前日期
        LocalDate nowdate = LocalDate.now();
        System.out.println("当前日期:" + nowdate);

        //获取当前时间
        LocalTime time = LocalTime.now();
        System.out.println("当前时间:" + time);

        System.out.println("********************************************");

        //设置日期时间
        LocalDateTime localdatetime = LocalDateTime.of(1992, 9, 13, 23, 56, 59, 333);
        System.out.println("日期时间设置为:" + localdatetime);

        //设置日期
        LocalDate localdate = LocalDate.of(1992, 9, 13);
        System.out.println("日期设置为:" + localdate);

        //设置时间
        LocalTime localtime = LocalTime.of(23, 56, 59, 333);
        System.out.println("时间设置为:" + localtime);

    }
}
//输出
当前日期时间:2022-11-22T06:34:13.280
当前日期:2022-11-22
当前时间:06:34:13.280
********************************************
日期时间设置为:1992-09-13T23:56:59.000000333
日期设置为:1992-09-13
时间设置为:23:56:59.000000333

5.3 获取年月日时分秒

  • getYear():获取年
  • getMonth():获得月份(返回一个 Month 枚举值)
  • getMonthValue():获得月份(1-12)
  • getDayOfMonth():获得月份天数(1-31)
  • getDayOfYear():获得年份天数(1-366)
  • getHour():获取小时
  • getMinute():获取分钟
  • getSecond():获取秒值
  • now.getNano():获取纳秒
  • getDayOfWeek():获得星期几(返回一个 DayOfWeek枚举值)
import java.text.ParseException;
import java.time.*;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前日期时间:"+now);

        //获取年份
        int year = now.getYear();
        System.out.println("当前年份:" + year);

        //获取月份
        Month month = now.getMonth();
        int monthValue = now.getMonthValue();
        System.out.println("当前月份枚举值获取:" + month);
        System.out.println("当前月份值:" + monthValue);

        //获取日
        int dayOfMonth = now.getDayOfMonth();
        int dayOfYear = now.getDayOfYear();
        DayOfWeek dayOfWeek = now.getDayOfWeek();
        System.out.println("一个月中的天:" + dayOfMonth);
        System.out.println("一年中的天:" + dayOfYear);
        System.out.println("一周中的天:" + dayOfWeek);

        //获取小时
        int hour = now.getHour();
        System.out.println("小时:" + hour);

        //获取分钟
        int minute = now.getMinute();
        System.out.println("分钟:" + minute);

        //获取秒
        int second = now.getSecond();
        System.out.println("秒:" + second);

        //获取纳秒
        int nano = now.getNano();
        System.out.println("纳秒:" + nano);
        
    }
}
//输出
当前日期时间:2022-11-22T06:53:29.172
当前年份:2022
当前月份枚举值获取:NOVEMBER
当前月份值:11
一个月中的天:22
一年中的天:326
一周中的天:TUESDAY
小时:6
分钟:53
秒:29
纳秒:172000000

5.4 日期时间比较

  • isAfter():判断一个日期是否在指定日期之后
  • isBefore():判断一个日期是否在指定日期之前
  • isEqual():判断两个日期是否相同
  • isLeapYear():判断是否是闰年(注意是LocalDate类 和 LocalDateTime类特有的方法)
  • compareTo(): 两个日期比较返回0,1,-1
import java.text.ParseException;
import java.time.*;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //dateTime1时间初始化为1992-09-13 23:35:59
        LocalDateTime dateTime1 = LocalDateTime.of(1992, 9, 13, 23, 35, 59);
        //dateTime2时间初始化为1992-10-08 23:35:50
        LocalDateTime dateTime2 = LocalDateTime.of(1992, 10, 8, 23, 35, 50);
        //dateTime3时间初始化为1992-10-08 23:35:50
        LocalDateTime dateTime3 = LocalDateTime.of(1992, 10, 8, 23, 35, 50);

        System.out.println("******************输出三个时间*****************************");
        System.out.println("dateTime1时间1:"+dateTime1);
        System.out.println("dateTime2时间2:"+dateTime2);
        System.out.println("dateTime3时间3:"+dateTime3);


        //isAfter()方法比较
        System.out.println("------------isAfter()方法比较-------------------");
        System.out.println("dateTime1在dateTime2之后?"+dateTime1.isAfter(dateTime2));
        System.out.println("dateTime2在dateTime3之后?"+dateTime2.isAfter(dateTime3));
        System.out.println("dateTime2在dateTime1之后?"+dateTime2.isAfter(dateTime1));


        //isBefore()方法比较
        System.out.println("------------isBefore()方法比较-------------------");
        System.out.println("dateTime1在dateTime2之前?"+dateTime1.isBefore(dateTime2));
        System.out.println("dateTime2在dateTime3之前?"+dateTime2.isBefore(dateTime3));
        System.out.println("dateTime2在dateTime1之前?"+dateTime2.isBefore(dateTime1));


        //isEqual()方法比较
        System.out.println("------------isEqual()方法比较-------------------");
        System.out.println("dateTime1与dateTime2相等?"+dateTime1.isEqual(dateTime2));
        System.out.println("dateTime2与dateTime3相等?"+dateTime2.isEqual(dateTime3));
        System.out.println("dateTime2与dateTime1相等?"+dateTime2.isEqual(dateTime1));

        //compareTo()方法比较
        System.out.println("------------compareTo()方法比较-------------------");
        System.out.println("dateTime1与dateTime2比较?"+dateTime1.compareTo(dateTime2));
        System.out.println("dateTime2与dateTime3比较?"+dateTime2.compareTo(dateTime3));
        System.out.println("dateTime2与dateTime1比较?"+dateTime2.compareTo(dateTime1));
    }
}
//输出
******************输出三个时间*****************************
dateTime1时间11992-09-13T23:35:59
dateTime2时间21992-10-08T23:35:50
dateTime3时间31992-10-08T23:35:50
------------isAfter()方法比较-------------------
dateTime1在dateTime2之后?false
dateTime2在dateTime3之后?false
dateTime2在dateTime1之后?true
------------isBefore()方法比较-------------------
dateTime1在dateTime2之前?true
dateTime2在dateTime3之前?false
dateTime2在dateTime1之前?false
------------isEqual()方法比较-------------------
dateTime1与dateTime2相等?false
dateTime2与dateTime3相等?true
dateTime2与dateTime1相等?false
------------compareTo()方法比较-------------------
dateTime1与dateTime2比较?-1
dateTime2与dateTime3比较?0
dateTime2与dateTime1比较?1

5.5 日期时间计算

5.5.1 增加年月日时分秒
  • plusYears(int offset):增加指定年份
  • plusMonths(int offset):增加指定月份
  • plusDates(int offset):增加指定日
  • plusHours(int offset):增加指定时
  • plusMinuets(int offset):增加指定分
  • plusSeconds(int offset):增加指定秒
  • plusNanos(int offset):增加指定纳秒
  • plusWeeks(int offset):增加指定周
import java.text.ParseException;
import java.time.*;

public class DateTest {
    public static void main(String[] args) throws ParseException {
       //获取当前时间
        LocalDateTime now = LocalDateTime.now();

        System.out.println("当前时间:" + now);

        //两年后
        LocalDateTime localDateTime1 = now.plusYears(2);
        System.out.println("两年以后:" + localDateTime1);

        //三个月后
        LocalDateTime localDateTime2 = now.plusMonths(3);
        System.out.println("三个月后:" + localDateTime2);

        //五天后
        LocalDateTime localDateTime3 = now.plusDays(5);
        System.out.println("五天后:" + localDateTime3);

        //4小时后
        LocalDateTime localDateTime4 = now.plusHours(4);
        System.out.println("4小时后:"+localDateTime4);

        //30分钟后
        LocalDateTime localDateTime5 = now.plusMinutes(30);
        System.out.println("30分钟后:" + localDateTime5);

        //80秒后
        LocalDateTime localDateTime6 = now.plusSeconds(80);
        System.out.println("80秒后:" + localDateTime6);

        //3周后
        LocalDateTime localDateTime7 = now.plusWeeks(3);
        System.out.println("3周后:"+localDateTime7);


    }
}
//输出
当前时间:2022-11-22T07:28:55.129
两年以后:2024-11-22T07:28:55.129
三个月后:2023-02-22T07:28:55.129
五天后:2022-11-27T07:28:55.129
4小时后:2022-11-22T11:28:55.129
30分钟后:2022-11-22T07:58:55.129
80秒后:2022-11-22T07:30:15.129
3周后:2022-12-13T07:28:55.129
5.5.1 减少年月日时分秒
  • minusYears(int offset):减少指定年
  • minusMonths(int offset):减少指定月
  • minusDates(int offset):减少指定日
  • minusHours(int offset):减少指定时
  • minusMinuets(int offset):减少指定分
  • minusSeconds(int offset):减少指定秒
  • minusNanos(int offset):减少指定纳秒
  • minusWeeks(int offset):减少指定周
import java.text.ParseException;
import java.time.*;

public class DateTest {
    public static void main(String[] args) throws ParseException {
       //获取当前时间
        LocalDateTime now = LocalDateTime.now();

        System.out.println("当前时间:" + now);

        //10年以前
        LocalDateTime localDateTime1 = now.minusYears(10);
        System.out.println("10年以前:" + localDateTime1);

        //三个月以前
        LocalDateTime localDateTime2 = now.minusMonths(3);
        System.out.println("三个月以前:" + localDateTime2);

        //五天前
        LocalDateTime localDateTime3 = now.minusDays(5);
        System.out.println("五天前:" + localDateTime3);

        //4小时前
        LocalDateTime localDateTime4 = now.minusHours(4);
        System.out.println("4小时前:"+localDateTime4);

        //30分钟前
        LocalDateTime localDateTime5 = now.minusMinutes(30);
        System.out.println("30分钟前:" + localDateTime5);

        //80秒前
        LocalDateTime localDateTime6 = now.plusSeconds(80);
        System.out.println("80秒前:" + localDateTime6);

        //3周后
        LocalDateTime localDateTime7 = now.minusWeeks(3);
        System.out.println("3周前:"+localDateTime7);

    }
}
//输出
当前时间:2022-11-22T07:33:14.203
10年以前:2012-11-22T07:33:14.203
三个月以前:2022-08-22T07:33:14.203
五天前:2022-11-17T07:33:14.203
4小时前:2022-11-22T03:33:14.203
30分钟前:2022-11-22T07:03:14.203
80秒前:2022-11-22T07:34:34.203
3周前:2022-11-01T07:33:14.203
5.5.3 时间调节器

可以更加灵活地处理一些复杂的日期,例如:实现日期调整到下个周日、下个工作日,或者是下个月的第一天等等,也可以增加自己定制功能

import java.text.ParseException;
import java.time.*;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;

public class DateTest {
    public static void main(String[] args) throws ParseException {
       //获取当前时间
        LocalDateTime now = LocalDateTime.now();

        System.out.println("当前时间:" + now);

        System.out.println("------------------下个月第一天--------------------------");

        //下个月第一天
        TemporalAdjuster temporalAdjuster = TemporalAdjusters.firstDayOfNextMonth();
        LocalDateTime localDateTime1 = now.with(temporalAdjuster);
        System.out.println(localDateTime1);

        System.out.println("------------------下周周五--------------------------");
        //下周周五
        TemporalAdjuster next = TemporalAdjusters.next(DayOfWeek.FRIDAY);
        LocalDateTime localDateTime12 = now.with(next);
        System.out.println(localDateTime12);
        
    }
}
//输出
当前时间:2022-11-22T07:56:56.906
------------------下个月第一天--------------------------
2022-12-01T07:56:56.906
------------------下周周五--------------------------
2022-11-25T07:56:56.906
5.5.4 with方法使用
  • withYear(int year):指定年
  • withMonth(int month):指定月
  • withDayOfMonth(int dayOfMonth):指定日
  • withDayOfYear(int dayOfYear):指定日
  • with(TemporalAdjuster adjuster):指定特殊时间
import java.text.ParseException;
import java.time.*;
import java.time.temporal.TemporalAdjusters;

public class DateTest {
    public static void main(String[] args) throws ParseException {
       //获取当前时间
        LocalDateTime now = LocalDateTime.now();

        System.out.println("当前时间:" + now);
        //指定1992年
        LocalDateTime localDateTime1 = now.withYear(1992);
        System.out.println("指定1992年:" + localDateTime1);

        //指定11月
        LocalDateTime localDateTime2 = now.withMonth(11);
        System.out.println("指定11月份:" + localDateTime2);

        //指定11日
        LocalDateTime localDateTime3 = now.withDayOfMonth(11);
        System.out.println("指定11日:" + localDateTime3);

        //指定特殊日期
        LocalDateTime localDateTime4 = now.with(TemporalAdjusters.firstDayOfMonth());
        System.out.println("指定当月第一天:"+localDateTime4);
    }
}
//输出
当前时间:2022-11-22T07:50:02.386
指定1992年:1992-11-22T07:50:02.386
指定11月份:2022-11-22T07:50:02.386
指定11日:2022-11-11T07:50:02.386
指定当月第一天:2022-11-01T07:50:02.386
5.5.5 计算两个“日期”间隔

Period 用于计算两个日期间隔, between() 方法只能接收 LocalDate 类型的参数

  • 静态方法 between():计算两个日期之间的间隔
  • getYears():获取年份
  • getMonths():获取月份
  • getDays():获取天数
import java.text.ParseException;
import java.time.*;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //设置生日
        LocalDate birth = LocalDate.of(2004, 10, 8);
        //获取当前时间
        LocalDate now = LocalDate.now();

        //计算两个时间间隔
        Period between = Period.between(birth, now);
        int years = between.getYears();
        int months = between.getMonths();
        int days = between.getDays();

        System.out.println("从出生到现在" + years + "年" + months + "月" + days + "天了");


    }
}
//输出
从出生到现在18115天了
5.5.6 计算两个“时间”间隔

Duration 表示一个时间段,Duration 包含两部分:seconds 表示秒,nanos 表示纳秒,它们的组合表达了时间长度。
因为 Duration 表示时间段,所以 Duration 类中不包含 now() 静态方法。注意,Duration 不包含毫秒这个属性。
Duration只能处理两个LocalTime, LocalDateTime, ZonedDateTime; 如果传入的是LocalDate,将会抛出异常

  • 静态方法 between():计算两个时间的间隔,默认是秒
  • toDays():将时间转换为以天为单位的
  • toHours():将时间转换为以时为单位的
  • toMinutes():将时间转换为以分钟为单位的
  • toMillis():将时间转换为以毫秒为单位的
  • toNanos():将时间转换为以纳秒为单位的
import java.text.ParseException;
import java.time.*;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        LocalTime beginTime = LocalTime.of(0, 1, 2);
        LocalTime now = LocalTime.now();

        Duration between = Duration.between(beginTime, now);

        long days = between.toDays();
        long hours = between.toHours();
        long minutes = between.toMinutes();
        long millis = between.toMillis();
        long nanos = between.toNanos();

        System.out.println("从0点1分1秒到现在一共" + days + "天" );
        System.out.println("从0点1分1秒到现在一共" + hours + "小时" );
        System.out.println("从0点1分1秒到现在一共" + minutes + "分" );
        System.out.println("从0点1分1秒到现在一共" + millis/1000 + "秒" );
        System.out.println("从0点1分1秒到现在一共" + nanos + "纳秒" );

    }
}
//输出011秒到现在一共0天
从011秒到现在一共6小时
从011秒到现在一共381分
从011秒到现在一共22888秒
从011秒到现在一共22888801000000纳秒

5.6 获取时间戳

java.time.Instant 可以获取时间线上的一个瞬时点,精确到纳秒级

  • now(): 获取实例化对象。默认获取出来的是默认时区,和我们(东八区)相差8小时
  • atOffset():设置偏移量
  • atZone():获取系统默认时区时间,参数是一个时区的编号(可以通过时区编号类获取ZonedDateTime类的对象)
  • getEpochSecond():获取从1970-01-01 00:00:00到当前时间的秒数
  • toEpochMilli():获取从1970-01-01 00:00:00到当前时间的毫秒数
  • getNano():获取从1970-01-01 00:00:00到当前时间的纳秒数
  • ofEpochSecond():给计算机元年增加秒数
  • ofEpochMilli():给计算机元年增加毫秒数
import java.text.ParseException;
import java.time.*;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //从1970-01-01 00:00:00 截止到当前时间的毫秒值(时区不是中国的)
        Instant now = Instant.now();
        System.out.println("1970-01-01 00:00:00到默认时区当前日期:" + now);

        //获取当前时区的,我们可以添加偏移量,返回偏移过后的日期
        OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));
        System.out.println("1970-01-01 00:00:00到当前时区日期:"+offsetDateTime);


        //1970-01-01 00:00:00 截止到当前时间间隔的毫秒值
        long ll = now.toEpochMilli();
        System.out.println("1970-01-01 00:00:00到当前时间间隔的毫秒值:" + ll);

        //1970-01-01 00:00:00 截止到当前时间间隔的秒数
        long epochSecond = now.getEpochSecond();
        System.out.println("1970-01-01 00:00:00 到当前时间间隔的秒数:" + epochSecond);


        //ofEpochMilli() 给计算机元年增加毫秒数
        Instant instant = Instant.ofEpochMilli(1000 * 60 * 60 * 24);
        System.out.println("计算机元年增加1天(86400000毫秒):"+instant);

        //ofEpochSecond() 方法 给计算机元年增加秒数
        Instant instant1 = Instant.ofEpochSecond(60 * 60 * 24);
        System.out.println("计算机元年增加1天(86400秒):"+instant1);

    }
}
//输出
1970-01-01 00:00:00到默认时区当前日期:2022-11-22T23:12:40.988Z
1970-01-01 00:00:00到当前时区日期:2022-11-23T07:12:40.988+08:00
1970-01-01 00:00:00到当前时间间隔的毫秒值:1669158760988
1970-01-01 00:00:00 到当前时间间隔的秒数:1669158760
计算机元年增加1天(86400000毫秒):1970-01-02T00:00:00Z
计算机元年增加1天(86400秒):1970-01-02T00:00:00Z

5.7 带时区的日期时间

ZonedDateTime 是带有带有特定时区的日期时间类,类的方法和用法和 LocalDateTime 基本一样。
可以简单地把ZonedDateTime理解成LocalDateTimeZoneId
ZoneIdjava.time引入的新的时区类

5.7.1 获取不同时区当前时间
import java.text.ParseException;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Set;

public class DateTest {
    public static void main(String[] args) throws ParseException {
        //获取世界各个地方的时区编号
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        for (String availableZoneId : availableZoneIds) &#123;
            System.out.println(availableZoneId);
        &#125;
        System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++");

        //获取系统默认时区编号
        ZoneId zoneId = ZoneId.systemDefault();
        System.out.println("系统默认时区编号:" + zoneId);
        System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++");

        ZonedDateTime zbj = ZonedDateTime.now(); // 默认时区
        System.out.println("获取默认时区时间:"+zbj);

        System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++");
        ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/New_York")); // 用指定时区获取当前时间
        System.out.println("获取指定时区时间:"+zny);
    &#125;
&#125;
**注:时区不同,但表示的时间都是同一时刻**

//输出
Asia/Aden
America/Cuiaba
Etc/GMT+9
....... 由于时区比较多,这里就不一一例举了
Europe/Athens
US/Pacific
Europe/Monaco
+++++++++++++++++++++++++++++++++++++++++++++++
系统默认时区编号:Asia/Shanghai
+++++++++++++++++++++++++++++++++++++++++++++++
获取默认时区时间:2022-11-23T21:24:03.304+08:00[Asia/Shanghai]
+++++++++++++++++++++++++++++++++++++++++++++++
获取指定时区时间:2022-11-23T08:24:03.305-05:00[America/New_York]
5.7.2 设置一个时区时间
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class DateTest &#123;
    public static void main(String[] args) throws ParseException &#123;
        LocalDateTime localDateTime = LocalDateTime.of(1992, 9, 13, 23, 35, 59);

        ZonedDateTime zonedDateTime1 = localDateTime.atZone(ZoneId.systemDefault());
        ZonedDateTime zonedDateTime2 = localDateTime.atZone(ZoneId.of("America/New_York"));

        System.out.println("默认时区时间:"+zonedDateTime1);
        System.out.println("America/New_York时区时间:"+zonedDateTime2);
    &#125;
&#125;
//输出
默认时区时间:1992-09-13T23:35:59+08:00[Asia/Shanghai]
America/New_York时区时间:1992-09-13T23:35:59-04:00[America/New_York]

注:它的日期和时间与LocalDateTime相同,但附加的时区不同,因此是两个不同的时刻

5.7.3 时区转换

将关联时区转换到另一个时区,转换后日期和时间都会相应调整

import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class DateTest &#123;
    public static void main(String[] args) throws ParseException &#123;
        //以中国时区获取当前时间
        ZonedDateTime now1 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
        //将中国时间转换为美国纽约时间
        ZonedDateTime zonedDateTime = now1.withZoneSameInstant(ZoneId.of("America/New_York"));

        System.out.println("中国时区当前时间:" + now1);
        System.out.println("将中国时间转换为美国纽约时间:"+zonedDateTime);

    &#125;
&#125;
//输出
中国时区当前时间:2022-11-23T21:43:31.065+08:00[Asia/Shanghai]
将中国时间转换为美国纽约时间:2022-11-23T08:43:31.065-05:00[America/New_York]
5.7.4 日期时间格式化

第一代Date对象用SimpleDateFormat进行格式化显示,而DateTimeFormatter用于解析第三代日期字符串和格式化日期输出

import java.text.ParseException;
import java.time.LocalDateTime;

import java.time.format.DateTimeFormatter;

public class DateTest &#123;
    public static void main(String[] args) throws ParseException &#123;
        //指定日期格式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
        LocalDateTime now = LocalDateTime.now();

        String format = dateTimeFormatter.format(now);
        System.out.println("未格式化日期显示:" + now);
        System.out.println("当前日期格式化后:" + format);

    &#125;
&#125;
//输出
未格式化日期显示:2022-11-23T21:51:00.197
当前日期格式化后:2022-11-23 09:51:00
5.7.5 日期字符串转日期
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;

import java.time.format.DateTimeFormatter;

public class DateTest &#123;
    public static void main(String[] args) throws ParseException &#123;
        //指定日期格式
        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDate localDate = LocalDate.parse("1992-09-13", dateTimeFormatter1);
        System.out.println("字符串转LocalDate:" + localDate);
      
        LocalDateTime localDateTime = LocalDateTime.parse("1992-09-13 23:35:59", dateTimeFormatter2);
        System.out.println("字符串转LocalDateTime:" + localDateTime);


    &#125;
&#125;
//输出
字符串转LocalDate:1992-09-13
字符串转LocalDateTime:1992-09-13T23:35:59

六、三代日期之间相互转换

由于历史遗留问题,有时候我们不得不与遗留代码打交道。这时就涉及了三代日期时间之间的相互转换

注: 在转换中我们需要特别注意,java8之前Date是包含日期和时间的,而LocalDate只包含日期LocalTime只包含时间,所以与Date与之互转过程中,会丢失日期或者时间。最好是转换成LocalDateTime,这样就不存在日期或时间丢失问题

6.1 Calendar 与 Date 互转

6.1.1 Date 转换为Calendar
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;

public class DateTest &#123;
    public static void main(String[] args) throws ParseException &#123;
        //Date 转换为Calendar
        Date date = new Date();
        System.out.println("当前Date时间为:"+date);
        Calendar cal= Calendar.getInstance();
        cal.setTime(date);
        System.out.println("Date转换为Calendar后:"+(cal.get(Calendar.YEAR) + "-" + (cal.get(Calendar.MONTH) + 1) + "-"+ cal.get(Calendar.DAY_OF_MONTH) +
                " "+ cal.get(Calendar.HOUR_OF_DAY) + ':' + cal.get(Calendar.MINUTE) + ':' + cal.get(Calendar.SECOND)));

    &#125;
&#125;
//输出
当前Date时间为:Fri Nov 25 07:17:06 CST 2022
Date转换为Calendar后:2022-11-25 7:17:6
6.1.2 Calendar 转换为Date
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;

public class DateTest &#123;
    public static void main(String[] args) throws ParseException &#123;
        //Calendar 转换为Date
        Calendar cal=Calendar.getInstance();
        System.out.println("Calendar获取的当前时间是:"+(cal.get(Calendar.YEAR) + "-" + (cal.get(Calendar.MONTH) + 1) + "-"+ cal.get(Calendar.DAY_OF_MONTH) +
                " "+ cal.get(Calendar.HOUR_OF_DAY) + ':' + cal.get(Calendar.MINUTE) + ':' + cal.get(Calendar.SECOND)));

        Date date=cal.getTime();
        System.out.println("当前Date时间为:"+date);
    &#125;
&#125;
//输出
Calendar获取的当前时间是:2022-11-25 7:17:29
当前Date时间为:Fri Nov 25 07:17:29 CST 2022

6.2 Date和Instant互换

6.2.1 Date转为Instant
import java.text.ParseException;
import java.time.Instant;
import java.util.Date;

public class DateTest &#123;
    public static void main(String[] args) throws ParseException &#123;
        //Date转为Instant
        Date date = new Date();
        System.out.println("当前Date获取的时间是:"+date);
        Instant instant = date.toInstant();
        System.out.println("转为Instant后的时间是:"+instant);
    &#125;
&#125;
//输出
当前Date获取的时间是:Fri Nov 25 07:27:13 CST 2022
转为Instant后的时间是:2022-11-24T23:27:13.860Z
6.2.2 Instant转为Date
import java.text.ParseException;
import java.time.Instant;
import java.util.Date;

public class DateTest &#123;
    public static void main(String[] args) throws ParseException &#123;
        //Instant转为Date
        Instant instant  = Instant.now();
        System.out.println("Instant获取的时间是:"+instant);
        Date date = Date.from(instant);
        System.out.println("转换为Date后:"+date);
    &#125;
&#125;
//输出
Instant获取的时间是:2022-11-24T23:29:18.857Z
转换为Date后:Fri Nov 25 07:29:18 CST 2022

6.3 Date与LocalDateTime互转

6.3.1 Date转LocalDateTime
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

public class DateTest &#123;
    public static void main(String[] args) throws ParseException &#123;
        //Date 转LocalDateTime
        Date date = new Date();
        System.out.println("Date获取的当前时间" + date);

        LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        System.out.println("第一种方式转为LocalDateTime后: " + localDateTime);

        LocalDateTime localDateTime1 = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        System.out.println("第二种方式转为localDateTime2: " + localDateTime1);


    &#125;
&#125;
//输出
Date获取的当前时间Fri Nov 25 07:35:04 CST 2022
第一种方式转为LocalDateTime后: 2022-11-25T07:35:04.379
第二种方式转为localDateTime2: 2022-11-25T07:35:04.379
6.3.2 LocalDateTime 转Date
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

public class DateTest &#123;
    public static void main(String[] args) throws ParseException &#123;
        //LocalDateTime 转 Date
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println("localDateTime获取的当前时间: " + localDateTime);

        Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        System.out.println("转为Date后的时间: " + date);

    &#125;
&#125;
//输出
localDateTime获取的当前时间: 2022-11-25T07:36:58.216
转为Date后的时间: Fri Nov 25 07:36:58 CST 2022

七、阿里巴巴关于日期时间编程规约

阿里巴巴java开发手册,第一章1.5小结对日期时间做了相关规约。这里的规约也值得我们每个开发者遵守

①【强制】在日期格式化时,传入pattern中表示年份统一使用小写y

日期格式化时,yyyy表示当天所在的年,大写的YYYY表示当天所在的周所属的年份。一周以周日开始,周六结束,只要本周跨年,返回的YYYY就是下一年。

//正例
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")

②【强制】在日期格式中,分清楚大写的M小写的m大写的H小写的h分别代表的含义

  • 表示月份,用大写M
  • 表示分钟,用小写m
  • 表示24小时制,用大写H
  • 表示12小时制,用小写h

③ 【强制】获取当前毫秒数,是System.currentTimeMillis();而不是new Date().getTime()。

说明:如果像获取更加精确的纳秒级时间值,则使用System.nanoTime() 的方法。在JDK8中,针对时间等场景,推荐使用Instant类

④ 【强制】不允许在程序的任何地方使用:
1)java.sql.Date;
2) java.sql.Time;
3) java.sql.Timestamp;

说明:第1个不记录时间,getHours() 抛出异常;
第2个不记录日期,getYear() 抛出异常
第3个在构造方法supper((time/1000)*1000)时,在Timestamp属性henanos中分别存贮秒和纳秒信息

⑤【强制】不要在程序中写死一年未365天,避免在闰年时出现日期转换错误或程序逻辑错误。
//正列

//获取几年的天数
int days =localDate.now().lengthOfYear();
//获取某年的天数
Localdate.of(2022,1,2).lengthOfYear();

//反列

//第一种情况:在闰年(366天)时,出现数组越界异常
int[] dayArray = new int[365]
//第二种情况:一年有效期会员制,今年1月26日注册,
//一年未365天,返回的却是1月25日
Calendar calendar = Calendar.getInstance();
calendar.set(2022,0,26);
calendar.add(Calendar.DATE,365);

⑥ 【推荐】避免出现闰年2月问题。闰年2月有29天,一年后的那一天不可能是2月29日。
⑦ 【推荐】使用枚举值指代月份(month)取值在0~11之间

说明:参考JDK原生注释:Month value is 0-based.e.g.0 for January
//正例
用Calendar.JANUARY、Calendar.FEBRUARY、Calendar.MARCH等指代月份,进行传参或比较

本期内容就到这了,我们下期再见(●’◡’●)


文章作者: xiezhr
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 xiezhr !
评论
  目录