首页IT科技Java 8 Time API

Java 8 Time API

时间2025-04-29 18:13:23分类IT科技浏览8384
导读:Java 8 系列文章 持续更新中...

Java 8 系列文章 持续更新中

日期时间API 也是Java 8重要的更新之一              ,Java从一开始就缺少一致的日期和时间方法                    ,Java 8 Date Time API是Java核心API的一个非常好的补充             。

为什么需要新的日期时间API

Java中现有的与日期和时间相关的类存在一些问题:

日期时间类的定义不一致       ,在java.util和java.sql包中都有Date类                     。同样       ,格式化和解析类是在java.text包中定义的       。 java.util.Date同时包含日期和时间值                    ,而java.sql.Date只包含日期值             ,把它放在java.sql包中是没有意义的             。而且这两个类的名称相同       ,这本身就是一个非常糟糕的设计                    。 没有为时间             、时间戳                     、格式化和解析明确定义的类       。我们有java.text.DateFormat抽象类用于解析和格式化                     ,通常使用SimpleDateFormat类解析和格式化       。 所有Date类都是可变的             ,所以它们不是线程安全的,这也是JavaDate和Calendar类最大的问题之一                    。 Date类不提供国际化                     ,不支持时区              。虽然引入了java.util.Calendar和java.util.TimeZone                    ,但是它们也存在上面的问题       。

在Date和Calendar类中定义的方法还有一些其他的问题,但是上面的问题清楚地表明              ,Java中需要一个健壮的日期时间API                    。这就是为什么 Joda Time 可以成为Java 日期时间高质量的替代品              。

Java 8日期时间设计原则

Java 8日期时间API是基于 JSR-310 规范实现的。目的是为了解决遗留日期时间实现中的所有缺陷                    。新的日期时间API的一些设计原则如下:

不变性:新的日期时间API中的所有类都是不可变的                    ,适用于多线程环境                     。

关注点分离:新的日期时间API明确区分了人类可读的日期       、时间和机器时间(Unix时间戳)       ,它为Date             、Time                    、DateTime       、Timestamp       、Timezone 等定义单独的类。

清晰性:所有的类中都清晰地定义了方法              ,并执行相同的操作             。例如                    ,要获取当前时间实例可以用now()方法       ,在所有这些类中都定义了format()和parse()方法       ,而不是为它们单独定义一个类                     。

所有类都使用工厂模式策略模式来更好地操作       。一旦您使用了其中一个类中的方法                    ,使用其他类并不困难             。

实用的操作:所有新的日期时间API类都常见的方法             ,比如加                    、减              、格式化       、解析                    、在日期/时间中获取单独的部分等等                    。

可扩展:新的日期时间API可以在ISO-8601日历系统上工作       ,但是我们也可以在其他非ISO日历上使用它       。

Java 8日期时间API的包

Java8日期时间API由以下包组成       。

java.time:这是Java 8日期时间API的基本包                    。所有主要的基类都是这个包的一部分                     ,例如LocalDate              、LocalTime、LocalDateTime                    、Instant                     、Period、Duration等              。所有这些类都是不可变的和线程安全的       。大多数情况下             ,这些类足以处理常见的需求                    。 java.time.chrono:这个包为非ISO日历系统定义了通用API              。我们可以扩展AbstractChronology类来创建我们自己的日历系统。 java.time.format:这个包包含用于格式化和解析日期时间对象的类                    。大多数时候我们不会直接使用它们,因为java.time包中的日期时间类已经提供了格式化和解析方法                     。 java.time.temporal:这个包包含temporal对象                     ,我们可以使用它来找出与日期/时间对象相关的特定日期或时间。例如                    ,我们可以使用它们来查找一个月的第一天或最后一天             。您可以很容易地识别这些方法,因为它们的格式总是withXXX                     。 java.time.zone:这个包包含用于支持不同时区及其规则的类       。

Java 8日期时间API类的示例

下面通过一些日期时间API类的示例              ,来更好的了解Java 8日期时间API

1.LocalDate

LocalDate是一个不可变的日期类                    ,它以yyyy-MM-dd的默认格式表示日期             。可以使用now()方法来获取当前日期       ,还可以提供年             、月和日期的输入参数来创建LocalDate实例                    。

这个类为now()提供了一个重载方法              ,在这里可以传递ZoneId来获取特定时区中的日期       。这个类提供了与java.sql.Date相同的功能       。

