Java 8的日期/时间API,有篇不错的文章,直接转载

原文链接: journaldev 翻译: ImportNew.comJustin Wu
译文链接: http://www.importnew.com/14140.html

Java 8中的日期/时间(Date/Time)API是开发人员最受追捧的变化之一,Java从一开始就没有对日期/时间一致性处理的方法,因此在Java 8中新增的日期/时间API也是除Java核心API以外另一项倍受欢迎的内容。

为什么我们需要新的Java日期/时间API?

在开始研究Java 8日期/时间API之前,让我们先来看一下为什么我们需要这样一个新的API。在Java 8之前中,日期和时间相关的类存在如下问题:

  • Java中日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。

  • java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。

  • 对于时间、时间戳、格式化以及解析,并没有一些明确定义的类。对于格式化和解析的需求,我们有java.text.DateFormat抽象类,但通常情况下,SimpleDateFormat类被用于此类需求。

  • 所有的日期类都是可变的,因此他们都不是线程安全的,这是Java日期类最大的问题之一。

  • 日期类并不提供国际化,没有时区支持,虽然引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。

在现有的日期和日历类中定义的方法还存在一些其他的问题,但以上问题已经很清晰地表明:Java需要一个健壮的日期/时间类。这也是为什么Joda Time库,作为旧的日期/时间API的替换者,在Java 8日期/时间需求中扮演重要角色的原因。

Java 8日期/时间API

Java 8日期/时间API是JSR-310规范的实现,它的目标是克服旧的日期/时间API实现中所有的缺陷,新的日期/时间API的一些设计原则如下:

  • 不变性:新的日期/时间API中,所有的类都是不可变的,这种设计有利于并发编程。

  • 关注点分离:新的API将人可读的日期时间和机器时间(unix timestamp)明确分离,它为日期(Date)、时间(Time)、日期时间(DateTime)、时间戳(unix timestamp)以及时区定义了不同的类。

  • 清晰:在所有的类中,方法都被明确定义用以完成相同的行为。举个例子,要拿到当前实例我们可以使用now()方法,在所有的类中都定义了format()和parse()方法,而不是像以前那样专门有一个独立的类。为了更好的处理问题,所有的类都使用了工厂模式和策略模式,一旦你使用了其中某个类的方法,与其他类协同工作并不困难。

  • 实用操作:所有新的日期/时间API类都实现了一系列方法用以完成通用的任务,如:加、减、格式化、解析、从日期/时间中提取单独部分等操作。

  • 可扩展性:新的日期/时间API是工作在ISO-8601日历系统上的,但我们也可以将其应用在非IOS的日历上。

Java日期/时间API包

Java日期/时间API由以下包组成:

  • java.time包:这是新的Java日期/时间API的基础包,所有的主要基础类都是这个包的一部分,如:LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration等等。所有这些类都是不可变的和线程安全的,在大多数情况下,这些类足够应付常见需求。

  • java.time.chrono包:这个包为非ISO的日历系统定义了一些泛化的API,我们可以扩展AbstractChronology类来创建自己的日历系统。

  • java.time.format包:这个包包含能够格式化和解析日期时间对象的类,在绝大多数情况下,我们不应该直接使用它们,因为java.time包中相应的类已经提供了格式化和解析的方法。

  • java.time.temporal包:这个包包含一些时态对象,我们可以用其找出关于日期/时间对象的某个特定日期或时间,比如说,可以找到某月的第一天或最后一天。你可以非常容易地认出这些方法,因为它们都具有“withXXX”的格式。

  • java.time.zone包:这个包包含支持不同时区以及相关规则的类。

Java日期/时间API示例

我们已经浏览了Java 8日期/时间API中的大多数重要部分,是时候根据示例深入了解其中的核心类了。

LocalDate

LocalDate是一个不可变的类,它表示默认格式(yyyy-MM-dd)的日期,我们可以使用now()方法得到当前时间,也可以提供输入年份、月份和日期的输入参数来创建一个LocalDate实例。该类为now()方法提供了重载方法,我们可以传入ZoneId来获得指定时区的日期。该类提供与java.sql.Date相同的功能,对于如何使用该类,我们来看一个简单的例子。

