JDK1.8-新的日期和时间API

栏目: 后端 · 发布时间: 5年前

内容简介:Java的API提供了很多有用的组件,能帮助你构建复杂的应用。不过,Java API也不总是完美的。我们相信大多数有经验的程序员都会赞同Java 8之前的库对日期和时间的支持就非常不理想。然而,你也不用太担心:Java 8中引入全新的日期和时间API就是要解决这一问题。让我们从探索如何创建简单的日期和时间间隔入手。 java.time 包中提供了很多新的类可以帮你解决问题,它们是 LocalDate 、 LocalTime 、 Instant 、 Duration 和 Period 。LocalDate 类

Java的API提供了很多有用的组件,能帮助你构建复杂的应用。不过,Java API也不总是完美的。我们相信大多数有经验的 程序员 都会赞同 Java 8之前的库对日期和时间的支持就非常不理想。然而,你也不用太担心:Java 8中引入全新的日期和时间API就是要解决这一问题。

1 LocalDate 、 LocalTime 、 Instant 、 Duration 以及 Period

让我们从探索如何创建简单的日期和时间间隔入手。 java.time 包中提供了很多新的类可以帮你解决问题,它们是 LocalDate 、 LocalTime 、 Instant 、 Duration 和 Period 。

1.1 LocalDate 和 LocalTime

LocalDate 类,该类的实例是一个不可变对象,它只提供了简单的日期,并不含当天的时间信息。另外,它也不附带任何与时区相关的信息。

你可以通过 静态工厂方法 of 创建一个 LocalDate 实例 。 LocalDate 实例提供了多种方法来读取常用的值,比如年份、月份、星期几等。

public static void main(String[] args) {
        //2014-3-18
        LocalDate date = LocalDate.of(2014, 3, 18);
        //2014
        int year = date.getYear();
        //march
        Month month = date.getMonth();
        //18
        int day = date.getDayOfMonth();
        DayOfWeek dow = date.getDayOfWeek();
        //这个月的天数
        int len = date.lengthOfMonth();
        //是否事闰年
        boolean leap = date.isLeapYear();
        System.out.println("year : " + year + " month : " + month + " day : " + day +
                " dow : " + dow + " len : " + len + " leap : " + leap);
    }

复制代码

似地,一天中的时间,比如13:45:20,可以使用 LocalTime 类表示。你可以使用 of 重载的两个工厂方法创建 LocalTime 的实例。第一个重载函数接收小时和分钟,第二个重载函数同时还接收秒。同 LocalDate 一样, LocalTime 类也提供了一些 getter 方法访问这些变量的值。

LocalTime time = LocalTime.of(13, 45, 20);
int hour = time.getHour();
int minute = time.getMinute();
int second = time.getSecond();
复制代码

LocalDate 和 LocalTime 都可以通过解析代表它们的字符串创建。使用静态方法 parse ,你可以实现这一目的:

LocalDate date = LocalDate.parse("2014-03-18");
LocalTime time = LocalTime.parse("13:45:20");
复制代码

1.2 合并日期和时间

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

// 2014-03-18T13:45:20
LocalDateTime dt1 = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45, 20);
LocalDateTime dt2 = LocalDateTime.of(date, time);
LocalDateTime dt3 = date.atTime(13, 45, 20);
LocalDateTime dt4 = date.atTime(time);
LocalDateTime dt5 = time.atDate(date);
复制代码

通过它们各自的 atTime 或者 atDate 方法,向 LocalDate 传递一个时间对象,或者向LocalTime 传递一个日期对象的方式,你可以创建一个 LocalDateTime 对象。你也可以使用toLocalDate 或者 toLocalTime 方法,从 LocalDateTime 中提取 LocalDate 或者 LocalTime组件:

LocalDate date1 = dt1.toLocalDate();
LocalTime time1 = dt1.toLocalTime();
复制代码

1.3 Duration 和 Period

Duration 类的静态工厂方法 between 就是为比较两个时间而设计的。你可以创建两个 LocalTimes 对象、两个 LocalDateTimes对象,或者两个 Instant 对象之间的 duration:

Duration d1 = Duration.between(time1, time2);
Duration d1 = Duration.between(dateTime1, dateTime2);
复制代码

如果你需要以年、月或者日的方式对多个时间单位建模,可以使用 Period 类。使用该类的工厂方法 between ,你可以使用得到两个 LocalDate 之间的时长:

Period tenDays = Period.between(LocalDate.of(2014, 3, 8),
								LocalDate.of(2014, 3, 18));
复制代码

最后, Duration 和 Period 类都提供了很多非常方便的工厂类,直接创建对应的实例;换句话说,就像下面这段代码那样,不再是只能以两个temporal对象的差值的方式来定义它们的对象。

Duration threeMinutes = Duration.ofMinutes(3);
Duration threeMinutes = Duration.of(3, ChronoUnit.MINUTES);
Period tenDays = Period.ofDays(10);
Period threeWeeks = Period.ofWeeks(3);
Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);
复制代码

Duration 类和 Period 类共享方法

JDK1.8-新的日期和时间API
JDK1.8-新的日期和时间API

2 操纵、解析和格式化日期

2.1 比较直观的方式操纵 LocalDate 的属性

//2019-3-20
        LocalDate of = LocalDate.of(2019, 3, 20);
        //2018-3-20
        LocalDate localDate = of.withYear(2018);
        //2018-4-20
        LocalDate localDate1 = localDate.withMonth(4);
        //2018-9-20
        LocalDate with = localDate1.with(ChronoField.MONTH_OF_YEAR, 9);