// 当前日期 LocalDate today = LocalDate.now(); System.out.println("当前日期=" + today); // 通过提供年月日参数创建日期 LocalDate nowYear_1024 = LocalDate.of(2022, Month.OCTOBER, 24); System.out.println("参数日期=" + nowYear_1024); // 通过时区获取当前日期 LocalDate todayShanghai = LocalDate.now(ZoneId.of("Asia/Shanghai")); System.out.println("当前日期(CTT)=" + todayShanghai); // 从纪元日(1970-01-01)开始的第多少天 LocalDate dateFromBase = LocalDate.ofEpochDay(365); System.out.println("1970-01-01的第365天= " + dateFromBase); // 某年的第多少天 LocalDate hundredDay2022 = LocalDate.ofYearDay(2022, 100); System.out.println("2022年的第100天=" + hundredDay2022);

运行之后结果如下:

当前日期=2022-10-26 特殊日期=2022-10-24 当前日期(CTT)=2022-10-26 1970-01-01的第365天= 1971-01-01 2022年的第100天=2022-04-10 2.LocalTime

LocalTime是一个不可变的时间类                    ,它以HH:mm:ss.SSS的默认格式表示时间                    。与LocalDate一样       ,这个类提供了时区支持       ,并可以通过传递小时                     、分钟和秒作为输入参数来创建实例              。

// 当前时间 LocalTime time = LocalTime.now(); System.out.println("当前时间=" + time); // 通过提供时分秒参数创建日期 LocalTime specificTime = LocalTime.of(12, 20, 25, 40); System.out.println("参数时间=" + specificTime); // 通过时区获取当前时间 LocalTime timeShanghai = LocalTime.now(ZoneId.of("Asia/Shanghai")); System.out.println("当前时间(CTT)=" + timeShanghai); // 从纪元日开始的第多少秒 LocalTime specificSecondTime = LocalTime.ofSecondOfDay(100); System.out.println("从纪元日开始的第100秒=" + specificSecondTime);

运行之后结果如下:

当前时间=15:39:18.948 参数时间=12:20:25.000000040 当前时间(CTT)=15:39:18.949 从0开始的第100秒=00:01:40 3.LocalDateTime

LocalDateTime是一个不可变的日期时间类                    ,它以yyyy-MM-ddTHH:mm:ss.SSS的默认格式表示时间日期       。它提供了一个工厂方法             ,该方法使用LocalDate和LocalTime作为参数创建LocalDateTime实例                    。

// 当前日期时间 LocalDateTime now = LocalDateTime.now(); System.out.println("当前日期时间=" + now); // 通过提供LocalDate和LocalTime参数创建日期时间 now = LocalDateTime.of(LocalDate.now(), LocalTime.now()); System.out.println("当前日期时间=" + now); // 通过提供年月日时分秒参数创建日期时间 LocalDateTime specificTime = LocalDateTime.of(2022, Month.OCTOBER, 24, 10, 24, 24); System.out.println("参数日期时间=" + specificTime); // 通过时区获取当前日期时间 LocalDateTime todayKolkata = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); System.out.println("当前日期时间(CTT)=" + todayKolkata); // 从纪元日开始的第多少秒 LocalDateTime dateFromBase = LocalDateTime.ofEpochSecond(100, 0, ZoneOffset.UTC); System.out.println("从纪元日开始的第100秒= " + dateFromBase);

运行之后结果如下:

当前日期时间=2022-10-26T15:51:59.070 当前日期时间=2022-10-26T15:51:59.071 参数日期时间=2022-10-24T10:24:24 当前日期时间(CTT)=2022-10-26T15:51:59.071 从纪元日开始的第100秒=1970-01-01T00:01:40

注意:以上例子通过输入参数创建实例时       ,如果输入了无效的参数name将会抛出java.time.DateTimeException

4.Instant

instant类用于处理机器可读的时间格式              。instant类将日期时间存储在unix时间戳中。

// 当期时间戳 Instant timestamp = Instant.now(); System.out.println("当期时间戳= "+timestamp); // 从纪元日开始的第多少毫秒 Instant specificTime = Instant.ofEpochMilli(timestamp.toEpochMilli()); System.out.println("从纪元日开始="+specificTime);

运行之后结果如下:

当期时间戳=2022-10-26T08:08:40.429Z 从纪元日开始=2022-10-26T08:08:40.429Z

Java8日期时间API类的实用方法

大多数日期时间类都会提供各种实用方法                     ,例如加/减天数       、周数             、月数等                    。还有一些其他实用方法可以使用时间调整器TemporalAdjuster调整日期             ,并计算两个日期之间的时间段                     。

