Java 8 - 新的日期时间API

你好,未来的Java法师们!? 今天,我们将踏上一段激动人心的旅程,探索Java的日期时间API的神奇领域。如果你之前从未编写过一行代码,也不用担心——我们将从头开始,一起逐步学习。在本课结束时,你将能够像专业人士一样熟练地处理日期和时间!那么,让我们开始吧!

Java - Datetime Api

Java日期时间API简介

想象一下你在建造一个时光机器(酷吧?)。为了使其工作,你需要精确地处理日期和时间。这正是Java的日期时间API在我们的程序中帮助我们的地方。它就像一个集成了超级精确的时钟和日历!

为什么要有新的API?

在我们深入了解之前,你可能会有疑问:“Java为什么要创建一个新的日期时间API?”让我给你讲一个小故事。

曾经有一次(在Java 8之前),开发者们不得不使用旧的java.util.Datejava.util.Calendar类。这些就像使用一个旧的老式时钟——它们能工作,但有很多问题。它们难以使用,不是线程安全的(这意味着它们可能在复杂的程序中引起问题),并且处理时区的能力不佳。

因此,Java团队决定创建一个全新的、闪亮的API来解决所有这些问题。于是,java.time包在Java 8中诞生了!

Java本地日期时间API

让我们从基础开始。本地日期时间API帮助我们处理日期和时间,而不用担心时区。这就像在你的桌子上有一个简单的时钟和日历。

LocalDate

LocalDate代表没有时区的日期。让我们看看如何使用它:

import java.time.LocalDate;

public class DateExample {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
System.out.println("今天的日期是: " + today);

LocalDate specificDate = LocalDate.of(2023, 6, 15);
System.out.println("一个特定的日期: " + specificDate);
}
}

在这个例子中,我们做了两件事:

  1. 我们使用LocalDate.now()获取今天的日期。
  2. 我们使用LocalDate.of()创建一个特定的日期(2023年6月15日)。

当你运行这段代码时,你将看到打印出的今天的日期和我们创建的特定日期。

LocalTime

LocalTime代表没有日期或时区的时间。下面是如何使用它:

import java.time.LocalTime;

public class TimeExample {
public static void main(String[] args) {
LocalTime now = LocalTime.now();
System.out.println("当前时间是: " + now);

LocalTime specificTime = LocalTime.of(14, 30, 45);
System.out.println("一个特定的时间: " + specificTime);
}
}

在这个例子中:

  1. 我们使用LocalTime.now()获取当前时间。
  2. 我们使用LocalTime.of()创建一个特定的时间(下午2:30:45)。

LocalDateTime

LocalDateTime结合了日期和时间,但仍然没有时区。这就像一个既显示时间也显示日期的时钟。下面是如何使用它:

import java.time.LocalDateTime;

public class DateTimeExample {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println("当前的日期和时间: " + now);

LocalDateTime specificDateTime = LocalDateTime.of(2023, 6, 15, 14, 30, 45);
System.out.println("一个特定的日期和时间: " + specificDateTime);
}
}

在这个例子中:

  1. 我们使用LocalDateTime.now()获取当前的日期和时间。
  2. 我们使用LocalDateTime.of()创建一个特定的日期和时间(2023年6月15日下午2:30:45)。

Java时区日期时间API

现在,让我们的时光机器增加一些调料——时区!时区日期时间API帮助我们在考虑不同时区的同时处理日期和时间。

ZonedDateTime

ZonedDateTime代表一个有时区的日期时间。它就像一个世界时钟,显示不同地区的时间。

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

public class ZonedDateTimeExample {
public static void main(String[] args) {
ZonedDateTime nowInSystemTZ = ZonedDateTime.now();
System.out.println("系统时区中的当前日期和时间: " + nowInSystemTZ);

ZonedDateTime nowInParis = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
System.out.println("巴黎的当前日期和时间: " + nowInParis);
}
}

在这个例子中:

  1. 我们使用ZonedDateTime.now()获取系统默认时区中的当前日期和时间。
  2. 我们使用ZonedDateTime.now(ZoneId.of("Europe/Paris"))获取巴黎的当前日期和时间。

