Java8 新的日期/时间API操作和示例

目录

1、Java8 新的日期/时间API操作

(1)LocalDate、LocalTime 和 LocalDateTime 时间类

(2)Instant、Duration 和 Period 时间间隔类

(3)Temporal、TemporalField 和 ChronoField

(4)时间、日期设置和修改

(5)时间、日期解析和格式化

(6)不同时区的时间处理

2、日期/时间 API 使用示例

(1)通过 Java 的基本语法来实现万年历

(2)Java 获取一年中所有的周六和周日


1、Java8 新的日期/时间API操作

        Java 旧的日期时间类 java.util.Date java.util.Calendar 存在可变性,导致在多线程环境下使用时会存在线程安全问题。在新的 API 中,几乎所有的类都是不可变的,从而保证了线程安全性。此外,旧的 API 命名不清晰,使得日期时间处理相对困难。新的 API 使用了更清晰和直观的命名,使得代码更易读、更易写。

(1)LocalDate、LocalTime 和 LocalDateTime 时间类

        LocalDate LocalTime Java java.time 包下的两个日期时间类,用于分别表示日期和时间,它们不包含时区信息,仅仅表示日期或时间部分//时间和日期可以进行分开

        LocalDate:用于表示日期,包含年、月、日,但不包含时、分、秒和时区信息,可以使用 now() 方法获取当前日期,或者使用 of() 方法指定特定的年、月、日创建实例。

// 获取当前日期
LocalDate currentDate = LocalDate.now();// 创建特定日期
LocalDate specificDate = LocalDate.of(2023, 12, 31);// 获取年、月、日
int year = currentDate.getYear();
int month = currentDate.getMonthValue();
int day = currentDate.getDayOfMonth();

        LocalTime:用于表示时间,包含时、分、秒和纳秒,但不包含日期和时区信息。也可以使用 now() 方法获取当前时间,或者使用 of() 方法指定特定的时、分、秒创建实例。

// 获取当前时间
LocalTime currentTime = LocalTime.now();// 创建特定时间
LocalTime specificTime = LocalTime.of(12, 30, 0);// 获取时、分、秒
int hour = currentTime.getHour();
int minute = currentTime.getMinute();
int second = currentTime.getSecond();

        LocalDateTime:是 LocalDate 和 LocalTime 的合体。它同时表示了日期和时间,但不带有时区信息,你可以直接创建,也可以通过合并日期和时间对象构造,如下所示。

// 获取当前日期时间
LocalDateTime currentDateTime = LocalDateTime.now();// 创建特定日期时间
LocalDateTime specificDateTime = LocalDateTime.of(2023, 12, 31, 12, 30, 0);// 使用 LocalDate 和 LocalTime 构建 LocalDateTime
LocalDate localDate = LocalDate.of(2023, 12, 31);
LocalTime localTime = LocalTime.of(12, 30);
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);

(2)Instant、Duration 和 Period 时间间隔类

        Instant、Duration Period Java 中用于处理时间间隔和持续时间的类。

        Instant:用于表示时间线上的一个具体点,通常表示自 1970-01-01T00:00:00Z(即协调世界时)开始经过的秒数和纳秒数。可以使用 now() 方法获取当前的时间点,或者使用 ofEpochSecond()、ofEpochMilli() 等方法指定特定的秒数或毫秒数创建实例。

// 获取当前时间点
Instant currentInstant = Instant.now();// 创建特定时间点
Instant specificInstant = Instant.ofEpochSecond(1630452000); // 2022-09-01T00:00:00Z

        需要特别强调的一点,Instant 的设计初衷是为了便于机器使用。它包含的是由秒及纳秒所构成的数字。所以,它无法处理那些我们非常容易理解的时间单位。比如下面这段语句:

int hour = Instant.now().get(ChronoField.HOUR_OF_DAY);

        它会抛出如下异常:

        Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay

        Duration:用于表示时间段的持续时间,包含了以秒和纳秒为单位的时间间隔。可以使用 between() 方法计算两个时间点之间的持续时间,或者使用 ofSeconds()、ofMinutes() 等方法指定特定的时间间隔创建实例。

// 计算两个时间/时间点之间的持续时间:不支持使用LocalDate入参
Duration instantDuration = Duration.between(startInstant, endInstant);
Duration timeDuration = Duration.between(startTime, endTime);

        Period:用于表示日期之间的时间段,以年、月、日为单位。可以使用 between() 方法计算两个日期之间的时间段,或者使用 of() 方法指定特定的年、月、日创建实例。

