【从零开始学Java第64期】JDK8 关于日期时间的新特性_java 时间jdk

给大家的福利

零基础入门

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

同时每个成长路线对应的板块都有配套的视频提供:

在这里插入图片描述

因篇幅有限,仅展示部分资料

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以点击这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

7. with()方法

LocalDateTime中有一个通用的with()方法,允许我们进行更复杂的运算,比如获取当月或下个月的第一天、最后一天、第一个周一等操作。

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;

public class Demo14 {

	public static void main(String[] args) {
        //获取本月的第一天0:00时刻:
        LocalDateTime firstDay = LocalDate.now().withDayOfMonth(1).atStartOfDay();
        System.out.println("firstDay="+firstDay);

        //获取本月的最后1天:
        LocalDate lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
        System.out.println("lastDay="+lastDay);

        //获取下个月的第1天:
        LocalDate nextMonthFirstDay = LocalDate.now().with(TemporalAdjusters.firstDayOfNextMonth());
        System.out.println("nextMonthFirstDay="+nextMonthFirstDay);

        //获取本月的第1个周一
        LocalDate firstWeekday = LocalDate.now().with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
        System.out.println("firstWeekday="+firstWeekday);
	}

}

8. isBefore()与isAfter()方法

如果我们判断两个LocalDateTime的先后顺序,可以使用isBefore()、isAfter()方法。

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class Demo16 {

	public static void main(String[] args) {
		LocalDateTime now = LocalDateTime.now();
        LocalDateTime target = LocalDateTime.of(2022, 12, 25, 10, 15, 10);
        //判断A日期在B日期之前
        System.out.println("before?="+now.isBefore(target));
        
        //判断A日期在B日期之前
        System.out.println(LocalDate.now().isBefore(LocalDate.of(2023, 12, 19)));
        
        //判断A时间在B时间之后
        System.out.println(LocalTime.now().isAfter(LocalTime.parse("10:15:20")));
	}

}

9. Duration时间间隔和Period间隔天数

我们可以使用Duration表示两个时刻之间的时间间隔,用Period表示两个日期之间的间隔天数。

DurationPeriod的表示方法也符合ISO 8601的格式,它以P…T…的形式表示。P…T之间表示日期间隔,T后面表示时间间隔,如果是PT…的格式表示仅有时间间隔。

所以如果是两个LocalDateTime之间的差值,要使用Duration表示,形式为PT12H10M30S,意思是间隔12小时10分钟30秒。而两个LocalDate之间的差值用Period表示,形式为P1M21D,表示间隔1个月21天。

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;

public class Demo17 {

	public static void main(String[] args) {
		LocalDateTime start = LocalDateTime.of(2023, 05, 24, 13, 15, 20);
        LocalDateTime end = LocalDateTime.of(2025, 11, 8, 19, 25, 30);
        //计算两个时间的间隔
        Duration d = Duration.between(start, end);
        //PT21582H10M10S,间隔21582小时10分10秒
        System.out.println("duration="+d); 

        //计算两个日期的间隔
        Period p = LocalDate.of(2022, 12, 11).until(LocalDate.of(2025, 2, 22));
        //P2Y2M11D,间隔2个月11天
        System.out.println("period="+p); 
        
        //我们也可以使用ofXxx()或parse()方法直接创建Duration
        //10hours
        Duration d1 = Duration.ofHours(10);
        //2day,4hours,5minutes
        Duration d2 = Duration.parse("P2DT4H5M"); 
        System.out.println("d1="+d1); 
        System.out.println("d2="+d2); 
	}

}

三. ZonedDateTime

1. 简介

我们知道,LocalDateTime表示本地日期和时间,如果我们要表示一个带时区的日期和时间,就需要使用ZonedDateTime了。ZonedDateTime相当于是LocalDateTime + ZoneId,其中ZoneId是java.time引入的新的时区类,它与旧的java.util.TimeZone是有区别的。在ZonedDateTime中也提供了plusDays()等加减操作,使用起来也非常地方便。