Java时间单位枚举

ChronoUnit枚举提供了一组标准的时间周期和时间单位。这就像有一系列用于计时的工具——秒、分钟、小时、天、周、月、年等。

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

public class ChronoUnitExample {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime futureDateTime = now.plus(1, ChronoUnit.WEEKS);

long daysBetween = ChronoUnit.DAYS.between(now, futureDateTime);
System.out.println("现在和一周后的日期之间相差的天数: " + daysBetween);
}
}

在这个例子中:

  1. 我们将当前日期时间加上一周,使用plus(1, ChronoUnit.WEEKS)
  2. 我们计算现在和一周后的日期之间相差的天数,使用ChronoUnit.DAYS.between()

Java Period和Duration

PeriodDuration用于表示时间量。可以将Period视为日历上两个日期之间的差异,而Duration则像是秒表上显示的时间。

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

public class PeriodDurationExample {
public static void main(String[] args) {
LocalDate date1 = LocalDate.of(2023, 1, 1);
LocalDate date2 = LocalDate.of(2023, 12, 31);
Period period = Period.between(date1, date2);
System.out.println("在" + date1 + "和" + date2 + "之间的时间段: " + period);

LocalTime time1 = LocalTime.of(9, 0);
LocalTime time2 = LocalTime.of(17, 30);
Duration duration = Duration.between(time1, time2);
System.out.println("在" + time1 + "和" + time2 + "之间的持续时间: " + duration);
}
}

在这个例子中:

  1. 我们计算两个日期之间的时间段,使用Period.between()
  2. 我们计算两个时间之间的持续时间,使用Duration.between()

Java时间调整器

时间调整器就像魔法棒,可以以有用的方式调整日期,比如找到下一个星期一或月份的最后一天。

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

public class TemporalAdjustersExample {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
LocalDate nextMonday = date.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println("下一个星期一: " + nextMonday);

LocalDate lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("这个月的最后一天: " + lastDayOfMonth);
}
}

在这个例子中:

  1. 我们使用TemporalAdjusters.next(DayOfWeek.MONDAY)找到下一个星期一。
  2. 我们使用TemporalAdjusters.lastDayOfMonth()找到当前月份的最后一天。

向后兼容性

现在,你可能会有疑问:“那么,所有使用旧日期时间类的旧代码怎么办?”别担心!Java也考虑到了这一点。新的API提供了方法来在旧的和新的日期时间类之间进行转换。

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

public class BackwardCompatibilityExample {
public static void main(String[] args) {
// 将旧的Date转换为新的LocalDateTime
Date oldDate = new Date();
LocalDateTime newDateTime = LocalDateTime.ofInstant(oldDate.toInstant(), ZoneId.systemDefault());
System.out.println("旧的Date: " + oldDate);
System.out.println("新的LocalDateTime: " + newDateTime);

// 将新的LocalDateTime转换为旧的Date
LocalDateTime localDateTime = LocalDateTime.now();
Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
System.out.println("新的LocalDateTime: " + localDateTime);
System.out.println("旧的Date: " + date);
}
}

在这个例子中:

  1. 我们将一个旧的Date对象转换为一个新的LocalDateTime对象。
  2. 我们将一个新的LocalDateTime对象转换回一个旧的Date对象。

这种向后兼容性确保你可以在享受新日期时间API的好处的同时,继续与旧Java代码合作。

结论

恭喜你!你已经迈出了进入Java日期时间API世界的第一步。我们涵盖了从基本的日期时间处理到时区和时间调整器等更高级的概念。

记住,就像任何技能一样,掌握Java中的日期和时间需要练习。如果一开始感觉有点难以应对——别灰心——即使是经验丰富的开发者有时也需要查阅这些类的用法!

继续尝试这些例子,尝试修改它们,看看会发生什么。在你意识到之前,你将能够像一个真正的Java时间旅行者一样操纵日期和时间!

快乐编码,愿你的时间总是恰到好处!⏰?

Credits: Image by storyset