Java中常用日期API的前世今生

介绍API之前,先了解下几个基本知识。

计算世界时间的主要标准有:

  • UTC(Coordinated Universal Time)协调世界时:是以原子时秒长为基础,在时刻上尽量接近于世界时的一种时间计量系统。
  • GMT(Greenwich Mean Time)世界时:也称为格林威治标准时间,格林威治位于本初子午线上。
  • CST(Central Standard Time)中央标准时间:CST可视为美国、澳大利亚、古巴或中国的标准时间。

Java中的时间是从 1970 年 1 月 1 日 00:00:00 开始计算。



Java8之前的日期API

java.util.Date

java.util.Date类是JDK1.0引入的,表示特定的瞬间(时间戳),精确到毫秒。比如2022年01月01日 00:00:00就是一个瞬间,而用Date表示,就是从1970 年 1 月 1 日 00:00:00 到该时间所经历的毫秒数。

Date类常用的构造器有两个:

  1. Date():获取本地当前时间创建对象。
  2. Date(long date):使用给定的时间值构建对象。

常用方法:

  1. getTime():返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
  2. toString():把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat),zzz是时间标准。

Date类使用的简单演示:

@Test
public void test() {
    Date date = new Date();
    System.out.println(date);
    System.out.println(date.getTime());  // 获取当前对象的时间戳
    
    Date date1 = new Date(1651472939950L);
    System.out.println(date1);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cgWyI21H-1651633462149)(G:\Typora\JavaSE学习笔记高级篇.asserts\image-20220502143240700.png)]
当然Date类中还有许多其他方法,比如获取当前对象代表的秒数,小时数,分钟数等等,不过这些方法大多都过时了,由 java.util.Calendar中的方法代替。还有一些与新的日期类转换的方法,就不在这里介绍了。


java.util.Calendar(日历)类

java.util.Date类代表一个时间戳。如果想要知道某个时间点所处的位置,比如该时间是星期几,一个月中的第几天,一年中的第几天等等,就必须使用日历类了。

Calendar是JDK1.1引入的,是一个抽象基类,主要用于完成日期字段之间相互操作的功能。

获取Calendar实例的方法

  • 使用Calendar.getInstance()方法。(基本都用这个方法)
  • 调用它的子类GregorianCalendar的构造器。

Calendar中定义了一些常量(日期字段)供我们使用,比如:

YEAR:代表年份

MONTH:代表月份

MINUTE:代表分钟

SECOND:代表秒

DAY_OF_WEEK:代表一周中天数,也就是星期几。

HOUR_OF_DAY :代表一天中的小时数,也就是几点。

DAY_OF_WEEK_IN_MONTH:代表处于一个月的第几周。

注意:

  • 获取月份时:一月是0,二月是1,以此类推,12月是11
  • 获取星期时:周日是1,周二是2 , 。。。。周六是7

Calendar类提供了对日期字段操作的方法,获取、设置、对日期进行加减操作等。

常用方法:

  1. public void set(int field,int value):对日历对象进行修改
  2. public int get(int field):获取日历对象的属性
  3. public void add(int field,int amount):对日历对象的属性进行修改
  4. public final Date getTime():获取日历中Date对象
  5. public final void setTime(Date date):通过Date对象修改日历
  6. public boolean after(Object when):当前日历对象是否在when之后,当然这个when必须是Calendar的实例
  7. public boolean before(Object when):当前日历对象是否在when之前
  8. public int compareTo(Calendar anotherCalendar):比较日历对象的先后

Calendar类使用的简单演示:

@Test
public void test() {
    // 初始化,获取当前本地时间的日历对象
    Calendar calender = Calendar.getInstance();
    //Calendar gregorianCalendar = new GregorianCalendar();
    // 获取部分时间  比如几号,星期几
    int dayofweek = calender.get(Calendar.DAY_OF_WEEK);
    int dayofmonth = calender.get(Calendar.DAY_OF_MONTH);
    int dayofweekinmonth = calender.get(Calendar.DAY_OF_WEEK_IN_MONTH);
    System.out.println(dayofweek);
    System.out.println(dayofmonth);
    System.out.println(dayofweekinmonth);
    // set
    calender.set(Calendar.DAY_OF_MONTH, 22); //设置为当月的第21天
    System.out.println(calender.get(Calendar.DAY_OF_MONTH));
    calender.add(Calendar.DAY_OF_MONTH, 2); //往后推2天
    System.out.println(calender.get(Calendar.DAY_OF_MONTH));
    calender.add(Calendar.DAY_OF_MONTH,-2); // 往前推两天
    System.out.println(calender.get(Calendar.DAY_OF_MONTH));
    // Date <--> Calendar
    Date time = calender.getTime();
    System.out.println(time);
    Date date = new Date();
    calender.setTime(date);
    System.out.println(calender.getTime());
    //比较日期的先后
    Calendar calendar1 = Calendar.getInstance();
    System.out.println(calendar1.before(calender));
    System.out.println(calendar1.after(calender));
    System.out.println(calendar1.compareTo(calender));
}

java.text.SimpleDateFormat

Java虽然提供了日期相关的操作,但是想要创建任意时间的日期对象却并不方便(难道还要去算毫秒数?),而且Date类的API不易于国际化,大部分被废弃了。比如我们常见的是这种格式:2000-01-01 00:00:00,而Date类打印的是这种格式:Mon May 02 15:49:33 CST 2022。对于使用不同时间格式的地区来说很不舒服。

所以,提供日期格式转换功能的类java.text.SimpleDateFormat出现了。java.text.SimpleDateFormat类是一个不与语言环境有关的方式来格式化和解析日期的具体类。它允许进行格式化:日期->文本、解析:文本->日期

格式化相关方法:

  • SimpleDateFormat() :默认的模式和语言环境创建对象
  • public SimpleDateFormat(String pattern):该构造方法可以用参数pattern指定的格式创建一个对象
  • public String format(Date date):格式化时间对象date

解析相关方法:

public Date parse(String source):从给定字符串的开始解析文本,以生成一个日期。

对于日期格式的转换,并不是随意构造,而有一套规范:

日期转换的基本操作:

package com.chunni.date;

import org.junit.Test;

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

public class SimpleDateFormatTest {

    @Test
    public void test() {
        // 产生一个Date实例
        Date date = new Date(); 
        // 产生一个format格式化的实例
        SimpleDateFormat format = new SimpleDateFormat();
        // 打印输出默认的格式
        System.out.println(format.format(date));
        // 指定一个格式
        SimpleDateFormat format1 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        System.out.println(format1.format(date));
        try {
            // 实例化一个指定的格式对象
            Date date2 = format1.parse("2022年01月01日 08:08:08");
            // 将指定的日期解析后格式化按指定的格式输出
            System.out.println(date2.toString());
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9aY28mD7-1651633462150)(G:\Typora\JavaSE学习笔记高级篇.asserts\image-20220502155947032.png)]



Java8中的日期API

老API中存在的问题:

  • 可变性:像日期和时间这样的类应该是不可变的。
  • 偏移性:Calendar中月份从0开始,星期从周日(1)开始计算
  • 格式化:格式化只对Date有用,Calendar则不行。
  • 线程安全:SimpleDateFormat是非线程安全的,每个线程都需要维护一份。

Java8新推出的日期API:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4RndHmDL-1651633462151)(G:\Typora\JavaSE学习笔记高级篇.asserts\image-20220426202809752.png)]

新引入的日期API线程安全且不可变,月份从1开始,星期从星期一开始,且格式转换支持多种类型。

LocalDate、LocalTime、LocalDateTime

LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。可以提供日期相关的操作,对应之前的Calendar类。

  • LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。
  • LocalTime表示一个时间,而不是日期。
  • LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一。

(ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历。)

常用方法:

方法描述
now() / * now(ZoneId zone)静态方法,根据当前时间创建对象/指定时区的对象
of()静态方法,根据指定日期/时间创建对象
getDayOfMonth()/getDayOfYear()获得月份天数(1-31) /获得年份天数(1-366)
getDayOfWeek()获得星期几(返回一个 DayOfWeek 枚举值)
getMonth()获得月份, 返回一个 Month 枚举值
getMonthValue() / getYear()获得月份(1-12) /获得年份
getHour()/getMinute()/getSecond()获得当前对象对应的小时、分钟、秒
withDayOfMonth()/withDayOfYear()/withMonth()/withYear()将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象
plusDays(), plusWeeks(), plusMonths(), plusYears(),plusHours()向当前对象添加几天、几周、几个月、几年、几小时
minusMonths()/minusWeeks()/minusDays()/minusYears()/minusHours()从当前对象减去几月、几周、几天、几年、几小时

当然还有日期比较相关的方法…

新API中月份从1开始,星期从周一开始,符合我们常规的计量方式。

基本使用演示:

 @Test
 public void testLocaleDate() {
     // 获取当前时间创建对象
     LocalDate localDate = LocalDate.now();
     LocalTime localTime = LocalTime.now();
     LocalDateTime localDateTime = LocalDateTime.now();
     System.out.println(localDate);
     System.out.println(localTime);
     System.out.println(localDateTime);
     System.out.println(localDateTime.getDayOfMonth());
     System.out.println(localDateTime.getDayOfWeek().getValue());
     System.out.println(localDateTime.getDayOfYear());
     // 根据指定时间创建对象
     LocalDateTime localDateTime1 = LocalDateTime.of(2022, 4, 10, 12, 0, 0,0);
     System.out.println(localDateTime1);
     // localDate不会改变,体现了不可变性
     // 设置相关属性,直接使用withxx方法
     LocalDate localDate1 = localDate.withDayOfMonth(3);
     System.out.println(localDate1);
     System.out.println(localDate);
     // 日期加减操作
     LocalDateTime localDateTime2 = localDateTime.plusDays(3);
     System.out.println(localDateTime2);
     LocalDateTime localDateTime3 = localDateTime.minusDays(3);
     System.out.println(localDateTime3);
     System.out.println(localDateTime.isAfter(localDateTime1));
 }


java.time.Instant

Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳。相当于老API中的Date。

Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒数。因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。

常用方法:

方法描述
now()静态方法,返回默认UTC时区的Instant类的对象
ofEpochMilli(long epochMilli)静态方法,返回在1970-01-01 00:00:00基础上加上指定毫秒数之后的Instant类的对象
atOffset(ZoneOffset offset)结合即时的偏移来创建一个 OffsetDateTime
toEpochMilli()返回1970-01-01 00:00:00到当前时间的毫秒数,即为时间戳
equals(Object otherInstant)判断是否相等

Instant类中也存在进行加减、比较的方法…

基本使用演示:

@Test
public void test01() {
    // 获取当前时间创建对象
    Instant instant = Instant.now();
    System.out.println(instant); // 加8小时才是北京时间
    // 添加偏移量
    OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
    System.out.println(offsetDateTime); //
    // 获取对应毫秒数 自1970-01-01T00:00:00Z.
    long l = instant.toEpochMilli();//
    System.out.println(l);
    // 通过Long型的时间获取时间对象
    Instant instant1 = Instant.ofEpochMilli(1650977606932L);
    Instant instant2 = Instant.ofEpochSecond(1650977606L);
    System.out.println(instant1);
    System.out.println(instant2);
    // 判断时间戳是否相等
    System.out.println(instant1.equals(instant2));
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WEJttVfT-1651633462153)(G:\Typora\JavaSE学习笔记高级篇.asserts\image-20220502184015559.png)]



java.time.format.DateTimeFormatter

DateTimeFormatter用于格式化和解析日期时间对象。对应老API中的SimpleDateFormat。