2. 创建方式

如果我们想要创建一个ZonedDateTime对象,可以有以下几种方法:

● 通过now()方法返回ZonedDateTime对象;

● 通过给LocalDateTime附加ZoneId获取。

接下来我们就通过一些具体的案例来给大家展示一下ZonedDateTime到底是怎么创建的

2.1 now()方法

我们先来看看通过now()方法如何创建一个ZonedDateTime对象。

import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Demo18 {

	public static void main(String[] args) {
		//获取默认时区的时间对象
		ZonedDateTime zdt1 = ZonedDateTime.now(); 
		System.out.println("zdt1="+zdt1); 
		
		 //获取指定时区的时间对象
        ZonedDateTime zdt2 = ZonedDateTime.now(ZoneId.of("America/New\_York"));
        System.out.println("zdt2="+zdt2); 
	}

}

在这个案例中,我们获得的两个ZonedDateTime对象,它们的时区虽然不同,但时间都是同一时刻的,如果毫秒数不同是在执行语句时有一点时间差。

2.2 附加ZoneId

我们再来通过给LocalDateTime附加ZoneId的方式来获取一个LocalDateTime对象。

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

public class Demo19 {

	public static void main(String[] args) {
		LocalDateTime ldt = LocalDateTime.of(2023, 1, 25, 10, 15, 11);
		//获取默认时区的时间对象
		ZonedDateTime zdt1 = ldt.atZone(ZoneId.systemDefault());
		System.out.println("zdt1=" + zdt1);

		//获取指定时区的时间对象
		ZonedDateTime zdt2 = ldt.atZone(ZoneId.of("America/New\_York"));
		System.out.println("zdt2=" + zdt2);
	}

}

这种方式创建的ZonedDateTime对象,其日期和时间与LocalDateTime相同,但附加的时区不同,因此是两个不同的时刻。

3. 时区转换

有时候我们的项目中,需要将A时区的时间转换成B时区的时间,要在两个时区直接进行切换。以前的时候就需要我们自己计算,非得的麻烦且复杂,现在新的Java API中直接给我们带了负责时区转换的方法。比如withZoneSameInstant()方法,就可以将一个关联的时区转换到另一个时区,转换后的日期和时间也会相应调整。

import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Demo20 {
	public static void main(String[] args) {
		//将北京时间转为纽约时间
		//获取北京时区的当前时间
		//注意:这里的时区名字不能随便瞎写,否则会产生java.time.zone.ZoneRulesException: Unknown time-zone ID: Asia/Beijing
        ZonedDateTime zdt1 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
        System.out.println("zdt1=" + zdt1);
        
        //将当前时区的时间,转换为纽约时间
        ZonedDateTime zdt2 = zdt1.withZoneSameInstant(ZoneId.of("America/New\_York"));
		System.out.println("zdt2=" + zdt2);

        //转换为本地时间
		LocalDateTime ldt = zdt2.toLocalDateTime();
		System.out.println("ldt=" + ldt);
	}
}

注意:

时区的名字不能随便瞎写,否则会产生java.time.zone.ZoneRulesException: Unknown time-zone ID: Asia/Beijing,如下图所示:

而且在时区转换时,由于夏令时的存在,不同的日期转换结果也有可能是不同的,有可能会出现两次转换后有1小时的夏令时时差。我们以后涉及到时区时,尽量不要自己计算时差,否则难以正确处理夏令时。

四. DateTimeFormatter

1. 简介

我们在前面学习Date日期时间对象时,知道该对象默认输出的时间格式其实是不符合大多数的使用场景的,所以就需要我们对其进行格式化设置,比如通过printf()方法或SimpleDateFormat类来实现。但是当我们使用新的LocalDateTimeZonedDateTime需要进行格式化显示时,就要使用新的DateTimeFormatter类了。