LocalDate today = LocalDate.now(); //获取年份,判断年份是否是闰年 System.out.println("Year "+today.getYear()+" is Leap Year? "+today.isLeapYear()); //比较两个时间 System.out.println("Today is before 01/01/2023? "+today.isBefore(LocalDate.of(2023,1,1))); //通过LocalDate创建LocalDateTime System.out.println("Current Time="+today.atTime(LocalTime.now())); //加减操作 System.out.println("10 days after today will be "+today.plusDays(10)); System.out.println("3 weeks after today will be "+today.plusWeeks(3)); System.out.println("20 months after today will be "+today.plusMonths(20)); System.out.println("10 days before today will be "+today.minusDays(10)); System.out.println("3 weeks before today will be "+today.minusWeeks(3)); System.out.println("20 months before today will be "+today.minusMonths(20)); //时间调整器调整时间 System.out.println("First date of this month= "+today.with(TemporalAdjusters.firstDayOfMonth())); LocalDate lastDayOfYear = today.with(TemporalAdjusters.lastDayOfYear()); System.out.println("Last date of this year= "+lastDayOfYear); Period period = today.until(lastDayOfYear); System.out.println("Period Format= "+period); System.out.println("Months remaining in the year= "+period.getMonths());

运行之后结果如下:

Year 2022 is Leap Year? false Today is before 01/01/2023? true Current Time=2022-10-26T16:25:04.740 10 days after today will be 2022-11-05 3 weeks after today will be 2022-11-16 20 months after today will be 2024-06-26 10 days before today will be 2022-10-16 3 weeks before today will be 2022-10-05 20 months before today will be 2021-02-26 First date of this month= 2022-10-01 Last date of this year= 2022-12-31 Period Format= P2M5D Months remaining in the year= 2

Java8日期时间的解析和格式化

经常用到的操作有:将日期时间格式化为不同格式String                     ,解析String以获得日期时间对象。

// 格式化 LocalDate date = LocalDate.now(); // 默认格式 System.out.println("Default format of LocalDate=" + date); // 自定义格式 System.out.println(date.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"))); System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE)); LocalDateTime dateTime = LocalDateTime.now(); // 默认格式 System.out.println("Default format of LocalDateTime=" + dateTime); // 自定义格式 System.out.println(dateTime.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒"))); System.out.println(dateTime.format(DateTimeFormatter.BASIC_ISO_DATE)); Instant timestamp = Instant.now(); // 默认格式 System.out.println("Default format of Instant=" + timestamp); // 解析 LocalDateTime dt = LocalDateTime.parse("2022年10月24日10时24分24秒", DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒")); System.out.println("Default format after parsing = " + dt);

运行之后结果如下:

Default format of LocalDate=2022-10-26 2022102620221026 Default format of LocalDateTime=2022-10-26T16:37:51.300 2022102616375120221026 Default format of Instant=2022-10-26T08:37:51.301Z Default format after parsing = 2022-10-24T10:24:24

对遗留日期时间的支持

遗留日期/时间类几乎在所有应用程序中都使用                    ,因此必须有向下兼容             。这就是为什么我们可以通过一些实用方法将遗留类转换为新类,反之亦然                     。

//Date转Instant Instant timestamp = new Date().toInstant(); //Instant转LocalDateTime LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.of(ZoneId.SHORT_IDS.get("CTT"))); System.out.println("Date = " + date); //Calendar转Instant Instant time = Calendar.getInstance().toInstant(); System.out.println(time); //TimeZone转ZoneId ZoneId defaultZone = TimeZone.getDefault().toZoneId(); System.out.println(defaultZone); //ZonedDateTime from specific Calendar ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime(); System.out.println(gregorianCalendarDateTime); //Date API to Legacy classes Date dt = Date.from(Instant.now()); System.out.println(dt); TimeZone tz = TimeZone.getTimeZone(defaultZone); System.out.println(tz); GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime); System.out.println(gc);

运行之后结果如下:

Date = 2022-10-26T16:47:38.329 2022-10-26T08:47:38.429Z Asia/Shanghai 2022-10-26T16:47:38.455+08:00[Asia/Shanghai] Wed Oct 26 16:47:38 CST 2022 sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null] java.util.GregorianCalendar[time=1666774058455,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2022,MONTH=9,WEEK_OF_YEAR=43,WEEK_OF_MONTH=4,DAY_OF_MONTH=26,DAY_OF_YEAR=299,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=4,HOUR_OF_DAY=16,MINUTE=47,SECOND=38,MILLISECOND=455,ZONE_OFFSET=28800000,DST_OFFSET=0]

可以看到              ,遗留的TimeZone和GregorianCalendar类toString()方法过于冗长                    ,对用户不友好       。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
vue中引入组件的步骤(【插件推荐】vue3框架组件自动导入unplugin-vue-components) seo网站如何优化页面(seo教程网站优化)