DateTimeFormatter提供了三种初始化方式:

  1. DateTimeFormatter预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
  2. 本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.LONG)
  3. 自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”),当然,自定义是用的最多的。

格式转换相关方法:

  1. ofPattern(String pattern) :静态方法 , 返 回 一 个 指 定 字 符 串 格 式 的DateTimeFormatter
  2. format(TemporalAccessor t):格式化一个日期、时间,返回字符串
  3. parse(CharSequence text) :将指定格式的字符序列解析为一个日期、时间

日期转换基本演示:

@Test
public void test01() {
    // 初始化方式主要三种:
    //预定义的标准格式。如:
    //ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
    DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);
    // 格式化
    String dateStr = formatter.format(now);
    System.out.println(dateStr);
    // 解析
    TemporalAccessor date = formatter.parse("2022-04-26T21:05:35.224");
    System.out.println(date);
    //本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.LONG)
    DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT); // 22-4-26 下午9:13
    DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG); // 2022年4月26日 下午09时13分02秒
    DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);// 2022-4-26 21:13:02
    //DateTimeFormatter formatter4 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL);// 不支持localDateTime
    System.out.println(formatter1.format(now));
    System.out.println(formatter2.format(now));
    System.out.println(formatter3.format(now));
    LocalDate date1 = LocalDate.now();
    DateTimeFormatter formatter5 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL); // 2022年4月26日 星期二
    DateTimeFormatter formatter6 = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG); // 2022年4月26日
    DateTimeFormatter formatter7 = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM); // 2022-4-26
    DateTimeFormatter formatter8 = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT); // 22-4-26
    System.out.println(formatter5.format(date1));
    System.out.println(formatter6.format(date1));
    System.out.println(formatter7.format(date1));
    System.out.println(formatter8.format(date1));
    //自定义的格式。如:ofPattern(“yyyy-MM-dd HH:mm:ss”)  用的最多,随心所欲
    DateTimeFormatter formatter9 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 2022-04-26 21:22:10
    DateTimeFormatter formatter10 = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // 2022-04-26
    DateTimeFormatter formatter11 = DateTimeFormatter.ofPattern("HH:mm:ss"); // 21:22:10
    System.out.println(formatter9.format(now));
    System.out.println(formatter10.format(now));
    System.out.println(formatter11.format(now));
    TemporalAccessor parse1 = formatter9.parse("2022-04-26 21:22:10");
    System.out.println(parse1);
}


其他API的简单介绍

关于其他的API就简单说明下功能,具体细节可以查看API文档。

java.time.ZoneId :该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris

java.time.ZonedDateTime :一个在ISO-8601日历系统时区的日期时间,如 2007-12-03T10:15:30+01:00 Europe/Paris。其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等

java.time.Clock :使用时区提供对当前即时、日期和时间的访问的时钟。

java.time.Duration :持续时间,用于计算两个“时间”间隔

java.time.Period :用于计算两个“日期”间隔

java.time.temporal.TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。

java.time.temporal.TemporalAdjusters :该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster 的实现。



新类与老日期处理类的转换

新转旧旧转新
java.time.Instant与java.util.DateDate.from(instant)date.toInstant()
java.time.Instant与java.sql.TimestampTimestamp.from(instant)timestamp.toInstant()
java.time.ZonedDateTime与java.util.GregorianCalendarGregorianCalendar.from(zonedDateTime)cal.toZonedDateTime()
java.time.LocalDate与java.sql.TimeDate.valueOf(localDate)date.toLocalDate()
java.time.LocalTime与java.sql.TimeDate.valueOf(localTime)time.toLocalTime()
java.time.LocalDateTime与java.sql.TimestampTimestamp.valueOf(localDateTime)timestamp.toLocalDateTime()
java.time.ZoneId与java.util.TimeZoneTimezone.getTimeZone(id)timeZone.toZoneId()
java.time.format.DateTimeFormatter与java.text.DateFormatformatter.toFormat()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值