// 计算两个日期之间的时间段:不支持时间
Period period = Period.between(startDate, endDate);// 创建特定时间段
Period specificPeriod = Period.ofYears(2); // 2年的时间段

(3)Temporal、TemporalField 和 ChronoField

        对于一套新的 API,我们常常会为一些陌生的类而感到困惑,比如 Temporal、TemporalField 和 ChronoField。

        Temporal Java Date Time API 中的一个接口,它是所有日期和时间类的基本接口,定义了对日期时间操作的通用方法//定义一个通用接口的好处是,它的类型可以对所有的子类类型进行抽象,使一套模板方法具有普适性

        TemporalField 是一个接口,它定义了如何访问 Temporal 对象某个字段的值ChronoField 枚举实现了这一接口,所以你可以很方便地使用 get 方法得到枚举元素的值,如下所示://ChronoField 是一个枚举类

// 通过 TemporalField 获取字段值
int month = LocalDate.now().get(ChronoField.MONTH_OF_YEAR);
int hour = LocalTime.now().get(ChronoField.CLOCK_HOUR_OF_DAY);
int week = LocalDateTime.now().get(ChronoField.ALIGNED_WEEK_OF_MONTH);

(4)时间、日期设置和修改

        在 Java 中,可以使用 LocalDateTime 类来修改日期时间的各个部分。LocalDateTime 是不可变的,因此修改操作会返回一个新的实例,而不是修改原始实例

        以下是一些常见的 LocalDateTime 时间修改操作示例:

        增减年、月、日、时、分、秒、纳秒:

    LocalDateTime currentDateTime = LocalDateTime.now();// 增加或减少年、月、日、时、分、秒、纳秒LocalDateTime futureDateTime = currentDateTime.plusYears(1).minusMonths(3).plusDays(7).plusHours(2).minusMinutes(30).plusSeconds(15).minusNanos(500000000);// 或者使用带有时间单位的方法LocalDateTime modifiedDateTime = currentDateTime.plus(1, ChronoUnit.YEARS).minus(3, ChronoUnit.MONTHS).plus(7, ChronoUnit.DAYS).plus(2, ChronoUnit.HOURS).minus(30, ChronoUnit.MINUTES).plus(15, ChronoUnit.SECONDS).minus(500000000, ChronoUnit.NANOS);

        设置特定的年、月、日、时、分、秒、纳秒:

    LocalDateTime currentDateTime = LocalDateTime.now();// 设置特定的年、月、日、时、分、秒、纳秒LocalDateTime newDateTime = currentDateTime.withYear(2025).withMonth(10).withDayOfMonth(15).withHour(18).withMinute(45).withSecond(30).withNano(0);

       使用 TemporalAdjuster 对象对日期进行灵活处理:

        TemporalAdjusterJava Date Time API 中的一个接口,用于根据特定的规则调整日期时间,例如,将日期调整为下一个工作日、月末、下个星期等。通过 TemporalAdjusters 类的静态工厂方法可以使用大量预定义的 TemporalAdjuster,代码如下所示:

LocalDateTime now = LocalDateTime.now();
LocalDateTime dayOfWeek = now.with(TemporalAdjusters.dayOfWeekInMonth(1, DayOfWeek.SUNDAY));
LocalDateTime lastDayOfMonth = now.with(TemporalAdjusters.lastDayOfMonth());

       使用自定义的 TemporalAdjuster 对象:

        正如我们看到的,使用 TemporalAdjuster 可以进行更加复杂的日期操作,那么如果没有找到符合要求的 TemporalAdjuster,我们也可以创建自定义的 TemporalAdjuster方法很简单,只需要实现 TemporalAdjuster 接口即可,代码如下所示:

public class NextWorkingDay implements TemporalAdjuster {@Overridepublic Temporal adjustInto(Temporal temporal) {DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));int daysToAdd = 1;if (dayOfWeek == DayOfWeek.FRIDAY) {daysToAdd = 3; //星期五至星期一,加3天} else if (dayOfWeek == DayOfWeek.SATURDAY) {daysToAdd = 2; //星期六至星期一,加2天}//其他时间都是+1天return temporal.plus(daysToAdd, ChronoUnit.DAYS);}public static void main(String[] args) {LocalDate date = LocalDate.now();TemporalAdjuster adjuster = new NextWorkingDay();LocalDate nextWorkingDay = date.with(adjuster);}
}

        TemporalAdjuster 接口只声明了单一的一个方法:adjustInto,因此它也是一个函数式接口。