SimpleDateFormat不同的是,DateTimeFormatter不但是不可变的对象,且还是线程安全的。在代码中,我们可以创建出一个DateTimeFormatter实例对象,到处引用。而之前的SimpleDateFormat是线程不安全的,使用时只能在方法内部创建出一个新的局部变量。

2. 创建方式

我们要想使用DateTimeFormatter,首先得创建出一个DateTimeFormatter对象,一般有如下两种方式:

● DateTimeFormatter.ofPattern(String pattern):pattern是待传入的格式化字符串;

● DateTimeFormatter.ofPattern(String pattern,Locale locale):locale是所采用的本地化设置。

3. 基本使用

了解了创建方式之后,我们就可以来看看该如何进行时间格式化了。

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Demo21 {

	public static void main(String[] args) {
		//获取默认的本地时间
		ZonedDateTime zdt = ZonedDateTime.now();
		//获取一个DateTimeFormatter对象,如果需要输出固定字符,可以用'xxx'表示,如'中国时间'
        var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss ZZZZ '中国时间'");
        System.out.println(formatter.format(zdt));

        //获取一个DateTimeFormatter对象,中国时区
        var zhFormatter = DateTimeFormatter.ofPattern("yyyy MMM dd EE HH:mm:ss", Locale.CHINA);
        System.out.println(zhFormatter.format(zdt));
        //改变默认的显示格式,用指定的格式显示
        //System.out.println(DateTimeFormatter.ISO\_DATE.format(zdt));

        //获取一个DateTimeFormatter对象,美国时区
        var usFormatter = DateTimeFormatter.ofPattern("E, MMMM/dd/yyyy HH:mm:ss", Locale.US);
        //System.out.println(usFormatter.format(zdt));
        //改变默认的显示格式
        System.out.println(DateTimeFormatter.ISO_DATE_TIME.format(zdt));
	}

}

当我们在格式化字符串时,如果需要输出一些固定的字符,可以用’xxx’的形式来表示。

另外我们在调用System.out.println()方法对一个ZonedDateTime,或者LocalDateTime实例进行打印时,实际上调用的是它们的toString()方法。默认的toString()方法,显示的字符串是按照ISO 8601格式显示的,我们可以通过DateTimeFormatter预定义的几个静态变量来引用。

五. Instant

1. 简介

在之前给大家讲过,计算机中存储的当前时间,其实就是一个不断递增的整数,即从1970年1月1日0分0秒开始以来不断递增的一个整数值。要想获取这个整数值,我们可以使用System.currentTimeMillis()方法,该方法会返回一个long型的毫秒值,这就是当前时间的时间戳!

现在,我们其实还可以使用Instant.now()来获取当前的时间戳,效果和System.currentTimeMillis()类似。但Instant获取的时间戳更为精确,内部采用了两种时间精度,分别是秒和纳秒。

另外Instant还提供了plusXxxminusXxx增减方法,方便我们进行时间的操作。且Instant作为时间戳对象,我们还可以给它附加上一个时区,创建出对应的ZonedDateTime对象。也可以给它关联上指定的ZoneId,得到对应的ZonedDateTime,进而获得对应时区的LocalDateTime。所以我们可以在LocalDateTime、ZoneId、Instant、ZonedDateTime之间互相转换。

2. 使用方法

接下来我们看看Instant的用法。

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Demo22 {

	public static void main(String[] args) {
		//获取当前时间的时间戳
		long currentTimeMillis = System.currentTimeMillis();
		System.out.println("currentTimeMillis毫秒级时间戳="+currentTimeMillis);

		//获取当前时间的时间戳
		Instant now = Instant.now();
		System.out.println("now时刻="+now);
		// 秒
        System.out.println("秒级时间戳="+now.getEpochSecond()); 
        // 毫秒
        System.out.println("毫秒级时间戳="+now.toEpochMilli());
		
		//用指定的时间戳创建Instant对象
		Instant ins = Instant.ofEpochSecond(1676262418);
		//获取所在时区的ZonedDateTime对象
		ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault());
		System.out.println("zdt="+zdt); 
	}

}