import java.time.LocalTime;
import java.time.ZoneId; /**
* LocalTime Examples
*
* @author pankaj
*
*/
public class LocalTimeExample
{ public static void main(String[] args)
{ // Current Time
LocalTime time = LocalTime.now();
System.out.println("Current Time=" + time); // Creating LocalTime by providing input arguments
LocalTime specificTime = LocalTime.of(12, 20, 25, 40);
System.out.println("Specific Time of Day=" + specificTime); // Try creating time by providing invalid inputs
// LocalTime invalidTime = LocalTime.of(25,20);
// Exception in thread "main" java.time.DateTimeException:
// Invalid value for HourOfDay (valid values 0 - 23): 25 // Current date in "Asia/Kolkata", you can get it from ZoneId javadoc
LocalTime timeKolkata = LocalTime.now(ZoneId.of("Asia/Kolkata"));
System.out.println("Current Time in IST=" + timeKolkata); // java.time.zone.ZoneRulesException: Unknown time-zone ID: IST
// LocalTime todayIST = LocalTime.now(ZoneId.of("IST")); // Getting date from the base date i.e 01/01/1970
LocalTime specificSecondTime = LocalTime.ofSecondOfDay(10000);
System.out.println("10000th second time= " + specificSecondTime); } }

示例方法的详解都包含在注释内,当我们运行程序时,可以得到以下输出:

当前日期=2016-10-17
指定日期=2014-01-01
当前印度标准日期=2016-10-17
基准日期的第365天= 1971-01-01
2014年的第一百天=2014-04-10

LocalDateTime

LocalDateTime是一个不可变的日期-时间对象,它表示一组日期-时间,默认格式是yyyy-MM-dd-HH-mm-ss.zzz。它提供了一个工厂方法,通过接收LocalDate和LocalTime输入参数,来创建LocalDateTime实例。我们来看一个简单的例子。

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZoneOffset; public class LocalDateTimeExample
{ public static void main(String[] args)
{ // Current Date
LocalDateTime today = LocalDateTime.now();
System.out.println("Current DateTime=" + today); // Current Date using LocalDate and LocalTime
today = LocalDateTime.of(LocalDate.now(), LocalTime.now());
System.out.println("Current DateTime=" + today); // Creating LocalDateTime by providing input arguments
LocalDateTime specificDate = LocalDateTime.of(2014, Month.JANUARY, 1, 10, 10, 30);
System.out.println("Specific Date=" + specificDate); // Try creating date by providing invalid inputs
// LocalDateTime feb29_2014 = LocalDateTime.of(2014, Month.FEBRUARY, 28,
// 25,1,1);
// Exception in thread "main" java.time.DateTimeException:
// Invalid value for HourOfDay (valid values 0 - 23): 25 // Current date in "Asia/Kolkata", you can get it from ZoneId javadoc
LocalDateTime todayKolkata = LocalDateTime.now(ZoneId.of("Asia/Kolkata"));
System.out.println("Current Date in IST=" + todayKolkata); // java.time.zone.ZoneRulesException: Unknown time-zone ID: IST
// LocalDateTime todayIST = LocalDateTime.now(ZoneId.of("IST")); // Getting date from the base date i.e 01/01/1970
LocalDateTime dateFromBase = LocalDateTime.ofEpochSecond(10000, 0, ZoneOffset.UTC);
System.out.println("10000th second time from 01/01/1970= " + dateFromBase); } }

在所有这三个例子中,我们已经看到如果我们提供了无效的参数去创建日期/时间,那么系统会抛出java.time.DateTimeException,这是一种运行时异常,我们并不需要显式地捕获它。同时我们也看到,能够通过传入ZoneId得到日期/时间数据,你可以从它的Javadoc中得到支持的Zoneid的列表,当运行以上类时,可以得到以下输出。

Current DateTime=2016-10-17T16:22:19.453
Current DateTime=2016-10-17T16:22:19.453
Specific Date=2014-01-01T10:10:30
Current Date in IST=2016-10-17T13:52:19.454
10000th second time from 01/01/1970= 1970-01-01T02:46:40

Instant