复制代码

最后这一行中使用的 with 方法和get方法有些类似,它们都声明于 Temporal 接口,所有的日期和时间API类都实现这两个方法,它们定义了单点的时间,比如 LocalDate 、 LocalTime 、 LocalDateTime 以及 Instant 。更确切 地说,使用 get 和 with 方法,我们可以将 Temporal 对象值的读取和修改区分开。

2.2 以相对方式修改 LocalDate 对象的属性

//2014-3-18
LocalDate date1 = LocalDate.of(2014, 3, 18);
//2014-3-25
LocalDate date2 = date1.plusWeeks(1);

LocalDate date3 = date2.minusYears(3);
LocalDate date4 = date3.plus(6, ChronoUnit.MONTHS);
复制代码

最后一行使用的 plus 方法也是通用方法,它和 minus 方法都声明于 Temporal 接口中。通过这些方法,对 TemporalUnit 对象加上或者减去一个数字,我们能非常方便地将 Temporal 对象前溯或者回滚至某个时间段,通过ChronoUnit 枚举我们可以非常方便地实现 TemporalUnit 接口。

JDK1.8-新的日期和时间API

2.3 使用 TemporalAdjuster

有的时候,你需要进行一些更加复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可以使用重载版本的 with 方法,向其传递一个提供了更多定制化选择的 TemporalAdjuster 对象,更加灵活地处理日期。对于最常见的用例,日期和时间API已经提供了大量预定义的TemporalAdjuster 。你可以通过 TemporalAdjuster 类的静态工厂方法访问它们。

//2014-03-18
LocalDate date1 = LocalDate.of(2014, 3, 18);
//2014-03-23
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));
//2014-03-31
LocalDate date3 = date2.with(lastDayOfMonth());
复制代码
JDK1.8-新的日期和时间API

正如我们看到的,使用 TemporalAdjuster 我们可以进行更加复杂的日期操作,而且这些方 法的名称也非常直观,方法名基本就是问题陈述。此外,即使你没有找到符合你要求的预定义的 TemporalAdjuster ,创建你自己的 TemporalAdjuster 也并非难事。实际上, Temporal- Adjuster 接口只声明了单一的一个方法(这使得它成为了一个函数式接口)。

@FunctionalInterface
public interface TemporalAdjuster {
	Temporal adjustInto(Temporal temporal);
}
复制代码

这意味着 TemporalAdjuster 接口的实现需要定义如何将一个 Temporal 对象转换为另一个 Temporal 对象。你可以把它看成一个 UnaryOperator

2.4 实现一个定制的 TemporalAdjuster

设计一个 NextWorkingDay 类,该类实现了 TemporalAdjuster 接口,能够计算明天的日期,同时过滤掉周六和周日这些节假日。格式如下所示:

public class MyTemporalAdjuster {
    public static void main(String[] args) {
        LocalDate of = LocalDate.of(2019, 3, 20);
        LocalDate with = of.with(new NewTemporalAdjuster());
        System.out.println("with = " + with);
    }
}

//如果当天的星期介于周一至周五之间,日期向后移动一天;如果当天是周六或者周日,则返回下一个周一
class  NewTemporalAdjuster implements TemporalAdjuster {
    @Override
    public Temporal adjustInto(Temporal temporal) {
        DayOfWeek of = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
        int dayToAdd = 1;
        if (of == DayOfWeek.FRIDAY){
            dayToAdd = 3;
        }else if (of == DayOfWeek.SATURDAY){
            dayToAdd = 2;
        }
        return temporal.plus(dayToAdd, ChronoUnit.DAYS);
    }
}
复制代码

2.5 打印输出及解析日期--时间对象

处理日期和时间对象时,格式化以及解析日期时间对象是另一个非常重要的功能。新的java.time.format 包就是特别为这个目的而设计的。这个包中,最重要的类是 DateTimeFormatter 。创建格式器最简单的方法是通过它的静态工厂方法以及常量。像 BASIC_ISO_DATE和 ISO_LOCAL_DATE 这 样 的 常 量 是 DateTimeFormatter 类 的 预 定 义 实 例 。 所 有 的DateTimeFormatter 实例都能用于以一定的格式创建代表特定日期或时间的字符串。

LocalDate date = LocalDate.of(2014, 3, 18);
//20140318
String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE);
//2014-03-18
String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
复制代码

你也可以通过解析代表日期或时间的字符串重新创建该日期对象。所有的日期和时间API都提供了表示时间点或者时间段的工厂方法,你可以使用工厂方法 parse 达到重创该日期对象的目的:

LocalDate date1 = LocalDate.parse("20140318",DateTimeFormatter.BASIC_ISO_DATE);
LocalDate date2 = LocalDate.parse("2014-03-18",DateTimeFormatter.ISO_LOCAL_DATE);
复制代码

2.6 按照某个模式创建 DateTimeFormatter

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate date1 = LocalDate.of(2014, 3, 18);
String formattedDate = date1.format(formatter);
LocalDate date2 = LocalDate.parse(formattedDate, formatter);
复制代码

LocalDate 的 formate 方法使用指定的模式生成了一个代表该日期的字符串。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

HTML5

HTML5

Matthew David / Focal Press / 2010-07-29 / USD 39.95

Implement the powerful new multimedia and interactive capabilities offered by HTML5, including style control tools, illustration tools, video, audio, and rich media solutions. Understand how HTML5 is ......一起来看看 《HTML5》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器