Java日期时间的前世今生

简介: 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包下,主要包含Date 、SimpleDateFormat类

第二代日期时间类也是定义在java.util包下,主要是Calendar、TimeZone 类

第三代日期时间类是在Java 8引入的,定义在java.time 包下,主要包含LocalDateTime 、ZonedDateTime 、ZoneId 、DateTimeFormatter类

此时,小伙伴可能会问了


为什么会出现三代日期时间类呢?

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

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

答:如果是新项目,就建议使用最新API。因为新的API中的类是不变对象,并且是线程安全的;

如果读者和我一样苦逼,还得维护JDK1.6 这样的遗留代码,就必须对一二代API有所了解。

如果要维护历史遗留代码,新旧API可以相互转换吗?

答:当然了,新旧API之间也是可以相互转换的。

三、 第一代日期时间Date

3.1 继承关系


e55c32a2b38d4b968abab2b6ac9fb453.png

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格式:2022年11月20日 星期日 下午02时24分59秒 CST
MEDIUM格式:2022-11-20 14:24:59
LONG格式:2022年11月20日 下午02时24分59秒

3.5.2 SimpleDateFormat类进行格式化

DateFormat 类的子类,具有更加强大的日期格式化功能;DateFormat只能单独对日期或时间格式化,而 SimpleDateFormat可以选择任何用户定义的日期/时间格式的模式


5fcb03db41d4412880d984de68c71785.png

SimpleDateFormat 类主要有如下 3 种构造方法。

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

722f069723c14f1388919c070e670a81.png

字母 描述 示例
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()));
    }
}
//输出
今天是:2022年11月20日 15点27分37秒 091 毫秒 星期日 
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 继承关系

1c025581809a4c21b1b240a2a909452b.png

63f4a54fc9b348c5aa4f3defb31871fa.png

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方法比较结果2:0
compareTo方法比较结果3:1
------------------------------------------------------------------
equals方法比较结果1:false
equals方法比较结果2:true
equals方法比较结果3:false
------------------------------------------------------------------
before方法比较结果1:true
before方法比较结果2:false
before方法比较结果3:false
------------------------------------------------------------------
after方法比较结果1:false
after方法比较结果2:false
after方法比较结果3:true




五、 第三代日期时间

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

  • 可变性:像日期这样的类应该时不可变的
  • 偏移性:年份是从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




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时间1:1992-09-13T23:35:59
dateTime2时间2:1992-10-08T23:35:50
dateTime3时间3:1992-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 + "天了");
    }
}
//输出
从出生到现在18年1月15天了
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 + "纳秒" );
    }
}
//输出
从0点1分1秒到现在一共0天
从0点1分1秒到现在一共6小时
从0点1分1秒到现在一共381分
从0点1分1秒到现在一共22888秒
从0点1分1秒到现在一共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) {
            System.out.println(availableZoneId);
        }
        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);
    }
}
**注:时区不同,但表示的时间都是同一时刻**
//输出
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 {
    public static void main(String[] args) throws ParseException {
        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);
    }
}
//输出
默认时区时间: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 {
    public static void main(String[] args) throws ParseException {
        //以中国时区获取当前时间
        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);
    }
}
//输出
中国时区当前时间: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 {
    public static void main(String[] args) throws ParseException {
        //指定日期格式
        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);
    }
}
//输出
未格式化日期显示: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 {
    public static void main(String[] args) throws ParseException {
        //指定日期格式
        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);
    }
}
//输出
字符串转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 {
    public static void main(String[] args) throws ParseException {
        //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)));
    }
}
//输出
当前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 {
    public static void main(String[] args) throws ParseException {
        //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);
    }
}
//输出
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 {
    public static void main(String[] args) throws ParseException {
        //Date转为Instant
        Date date = new Date();
        System.out.println("当前Date获取的时间是:"+date);
        Instant instant = date.toInstant();
        System.out.println("转为Instant后的时间是:"+instant);
    }
}
//输出
当前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 {
    public static void main(String[] args) throws ParseException {
        //Instant转为Date
        Instant instant  = Instant.now();
        System.out.println("Instant获取的时间是:"+instant);
        Date date = Date.from(instant);
        System.out.println("转换为Date后:"+date);
    }
}
//输出
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 {
    public static void main(String[] args) throws ParseException {
        //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);
    }
}
//输出
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 {
    public static void main(String[] args) throws ParseException {
        //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);
    }
}
//输出
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()。

④ 【强制】不允许在程序的任何地方使用:

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等指代月份,进行传参或比较

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

目录
相关文章
|
25天前
|
Java 数据库
java小工具util系列1:日期和字符串转换工具
java小工具util系列1:日期和字符串转换工具
53 26
|
1月前
|
安全 Java API
告别SimpleDateFormat:Java 8日期时间API的最佳实践
在Java开发中,处理日期和时间是一个基本而重要的任务。传统的`SimpleDateFormat`类因其简单易用而被广泛采用,但它存在一些潜在的问题,尤其是在多线程环境下。本文将探讨`SimpleDateFormat`的局限性,并介绍Java 8引入的新的日期时间API,以及如何使用这些新工具来避免潜在的风险。
35 5
|
5月前
|
Java
Java基础之日期和时间
Java基础之日期和时间
40 1
|
6月前
|
安全 Java 程序员
Java8实战-新的日期和时间API
Java8实战-新的日期和时间API
51 3
|
2月前
|
Java API
Java的日期类都是怎么用的
【10月更文挑战第1天】本文介绍了 Java 中处理日期和时间的三个主要类:`java.util.Date`、`java.util.Calendar` 和 `java.time` 包下的新 API。`Date` 类用于表示精确到毫秒的瞬间,可通过时间戳创建或获取当前日期;`Calendar` 抽象类提供丰富的日期操作方法,如获取年月日及时区转换;`java.time` 包中的 `LocalDate`、`LocalTime`、`LocalDateTime` 和 `ZonedDateTime` 等类则提供了更为现代和灵活的日期时间处理方式,支持时区和复杂的时间计算。
50 14
|
3月前
|
Java 数据库
java小工具util系列1:日期和字符串转换工具
java小工具util系列1:日期和字符串转换工具
56 3
|
3月前
|
安全 Java API
时间日期API(Date,SimpleDateFormat,Calendar)+java8新增日期API (LocalTime,LocalDate,LocalDateTime)
这篇文章介绍了Java中处理日期和时间的API,包括旧的日期API(Date、SimpleDateFormat、Calendar)和Java 8引入的新日期API(LocalTime、LocalDate、LocalDateTime)。文章详细解释了这些类/接口的方法和用途,并通过代码示例展示了如何使用它们。此外,还讨论了新旧API的区别,新API的不可变性和线程安全性,以及它们提供的操作日期时间的灵活性和简洁性。
|
4月前
|
前端开发 JavaScript Java
【前端学java】java中的日期操作(13)
【8月更文挑战第10天】java中的日期操作
26 2
【前端学java】java中的日期操作(13)
|
4月前
|
Java
比较两个日期是否相等Java
这篇文章提供了Java中比较两个日期是否相等的两种方法:使用`Calendar`类和`SimpleDateFormat`类来确定两个日期是否为同一天,并附有详细的代码示例和测试结果。
|
6月前
|
Java 测试技术 API
滚雪球学Java(52):一步一步教你使用Java Calendar类进行日期计算
【6月更文挑战第6天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
56 3
滚雪球学Java(52):一步一步教你使用Java Calendar类进行日期计算