Instant类是用在机器可读的时间格式上的,它以Unix时间戳的形式存储日期时间,我们来看一个简单的程序。

import java.time.Duration;
import java.time.Instant; public class InstantExample
{ public static void main(String[] args)
{
// Current timestamp
Instant timestamp = Instant.now();
System.out.println("Current Timestamp = " + timestamp); // Instant from timestamp
Instant specificTime = Instant.ofEpochMilli(timestamp.toEpochMilli());
System.out.println("Specific Time = " + specificTime); // Duration example
Duration thirtyDay = Duration.ofDays(30);
System.out.println(thirtyDay);
} }

输出结果如下:

Current Timestamp = 2016-10-17T08:25:08.069Z
Specific Time = 2016-10-17T08:25:08.069Z
PT720H

JAVA 8日期/时间工具方法

我们早些时候提到过,大多数日期/时间API类都实现了一系列工具方法,如:加/减天数、周数、月份数,等等。还有其他的工具方法能够使用TemporalAdjuster调整日期,并计算两个日期间的周期。

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.temporal.TemporalAdjusters; public class DateAPIUtilities
{ public static void main(String[] args)
{ LocalDate today = LocalDate.now(); // Get the Year, check if it's leap year
System.out.println("Year " + today.getYear() + " is Leap Year? " + today.isLeapYear()); // Compare two LocalDate for before and after
System.out.println("Today is before 01/01/2015? " + today.isBefore(LocalDate.of(2015, 1, 1))); // Create LocalDateTime from LocalDate
System.out.println("Current Time=" + today.atTime(LocalTime.now())); // plus and minus operations
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)); // Temporal adjusters for adjusting the dates
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 2016 is Leap Year? true
Today is before 01/01/2015? false
Current Time=2016-10-17T16:30:30.743
10 days after today will be 2016-10-27
3 weeks after today will be 2016-11-07
20 months after today will be 2018-06-17
10 days before today will be 2016-10-07
3 weeks before today will be 2016-09-26
20 months before today will be 2015-02-17
First date of this month= 2016-10-01
Last date of this year= 2016-12-31
Period Format= P2M14D
Months remaining in the year= 2

解析和格式化

