Java 8 日期和时间 API
原文:https://www.studytonight.com/java-examples/java-8-date-and-time-api
Java 8 推出了全新的日期时间 API 。这个新的 API 的灵感来自流行的 JodaTime 库。添加它是为了克服现有日期 API 的缺点。
在本教程中,我们将讨论新的日期和时间 API 的重要类。
现有 API 的缺点(Java 7)
现有的日期和时间 API 有几个主要缺点。让我们讨论其中的一些缺点。
- 线程安全 -现有的日期和日历类不是线程安全的,需要额外的努力来处理并发性。新的 LocalDate、LocalTime 和 LocalDateTime 类解决了这个问题。这些类是不可变的和线程安全的。
- 时区 -旧的 API 不提供任何时区支持。新的 ZonedDateTime 类也支持时区。
- 其他改进 -新的 API 符合 ISO 标准,更容易理解。它提供了许多操作日期和时间的方法。与新的 API 相比,现有的 API 有点难以使用和理解。
LocalDate Class(本地日期类)
LocalDate 类用于表示标准 ISO 格式 (yyyy-mm-dd)的日期。它不包括时间,也不支持时区。
创建本地日期实例
我们可以使用 now() 方法创建 LocalDate 类的一个实例。它将根据系统时钟捕捉当前日期。
import java.time.LocalDate;
public class Demo
{
public static void main(String[] args)
{
LocalDate currDate = LocalDate.now();
System.out.print("Current Date is: " + currDate);
}
}
当前日期为:2021-08-13
要使用其他日期创建实例,我们可以使用()方法的。此方法采用三个整数参数,即年、月和日。
import java.time.LocalDate;
public class Demo
{
public static void main(String[] args)
{
LocalDate date = LocalDate.of(2021, 8, 13);
System.out.print("Date: " + date);
}
}
日期:2021-08-13
如果您有包含日期的字符串,请使用 parse() 方法。确保日期采用正确的国际标准化组织格式。
import java.time.LocalDate;
public class Demo
{
public static void main(String[] args)
{
LocalDate date = LocalDate.parse("2021-08-13");
System.out.print("Date: " + date);
}
}
日期:2021-08-13
加减方法
我们可以从日期中添加或减去天数、月数或年数。让我们使用 plusDays() 或 minusDays() 方法来获取昨天的日期和明天的日期。我们也有类似的方法来改变月份和年份。
import java.time.LocalDate;
public class Demo
{
public static void main(String[] args)
{
LocalDate currDate = LocalDate.now();
LocalDate yesterday = currDate.minusDays(1);
LocalDate tomorrow = currDate.plusDays(1);
System.out.println("Current Date: " + currDate);
System.out.println("tomorrow's Date: " + tomorrow);
System.out.println("Yesterday's Date: " + yesterday);
}
}
当前日期:2021-08-13 明天日期:2021-08-14 昨天日期:2021-08-12
我们也可以使用更简单的加()或减()方法来操纵日期。这些方法将使用计时单位枚举。请记住,LocalDate 是不可变的,我们不会更改现有的日期。所有这些方法都返回一个经过修改的新实例。
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class Demo
{
public static void main(String[] args)
{
LocalDate currDate = LocalDate.now();
LocalDate date1 = currDate.plus(5, ChronoUnit.MONTHS);
LocalDate date2 = currDate.minus(5, ChronoUnit.DAYS);
System.out.println("Current Date: " + currDate);
System.out.println("Current Date plus five months: " + date1);
System.out.println("Current Date minus five days: " + date2);
}
}
当前日期:2021-08-13 当前日期加五个月:2022-01-13 当前日期减五天:2021-08-08
吸气方法
LocalDate 类包含几个 getter 方法来从 LocalDate 获取不同的信息,例如获取星期几或月几等。下面的代码演示了这一点。
import java.time.DayOfWeek;
import java.time.LocalDate;
public class Demo
{
public static void main(String[] args)
{
LocalDate currDate = LocalDate.now();
DayOfWeek dayOfWeek = currDate.getDayOfWeek();//getDayOfWeek() returns a DayOfWeek instance and not a String
int dayOfMonth = currDate.getDayOfMonth();
int dayOfYear = currDate.getDayOfYear();
System.out.println("Date: " + currDate);
System.out.println("Day of Week: " + dayOfWeek);
System.out.println("Day of Month: " + dayOfMonth);
System.out.println("Day of Year: " + dayOfYear);
}
}
日期:2021-08-13 星期几:星期五 月日:13 年日:225
比较日期
我们可以通过使用 isBefore() 和 isAfter() 方法来比较日期,以检查哪个更大。请看下面的例子。
import java.time.LocalDate;
public class Demo
{
public static void main(String[] args)
{
LocalDate currDate = LocalDate.now();
LocalDate tomorrow = currDate.plusDays(1);
LocalDate yesterday = currDate.minusDays(1);
System.out.println("Current date is after yesterday's date: " + currDate.isAfter(yesterday));
System.out.println("Current date is before tomorrow's date: " + currDate.isBefore(tomorrow));
}
}
当前日期在昨天日期之后:真 当前日期在明天日期之前:真
其他实用方法
这个类还提供了其他实用方法。例如,我们有islapyear()方法,该方法返回一个布尔值,指示该年是否是闰年。
import java.time.LocalDate;
public class Demo
{
public static void main(String[] args)
{
LocalDate currDate = LocalDate.now();
System.out.println(currDate + " is a leap year? " + currDate.isLeapYear());
}
}
2021-08-13 是闰年?错误的
我们还有 lengthOfMonth() 和 lengthOfYear() 方法返回月和年的长度。
import java.time.LocalDate;
public class Demo
{
public static void main(String[] args)
{
LocalDate currDate = LocalDate.now();
System.out.println("Current Date " + currDate);
System.out.println("Length of Month: " + currDate.lengthOfMonth());
System.out.println("Length of Year: " + currDate.lengthOfYear());
}
}
当前日期 2021-08-14 月长:31 年长:365
还有很多其他方法可用。查看官方 Javadoc 页面查看它们。
LocalTime(本地时间)
LocalTime 类用于表示时间。
创建本地时间实例
要创建一个 LocalTime 实例,我们可以使用 now() 、 of() 或者 parse() 方法。now()方法将使用系统时钟获取当前时间。()和 parse()方法可以根据传递的参数创建一个 LocalTime。
import java.time.LocalTime;
public class Demo
{
public static void main(String[] args)
{
LocalTime currTime = LocalTime.now();
LocalTime t1 = LocalTime.of(5, 32, 44);
LocalTime t2 = LocalTime.parse("05:32:44");
System.out.println(currTime);
System.out.println(t1);
System.out.println(t2);
}
}
16:26:36.285807700 05:32:44 05:32:44
加减方法
LocalTime 类也有几个加减方法。
import java.time.LocalTime;
public class Demo
{
public static void main(String[] args)
{
LocalTime t1 = LocalTime.of(5, 32, 44);
LocalTime t2 = t1.plusHours(2);
LocalTime t3 = t1.minusMinutes(10);
System.out.println(t1);
System.out.println(t2);
System.out.println(t3);
}
}
05:32:44 07:32:44 05:22:44
我们也可以使用更简单的加()和减()方法,并带有一个计时单位参数。
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
public class Demo
{
public static void main(String[] args)
{
LocalTime t1 = LocalTime.of(5, 32, 44);
LocalTime t2 = t1.plus(2, ChronoUnit.HOURS);
LocalTime t3 = t1.plus(10, ChronoUnit.MINUTES);
System.out.println(t1);
System.out.println(t2);
System.out.println(t3);
}
}
05:32:44 07:32:44 05:42:44
吸气方法
这个类还包含几个 getter 方法来获取不同的信息,如小时、分钟或秒。下面的代码演示了这一点。
import java.time.LocalTime;
public class Demo
{
public static void main(String[] args)
{
LocalTime t = LocalTime.of(5, 32, 44);
int hours = t.getHour();
int minutes = t.getMinute();
int seconds = t.getSecond();
System.out.println("Time: " + t);
System.out.println("Hours: " + hours);
System.out.println("Minutes: " + minutes);
System.out.println("Seconds: " + seconds);
}
}
时间:05:32:44 小时:5 分钟:32 秒:44
比较本地时间实例
像 LocalDate 类一样,我们可以通过使用 isBefore() 和 isAfter() 方法来比较 LocalTime 的实例。
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
public class Demo
{
public static void main(String[] args)
{
LocalTime t1 = LocalTime.of(5, 32, 44);
LocalTime t2 = t1.plus(1, ChronoUnit.HOURS);
boolean b = t1.isAfter(t2); //False
}
}
LocalDateTime 类
本地日期时间类是本地日期和本地时间类的组合。本地日期时间实例包含日期组件和时间组件。
类似于前面的类,我们有 now() 、 of() 和 parse() 方法来构造 LocalDateTime 类的对象。
import java.time.LocalDateTime;
public class Demo
{
public static void main(String[] args)
{
LocalDateTime currDateTime = LocalDateTime.now();
LocalDateTime dt1 = LocalDateTime.of(2020, 8, 13, 5, 32);
LocalDateTime dt2 = LocalDateTime.parse("2020-08-13T05:32");
System.out.println(currDateTime);
System.out.println(dt1);
System.out.println(dt2);
}
}
2021-08-13t 16:44:11.684424 2020-08-13t 05:32 2020-08-13t 05:32
对于 LocalDateTime 类,我们也有类似的加减方法。
import java.time.LocalDateTime;
public class Demo
{
public static void main(String[] args)
{
LocalDateTime currDateTime = LocalDateTime.now();
LocalDateTime dt1 = currDateTime.plusDays(10);
LocalDateTime dt2 = currDateTime.minusHours(5);
System.out.println(currDateTime);
System.out.println(dt1);
System.out.println(dt2);
}
}
2021-08-13T 16:46:12.603985700 2021-08-23T 16:46:12.603985700 2021-08-13T 11:46:12.603985700
要获取 LocalDateTime 实例的不同组件,我们可以使用 getters。下面的代码演示了一些 getter 方法的使用。
import java.time.LocalDateTime;
import java.time.Month;
public class Demo
{
public static void main(String[] args)
{
LocalDateTime currDateTime = LocalDateTime.now();
int hour = currDateTime.getHour();
int dayOfMonth = currDateTime.getDayOfMonth();
Month month = currDateTime.getMonth();
System.out.println(currDateTime);
System.out.println("Hour: " + hour);
System.out.println("Day of Month: " + dayOfMonth);
System.out.println("Month: " + month);
}
}
2021-08-13t 16:49:07.087638100 小时:16 月日:13 月:8 月
ZonedDateTime Class
上面讨论的类不支持时区。ZonedDateTime 类提供了这种功能。它与 ZoneId 类一起使用,有助于识别不同的时区。
使用 now() 方法创建这个类的一个实例。相关时区信息将被添加到当前日期和时间。
import java.time.ZonedDateTime;
public class Demo
{
public static void main(String[] args)
{
ZonedDateTime zdt = ZonedDateTime.now();
System.out.print(zdt);
}
}
2021-08-13 t17:31:18.046976800+05:30[亚洲/加尔各答]
我们还可以为 now()方法提供一个区域标识。区域 id 用于识别不同的时区。使用 ZoneId 类的()方法的来实现。请确保您提供了有效的时区。
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Demo
{
public static void main(String[] args)
{
ZoneId zone = ZoneId.of("Asia/Tokyo");
ZonedDateTime zdt = ZonedDateTime.now(zone);
System.out.print(zdt);
}
}
2021-08-13t 21:02:03.657050700+09:00【亚洲/东京】
我们可以使用 ZoneId 类的 getAvailableZoneIds() 方法查看所有可用的时区。
import java.time.ZoneId;
import java.util.Set;
public class Demo
{
public static void main(String[] args)
{
Set<String> zones = ZoneId.getAvailableZoneIds();
for(String zone : zones)
System.out.println(zone);
}
}
由上述代码打印的几个时区如下所示。
亚洲/科伦坡 澳大利亚/西部 印度/塔那那利佛 澳大利亚/布里斯班 印度/马约特 美国/印第安纳-斯塔克
我们也可以通过使用这个类的 parse()方法来构造一个 ZonedDateTime 实例。
import java.time.ZonedDateTime;
public class Demo
{
public static void main(String[] args)
{
ZonedDateTime zdt = ZonedDateTime.parse("2021-08-13T17:35:08.044680100+09:00[Asia/Tokyo]");
System.out.print(zdt);
}
}
2021-08-13t 17:35:08.044680100+09:00【亚洲/东京】
ZoneOffset Class(区域偏移类)
使用时区的另一种方法是使用区域偏移量。下面的代码演示了这一点。
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
public class Demo
{
public static void main(String[] args)
{
LocalDateTime dateTime = LocalDateTime.now();
ZoneOffset offset = ZoneOffset.of("+09:00");
OffsetDateTime offsetDateTime = OffsetDateTime.of(dateTime, offset);
System.out.print(offsetDateTime);
}
}
2021-08-13t 17:38:41.485118900+09:00
期间和持续时间
“期间”和“持续时间”类用于查找两个日期或时间之间的差异。期间用于本地日期,持续时间用于本地时间。
让我们使用 Period 类来获取两个日期之间的差异。我们将使用 getDays() 、 getMonths() 和 getYears() 方法来获取两个日期的每个组成部分之间的差异。
import java.time.LocalDate;
import java.time.Period;
public class Demo
{
public static void main(String[] args)
{
LocalDate d1 = LocalDate.now();
LocalDate d2 = d1.plusDays(10).plusMonths(5).plusYears(1);
int days = Period.between(d1, d2).getDays();
int months = Period.between(d1, d2).getMonths();
int years = Period.between(d1, d2).getYears();
System.out.println("Initial Date: " + d1 + " Final Date " + d2);
System.out.println("Difference in Days: " + days);
System.out.println("Difference in Months: " + months);
System.out.println("Difference in Years: " + years);
}
}
起始日期:2021-08-13 结束日期 2023-01-23 日差:10 月差:5 年差:1
让我们使用 Duration 类来获取两个 LocalTimes 之间的差异。我们可以使用这个类的 getSeconds() 方法,以秒为单位获取两次的差值。
import java.time.Duration;
import java.time.LocalTime;
public class Demo
{
public static void main(String[] args)
{
LocalTime t1 = LocalTime.now();
LocalTime t2 = t1.plusHours(10).plusMinutes(5).plusSeconds(15);
long secs = Duration.between(t1, t2).getSeconds();
System.out.println("Initial Time: " + t1 + " Final Time " + t2);
System.out.println("Difference in Seconds: " + secs);
}
}
初始时间:17:55:56.774818600 最终时间 04:01:11.774818600 秒差:-50085
为此,我们还可以使用计时单位类的介于()之间的方法。下面的代码演示了它的用法。
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
public class Demo
{
public static void main(String[] args)
{
LocalTime t1 = LocalTime.now();
LocalTime t2 = t1.plusHours(10).plusMinutes(5).plusSeconds(15);
long hours = ChronoUnit.HOURS.between(t2, t1);
long mins = ChronoUnit.MINUTES.between(t2, t1);
long secs = ChronoUnit.SECONDS.between(t2, t1);
System.out.println("Initial Time: " + t1 + " Final Time " + t2);
System.out.println("Difference in Hours: " + hours);
System.out.println("Difference in Minutes: " + mins);
System.out.println("Difference in Seconds: " + secs);
}
}
初始时间:17:57:29.308126300 最终时间 04:02:44.308126300 小时差:13 分钟差:834 秒差:50085
新旧班级之间的转换
Java 8 还支持将旧的 API 类转换成新的。我们将在日期和日历类实例上使用 LocalDateTime 类的 ofInstant() 方法和 toInstant() 方法来执行转换。下面的代码演示了这一点。
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
public class Demo
{
public static void main(String[] args)
{
Date d = new Date();
Calendar c = Calendar.getInstance();
LocalDateTime dateTime1 = LocalDateTime.ofInstant(d.toInstant(), ZoneId.systemDefault());
LocalDateTime dateTime2 = LocalDateTime.ofInstant(c.toInstant(), ZoneId.systemDefault());
System.out.println(dateTime1);
System.out.println(dateTime2);
}
}
2021-08-13t 18:06:18.030 2021-08-13t 18:06:18.055
格式化日期
Java 8 提供了一个 format() 函数,使用特定的模式将日期格式化为字符串。新的日期时间格式化器类允许我们使用预定义的模式。在下面的代码中,我们使用了一些预定义的日期格式。
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Demo
{
public static void main(String[] args)
{
LocalDateTime dateTime = LocalDateTime.now();
String dateStr1 = dateTime.format(DateTimeFormatter.ISO_WEEK_DATE);
String dateStr2 = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE);
String dateStr3 = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
System.out.println(dateStr1);
System.out.println(dateStr2);
System.out.print(dateStr3);
}
}
2021-W32-6 20210814 2021-08-14T 09:02:32.534666660606
DateTimeFormatter 类还允许我们定义自定义日期格式。让我们用两个星号来分隔日期的每个部分。
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Demo
{
public static void main(String[] args)
{
LocalDateTime dateTime = LocalDateTime.now();
String dateStr1= dateTime.format(DateTimeFormatter.ofPattern("dd ** MM ** YYYY"));
System.out.print(dateStr1);
}
}
2021 年 14 08 月
摘要
新的日期和时间 API 旨在解决现有 API 的问题。新的日期和时间类是不可变的和线程安全的。本地日期、本地时间和本地日期时间类是新 API 最常用的类。这些新类出现在 java.time 包中。它还提供了一个 ZonedDateTime 类来处理时区。现有的 API 也缺乏这一功能。