(5)时间、日期解析和格式化

        DateTimeFormatter Java Date Time API 中用于格式化和解析日期时间对象的类。

        格式化日期时间对象为字符串:

LocalDateTime dateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = dateTime.format(formatter);

        解析字符串为日期时间对象:

String strDateTime = "2023-12-31 15:30:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime parsedDateTime = LocalDateTime.parse(strDateTime, formatter);

        预定义的 DateTimeFormatter:

        Java 提供了一些预定义的 DateTimeFormatter,方便进行常见格式化和解析操作:

  • DateTimeFormatter.ISO_LOCAL_DATEISO 格式的日期,例如:"2023-12-31"
  • DateTimeFormatter.ISO_LOCAL_TIMEISO 格式的时间,例如:"15:30:00"
  • DateTimeFormatter.ISO_LOCAL_DATE_TIMEISO 格式的日期时间,例如:"2023-12-31T15:30:00"
  • DateTimeFormatter.BASIC_ISO_DATE:基本的 ISO 格式日期,例如:"20231231"

        使用示例:

//格式化
String format = localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);//解析
LocalDateTime parse = LocalDateTime.parse("2023-12-27T13:39:07", DateTimeFormatter.ISO_LOCAL_DATE_TIME);

(6)不同时区的时间处理

        时区的处理是新版日期和时间 API 新增加的重要功能,使用新版日期和时间 API 时区的处理被极大地简化了。新的 java.time.zoneId 类是老版 java.util.Timezone 的替代品。zoneId 类跟其他日期类一样,也是无法修改的。

        获取默认时区和所有可用的时区:

//获取默认时区
ZoneId defaultZone = ZoneId.systemDefault(); // Asia/Shanghai//获取所有可用的时区
Set<String> allZoneIds = ZoneId.getAvailableZoneIds();

        每个特定的 zoneId 对象都是一个地区 ID 标识,地区 ID 都为 “{区域/城市}” 的格式,如:"Asia/Shanghai",这些地区集合的设定都由英特网编号分配机构(IANA)的时区数据库提供。

        创建特定的时区实例:

ZoneId newYorkZone = ZoneId.of("America/New_York");
ZoneId londonZone = ZoneId.of("Europe/London");
ZoneId tokyoZone = ZoneId.of("Asia/Tokyo");

        将时区应用到日期时间对象:

LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime newYorkDateTime = localDateTime.atZone(newYorkZone);
ZonedDateTime londonDateTime = localDateTime.atZone(londonZone);
ZonedDateTime tokyoDateTime = localDateTime.atZone(tokyoZone);//默认时区
ZoneId defaultZone = ZoneId.systemDefault();
ZonedDateTime defaultZoneTime = localDateTime.atZone(defaultZone);
//defaultZoneTime内容:
2023-12-28T09:29:30.277+08:00[Asia/Shanghai]

        在不同时区之间转换时间:

ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
ZonedDateTime londonTime = tokyoTime.withZoneSameInstant(ZoneId.of("Europe/London"));

        ZoneId 可以用于将本地日期时间转换为特定时区的日期时间,并且允许在不同时区之间进行时间转换。它是处理全球时区的重要工具,在跨越不同时区的应用程序中特别有用。

        在示例中,带时区信息的时间使用 ZonedDateTime 进行表示,那么 ZonedDateTime、LocaleDate、LocalTime、LocalDateTime 以及 ZoneId 之间有什么差异呢?

        下边一张图,可以清晰的解释它们之间的区别:

2、日期/时间 API 使用示例

(1)通过 Java 的基本语法来实现万年历

        通过年份和月份的天数进行万年历计算:

import java.util.Scanner;/*** @author swadian2008*/
public class DateUtils {public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("请输入年:");int year = sc.nextInt();System.out.println("请输入月份:");int month = sc.nextInt();//1.计算1900.1.1到输入年的天数int dayOfYear = 0;for (int i = 1900; i < year; i++) {if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) { // 闰年dayOfYear += 366;} else {dayOfYear += 365;}}//2.计算1月到输入月的天数int dayOfMonth = 0;for (int i = 1; i < month; i++) {switch (i) {case 1:case 3:case 5:case 7:case 8:case 10:case 12:dayOfMonth += 31;break;case 4:case 6:case 9:case 11:dayOfMonth += 30;break;case 2:if ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0)) {dayOfMonth += 29;} else {dayOfMonth += 28;}break;}}//3.获取输入月的天数int day = 0;switch (month) {case 1:case 3:case 5:case 7:case 8:case 10:case 12:day = 31;break;case 4:case 6:case 9:case 11:day = 30;break;case 2:if ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0)) {day = 29;} else {day = 28;}break;}//4.计算星期int allDay = dayOfYear + dayOfMonth + 1;int week = allDay % 7; // 计算余数在星期中的位置int count = 0;// 计数器,记录日期的空格System.out.println("星期日\t星期一\t星期二\t星期三\t星期四\t星期五\t星期六");//5.打印空格for (int i = 1; i <= week; i++) {System.out.print("\t\t\t");count++;}//6. 打印日历for (int i = 1; i <= day; i++) {if (i < 10) { // 为了格式化System.out.print(i + "\t\t\t");} else {System.out.print(i + "\t\t");}count++;//若记录数是七的倍数,换行输出if (count % 7 == 0) {System.out.println();}}}
}

        输出结果图示:

(2)Java 获取一年中所有的周六和周日

        下边的示例中使用了一个Map来收集一年当中的周六和周日的日期,统计年份可以根据需要进行调节,下边代码也适合用来处理自定义节假日的需求:

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.ChronoField;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.stream.Collectors;
import static java.time.temporal.TemporalAdjusters.firstInMonth;/*** @author swadian2008*/
public class WeekDay {public static void main(String[] args) {//收集2023年所有的周六和周日int year = 2023;int month = 1;int day = 1;//按月份统计周六和周日Map<Integer, List<Integer>> weekMap = new HashMap<>(12);//创建代表一年中第一天的LocalDate对象LocalDate localDate = LocalDate.of(year, month, day);//收集所有星期六collectDayOfWeek(weekMap, localDate, DayOfWeek.SATURDAY, year);//收集所有星期日collectDayOfWeek(weekMap, localDate, DayOfWeek.SUNDAY, year);Map<Integer, List<Integer>> sortWeekMap = weekMap.entrySet().stream().collect(Collectors.toMap(Entry::getKey, r -> r.getValue().stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList())));for (Entry<Integer, List<Integer>> map : sortWeekMap.entrySet()) {System.out.println(map.getKey() + "月:" + map.getValue().toString());}}private static void collectDayOfWeek(Map<Integer, List<Integer>> weekMap, LocalDate localDate, DayOfWeek dayOfWeek, int year) {//获取一年中的第一个指定日期(星期六或星期日)LocalDate weekday = localDate.with(firstInMonth(dayOfWeek));while (weekday.getYear() == year) {int month = weekday.get(ChronoField.MONTH_OF_YEAR);int day = weekday.getDayOfMonth();List<Integer> integers = weekMap.get(month);if (Objects.nonNull(integers) && !integers.isEmpty()) {integers.add(day);} else {integers = new ArrayList<>();integers.add(day);weekMap.put(month, integers);}//向后迭代一个星期weekday = weekday.plus(Period.ofDays(7));}}
}

        输出结果:

1月:[1, 7, 8, 14, 15, 21, 22, 28, 29]
2月:[4, 5, 11, 12, 18, 19, 25, 26]
3月:[4, 5, 11, 12, 18, 19, 25, 26]
4月:[1, 2, 8, 9, 15, 16, 22, 23, 29, 30]
5月:[6, 7, 13, 14, 20, 21, 27, 28]
6月:[3, 4, 10, 11, 17, 18, 24, 25]
7月:[1, 2, 8, 9, 15, 16, 22, 23, 29, 30]
8月:[5, 6, 12, 13, 19, 20, 26, 27]
9月:[2, 3, 9, 10, 16, 17, 23, 24, 30]
10月:[1, 7, 8, 14, 15, 21, 22, 28, 29]
11月:[4, 5, 11, 12, 18, 19, 25, 26]
12月:[2, 3, 9, 10, 16, 17, 23, 24, 30, 31]