将一个日期格式转换为不同的格式,之后再解析一个字符串,得到日期时间对象,这些都是很常见的。我们来看一下简单的例子。

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; public class DateParseFormatExample
{ public static void main(String[] args)
{ // Format examples
LocalDate date = LocalDate.now();
// default format
System.out.println("Default format of LocalDate=" + date);
// specific format
System.out.println(date.format(DateTimeFormatter.ofPattern("d::MMM::uuuu")));
System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE)); LocalDateTime dateTime = LocalDateTime.now();
// default format
System.out.println("Default format of LocalDateTime=" + dateTime);
// specific format
System.out.println(dateTime.format(DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss")));
System.out.println(dateTime.format(DateTimeFormatter.BASIC_ISO_DATE)); Instant timestamp = Instant.now();
// default format
System.out.println("Default format of Instant=" + timestamp); // Parse examples
LocalDateTime dt = LocalDateTime.parse("27::四月::2014 21::39::48",
DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss"));
System.out.println("Default format after parsing = " + dt);
} }

当运行以上程序时,可以看到如下输出:

Default format of LocalDate=2016-10-17
17::十月::2016
20161017
Default format of LocalDateTime=2016-10-17T16:37:47.846
17::十月::2016 16::37::47
20161017
Default format of Instant=2016-10-17T08:37:47.847Z
Default format after parsing = 2014-04-27T21:39:48

Java8 DateTime API的更多相关文章

  1. Java8新特性时间日期库DateTime API及示例

    Java8新特性的功能已经更新了不少篇幅了,今天重点讲解时间日期库中DateTime相关处理.同样的,如果你现在依旧在项目中使用传统Date.Calendar和SimpleDateFormat等API ...

  2. java8 异步api、循环、日期

    java8 异步api.循环.日期 转载请注明出处:https://www.cnblogs.com/funnyzpc/p/10801470.html 异步api 对于多任务耗时的业务场景,一般我们会用 ...

  3. Java 8 Date-Time API 详解

    从Java版本1.0开始就支持日期和时间,主要通过java.util.Date类. 但是,Date类设计不佳. 例如,Date中的月份从1开始,但从日期却从0开始.在JDK 1.1中使用它的许多方法已 ...

  4. Java 8 Date-Time API概览

    更新时间:2018-04-19 根据网上资料整理 java 8增加了新的Date-Time API (JSR 310),增强对日期与时间的处理.它在很大程度上受到Joda-Time的影响.之前写过一篇 ...

  5. Java8 新API读取文件内容

    import java.io.IOException;import java.nio.charset.Charset;import java.nio.file.Files;import java.ni ...

  6. Java8 日期 API 业务使用

    最近在做账单结算业务,需要根据客户选择的结算方式来推算下一次结算日期以及该次结算日期段. 推算日期这样的业务直男君以前就写过,只不过使用的是熟悉的 java.util.date 和 java.util ...

  7. 如何用Java8 Stream API找到心仪的女朋友

    传统的的Java 集合操作是有些啰嗦的,当我们需要对结合元素进行过滤,排序等操作的时候,通常需要写好几行代码以及定义临时变量. 而Java8 Stream API 可以极大简化这一操作,代码行数少,且 ...

  8. Java8 Time API与老Date之间的转换

    前面我已经总结了Java8 Time API常用的一些方法.封装的工具类,可是最近需要对一个比较老的项目进行重构,大致看了一下使用的Jdk还是7而且里面的时间工具类还是使用的Date和Calendar ...

  9. 何用Java8 Stream API进行数据抽取与收集

    上一篇中我们通过一个实例看到了Java8 Stream API 相较于传统的的Java 集合操作的简洁与优势,本篇我们依然借助于一个实际的例子来看看Java8 Stream API 如何抽取及收集数据 ...

随机推荐

  1. 2020年Yann Lecun深度学习笔记(上)

    2020年Yann Lecun深度学习笔记(上)

  2. YOLOv3和YOLOv4长篇核心综述(下)

    YOLOv3和YOLOv4长篇核心综述(下) 4.3.3 Neck创新 在目标检测领域,为了更好的提取融合特征,通常在Backbone和输出层,会插入一些层,这个部分称为Neck.相当于目标检测网络的 ...

  3. C语言const关键字的作用

    1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdio.h> 3 #include <string.h> 4 #include ...

  4. 【VBA】一些判断

    判断是否为空: Sub 测试() If IsEmpty(Range("A100000")) Then Debug.Print "空的" End If End S ...

  5. Eclipse安装PyDev失败的解决办法

    在Eclipse上安装Pydev,首先尝试了三种方法,均失败. Eclipse版本号如下: 尝试的方法 第一种: 菜单栏Help>Install New Software,输入网址, http: ...

  6. docker-compose 部署 Apollo 自定义环境

    Apollo 配置中心是什么: ​ Apollo是携程框架部门研发的开源配置管理中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性. ...

  7. Java8-四个函数式接口(Consumer,Supplier,Predicate,Function)

    Java8---函数式接口 Consumer---消费者(accept方法,Lambda与方法引用返回都是Consumer) Supplier---供给型(get方法,返回数据,与Optional可以 ...

  8. error C3646: 未知重写说明符

    记录一个报错 error C3646: 未知重写说明符 ①循环引用 在项目文件变多时,由于组织不当,很容易出现头文件的循环引用 有时候虽然没有出现循环引用,但是头文件多处被include :适当的使用 ...

  9. 96、linux之rpm包定制

    96.1.rpm包定制介绍: 编译安装软件,优点是可以定制化安装目录.按需开启功能等,缺点是需要查找并实验出适合的编译参数,诸如MySQL之类的软件编译耗时过长. yum安装软件,优点是全自动化安装, ...

  10. Linux + .net core 开发升讯威在线客服系统:同时支持 SQL Server 和 MySQL 的实现方法

    前段时间我发表了一系列文章,开始介绍基于 .net core 的在线客服系统开发过程. 有很多朋友一直提出希望能够支持 MySQL 数据库,考虑到已经有朋友在用 SQL Server,我在升级的过程中 ...