六. 新旧时间API的转换

1. 简介


现在我们知道,在Java中,关于日期和时间的API其实有两套,一套旧的,一套新的。这两套API以JDK 8为分割线,此前的属于旧版API,此后的属于新版API

● 旧版API:定义在java.util包中,主要包括Date、Calendar和TimeZone几个类;

● 新版API:JDK 8之后引入,定义在java.time包中,主要包括LocalDateTime、ZonedDateTime、ZoneId、DateTimeFormatter、Instant等。

这时有些同学就会好奇,这两套时间API我们在开发时该怎么选择?

1、如果大家的项目属于是一个新开发的项目,且你们的Java版本在JDK 8以上,那就采用新版的API吧。

2、但是如果你们的项目涉及到遗留代码,是对旧的项目进行维护或改造,很多遗留代码仍然在使用旧的API,建议大家还是不要改变原有的选择,请继续使用旧版API。

3、但是如果你们的项目环境已经从低版本的JDK切换到了高本版的JDK,且你们公司要求对项目进行升级改造,我们能不能在新旧两种API之间进行转换呢? 其实也是可以的,今天就给大家讲一下如何在新旧两套API之间互相转换。

2. 旧转新

首先我们来看看旧的API是如何转成新的API的。比如我们想把旧式的Date或Calendar转换为新的API对象,可以通过toInstant()方法转换为Instant对象,然后再继续转换为ZonedDateTime,实现代码如下:

import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;

public class Demo24 {

	public static void main(String[] args) {
		//将旧版API中的Date,转为新版API中的Instant对象
		Instant instant = new Date().toInstant();
		System.out.println("instant="+instant);
		
		//将旧版API中的Calendar,转为新版API中的Instant,然后再进一步转为新版的ZonedDateTime:
		Calendar calendar = Calendar.getInstance();
		Instant instant2 = calendar.toInstant();
		ZonedDateTime zdt = instant2.atZone(calendar.getTimeZone().toZoneId());
		System.out.println("zdt="+zdt); 
	}

}

3. 新转旧

旧版API可以转换成新版API,同时我们也可以将新班API转成旧版的API,已实现与原有系统的兼容。如果要实现这一目标,我们需要借助long型的时间戳做一个“中转”,具体实现如下:

import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class Demo25 {

	public static void main(String[] args) {
		//新版API中的ZonedDateTime,先转为long类型
		ZonedDateTime zdt = ZonedDateTime.now();
		//获取秒级时间戳,转为long类型
		long ts = zdt.toEpochSecond() \* 1000;
		System.out.println("ts=" + ts);

		//然后将long类型,转为旧版API中的Date
		Date date = new Date(ts);
		System.out.println("date=" + date);
		
		//将long类型转为旧版API中的Calendar对象
		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.setTimeZone(TimeZone.getTimeZone(zdt.getZone().getId()));
		calendar.setTimeInMillis(zdt.toEpochSecond() \* 1000);
		System.out.println("calendar=" + calendar);
	}

}


七. 结语

至此,就把日期的格式化操作给大家讲解完毕了,今天的内容比较多且很实用,最后我们总结一下今日重点

● JDK 8中引入了新的日期和时间API,它们是不变类,默认按ISO 8601标准格式化和解析;

● 使用LocalDateTime可以非常方便地对日期和时间进行加减、调整日期和时间,且总是返回新对象;

一、网安学习成长路线图

网安所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
在这里插入图片描述

二、网安视频合集

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
在这里插入图片描述

三、精品网安学习书籍

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
在这里插入图片描述

四、网络安全源码合集+工具包

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
在这里插入图片描述

五、网络安全面试题

最后就是大家最关心的网络安全面试题板块
在这里插入图片描述在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以点击这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

可以搞点实战案例来学习。
在这里插入图片描述

五、网络安全面试题

最后就是大家最关心的网络安全面试题板块
在这里插入图片描述在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以点击这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值