        至此,全文结束。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/309265.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

汇编语言学习中的Dosbox自动配置方法

学到期末才发现可以自动配置 一、先找到dosbox的下载/安装路径 二、打开其下的Dosbox *.**(这里是版本号) Options.bat 三、在其打开的文件的最下面输入你经常打开dosbox要输入的内容 例如&#xff1a; mount c e:\masm c:

二叉树顺序结构与堆的概念及性质(c语言实现堆)

上次介绍了树&#xff0c;二叉树的基本概念结构及性质&#xff1a;二叉树数据结构&#xff1a;深入了解二叉树的概念、特性与结构 今天带来的是&#xff1a;二叉树顺序结构与堆的概念及性质&#xff0c;还会用c语言来实现堆 文章目录 1. 二叉树的顺序结构2.堆的概念和结构3.堆…

C++提高编程二(STL、Vector容器、string字符串)

文章目录 STL容器算法迭代器初识Vector存放自定义数据类型Vector容器嵌套容器string构造函数string赋值操作string字符串拼接string查找和替换string字符串比较string字符存取string插入和删除string子串 STL STL&#xff08;Standard Template Library&#xff09;&#xff0…

【多传感器融合导航论文阅读】

多传感器融合导航论文积累 知识点总结因子图一致因子图 文献阅读笔记[IF 18.6] 知识点总结 因子图 Factor Graph 是概率图的一种&#xff0c;是对函数因子分解的表示图&#xff0c;一般内含两种节点&#xff0c;变量节点和函数节点。 因子图存在着&#xff1a;两类节点&#…

css 用多个阴影做出光斑投影的效果 box-shadow

css 用多个阴影做出光斑投影的效果 box-shadow 你首先需要知道的一点是 box-shadow 可以接收多个值&#xff0c;也就是可以设置多个阴影&#xff0c;这样就可以做一个类似光斑投影的效果。 一、效果 二、代码 里面用到了我一些 scss 工具方法&#xff0c;不过不影响&#xf…

3D视觉-结构光测量-多线结构光测量

工作原理 多线结构光测量在测量方式上类似上述线结构光测量&#xff0c;但是两者也有着一些明显的差别。这种形式的结构光测量&#xff0c;也常常被成为面结构光测量。首先激光器发出电光源通过通过光栅的调制产生多个切片光束&#xff0c;这些切片光束照射到待测物体表面后形成…

C++线性表

线性表的定义及其运算 线性表是一种最简单、最基本也是最常用的线性结构。在线性结构中&#xff0c;数据元素之间存在一个对一个的线性关系&#xff0c;数据元素“一个接一个地排列”。在一个线性表中&#xff0c;数据元素的类型是相同的&#xff0c;或者说&#xff0c;线性表…

Git基础学习_p1

文章目录 一、前言二、Git手册学习2.1 Git介绍&前置知识2.2 Git教程2.2.1 导入新项目2.2.2 做更改2.2.3 Git追踪内容而非文件2.2.4 查看项目历史2.2.5 管理分支&#x1f53a;2.2.6 用Git来协同工作2.2.7 查看历史 三、结尾 一、前言 Git相信大部分从事软件工作的人都听说过…

shell编程一

shell 定义 Shell 也是一种程序设计语言&#xff0c;它有变量&#xff0c;关键字&#xff0c;各种控制语句&#xff0c;有自己的语法结构&#xff0c;利用shell程序设计语 可以编写功能强、代码简短的程序 #! Shebang 定义解释器 shell的分类和切换 # cat /etc/shells /bin/sh…

win部署stable-diffusion

win部署stable-diffusion 1.环境2.模型3.使用4.效果 1.环境 首先下载stable-diffusion-webui&#xff0c;这个包了一层ui&#xff0c;特别好用。 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git然后搭建conda环境。 这里的pytorch&#xff0c;自己去…

鸿蒙HarmonyOS-带笔锋手写板(三)

笔者用ArkTS 写了一个简单的带笔锋的手写板应用&#xff0c;并且可以将手写内容保存为图片。 一、效果图 手写效果如下&#xff08;在鸿蒙手机模拟器上运行&#xff0c;手写时反应可能会有点慢&#xff09; 二、实现方法 参考文章&#xff1a; 支持笔锋效果的手写签字控件_a…

在Linux上搭建Maven仓库的实战教程

引言 在Java开发中&#xff0c;Maven作为项目构建和依赖管理的重要工具&#xff0c;其仓库的搭建至关重要。本文将手把手教你如何在Linux系统上安装并配置Nexus Repository Manager 3&#xff08;简称Nexus 3&#xff09;&#xff0c;从而创建一个私有的Maven仓库。 步骤一&a…