Java处理日期、日历和时间的方式一直为社区所诟病,将 java.util.Date设定为可变类型,以及SimpleDateFormat的非线程安全使其应用非常受限。
Java 8 推出了全新的日期时间API,在教程中我们将通过一些简单的实例来学习如何使用新API。
新API基于ISO标准日历系统,java.time包下的所有类都是不可变类型而且线程安全。
| 类的名称 | 描述 |
|---|---|
| java.time.Instant | 时间戳 |
| java.time.Duration | 持续时间,时间差 |
| java.time.LocalDate | 只包含日期,比如:2018-02-05 |
| java.time.MonthDay | 只包含月日,比如:02-05 |
| java.time.LocalTime | 只包含时间,比如:23:12:10 |
| java.time.LocalDateTime | 包含日期和时间,比如:2018-02-05 23:14:21 |
| java.time.Period | 时间段 |
| java.time.ZoneId | 时区id,比如 Asia/Shanghai |
| java.time.ZoneOffset | 时区偏移量,比如:+8:00 |
| java.time.ZonedDateTime | 带时区的时间 |
| java.time.Clock | 时钟,比如获取目前美国纽约的时间 |
| java.time.format.DateTimeFormatter | 时间格式化 |
java.time.Instant
Instant 类有一个静态工厂方法 now() 会返回当前的时间戳
import java.time.Instant;
public class Demo {
public static void main(String[] args) {
Instant timestamp = Instant.now();
System.out.println("What is value of this instant " + timestamp.toEpochMilli());
}
}
时间戳信息里同时包含了日期和时间,这和 java.util.Date 很像。实际上 Instant 类确实等同于 Java 8 之前的 Date 类,你可以使用 Date 类 和 Instant 类各自的转换方法互相转换。
例如:
将 Instant 转换成 java.util.Date
Date.from(Instant)
将 java.util.Date 转换成 Instant 类
Date.toInstant()
java.time.Duration
java.time.LocalDate
java 8 中的 LocalDate 用于表示当天日期。和 java.util.Date 不同,它只有日期,不包含时间。当你仅需要表示日期时就用这个类。
获取当前日期
import java.time.LocalDate;
public class Demo {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
}
}
获取当前 年、月、日
import java.time.LocalDate;
public class Demo {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
int year = today.getYear();
int month = today.getMonthValue();
int day = today.getDayOfMonth();
}
}
我们通过静态工厂方法 now() 非常容易地创建了当天日期。
你还可以调用另一个有用的工厂方法 LocalDate.of() 创建任意日期。 该方法需要传入年、月、日做参数,返回对应的 LocalDate 实例。这个方法的好处是没再犯老 API 的设计错误(比如年度起始于 1900,月份是从 0 开始等等)。
指定年月日
import java.time.LocalDate;
public class Demo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2020,3,17);
}
}
判断两个日期是否相等
import java.time.LocalDate;
public class Demo {
public static void main(String[] args) {
LocalDate date1 = LocalDate.now();
LocalDate date2 = LocalDate.of(2020,3,17);
if(date1.equals(date2)){
System.out.println("时间相等");
}else{
System.out.println("时间不等");
}
}
}
LocalDate 日期不包含时间信息,它的 plus() 方法用来增加天、周、月,ChronoUnit 类声明了这些时间单位。由于 LocalDate 是不变类型,返回后一定要用变量赋值。
增加日期
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class Demo {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
System.out.println("今天的日期为:"+today);
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
System.out.println("一周后的日期为:"+nextWeek);
}
}
可以看到新日期离当天日期是7天,也就是一周。你可以用同样的方法增加1个月、1年、1小时、1分钟甚至一个世纪,更多选项可以查看Java 8 API中的ChronoUnit类
判断日期是早于还是晚于另一个日期 LocalDate类有两类方法isBefore()和isAfter()用于比较日期。调用isBefore()方法时,如果给定日期小于当前日期则返回true。
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class Demo {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate tomorrow = LocalDate.of(2018,2,6);
if(tomorrow.isAfter(today)){
System.out.println("之后的日期:"+tomorrow);
}
LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
if(yesterday.isBefore(today)){
System.out.println("之前的日期:"+yesterday);
}
}
}
检查闰年
import java.time.LocalDate;
public class Demo {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
if(today.isLeapYear()){
System.out.println("This year is Leap year");
}else {
System.out.println("This year is not a Leap year");
}
}
}
java.time.MonthDay
MonthDay 只包含月和日,比较适合周期性的事件,比如生日
检查生日这种周期性事件
import java.time.MonthDay;
public class Demo {
public static void main(String[] args) {
MonthDay birthday = MonthDay.of(3,17);
MonthDay currentMonthDay = MonthDay.now();
if(currentMonthDay.equals(birthday)){
System.out.println("是你的生日");
}
}
}
java.time.LocalTime
LocalTime 只包含时分秒
获取当前时间
import java.time.LocalTime;
public class Demo {
public static void main(String[] args) {
LocalTime time = LocalTime.now();
System.out.println("获取当前的时间,不含有日期:" + time);
}
}
通过增加小时、分、秒来计算将来的时间很常见。Java 8 除了不变类型和线程安全的好处之外,还提供了更好的 plusHours() 方法替换 add() ,并且是兼容的。注意,这些方法返回一个全新的 LocalTime 实例,由于其不可变性,返回后一定要用变量赋值。
增加时间
import java.time.LocalTime;
public class Demo {
public static void main(String[] args) {
LocalTime time = LocalTime.now();
LocalTime newTime = time.plusHours(3);
System.out.println("三个小时后的时间为:" + newTime);
}
}
java.time.LocalDateTime
初始化时间
LocalDateTime dateTime = LocalDateTime.now();
LocalDateTime dateTime = LocalDateTime.of(2020, 8, 8, 0, 0);
加一个小时
LocalDateTime dateTime = LocalDateTime.now();
LocalDateTime newDateTime = dateTime.plusHours(1)
一减个小时
LocalDateTime dateTime = LocalDateTime.now();
LocalDateTime newDateTime = dateTime.minusHours(1)
格式化
LocalDateTime dateTime = LocalDateTime.now();
String time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(dateTime)
java.time.ZonedDateTime、java.time.ZoneId
Java 8 不仅分离了日期和时间,也把时区分离出来了。现在有一系列单独的类如 ZoneId 来处理特定时区,ZoneDateTime 类来表示某时区下的时间。在 Java 8 以前这都是 GregorianCalendar 类来做的。
把本时区的时间转换成另一个时区的时间
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Demo {
public static void main(String[] args) {
LocalDateTime localDateTime = LocalDateTime.now();
ZoneId shanghai = ZoneId.of("Asia/Shanghai");
ZonedDateTime shanghaiDateTime = ZonedDateTime.of(localDateTime, shanghai );
}
}
java.time.Period
Period 用于表示时间段
计算两个日期之间的天数、周数或月数
import java.time.LocalDate;
import java.time.Period;
public class Demo {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate date = LocalDate.of(2018, 12, 14);
Period period = Period.between(today, date);
System.out.println("相差" + period.getMonths() + "个月");
}
}
java.time.format.DateTimeFormatter
DateTimeFormatter 用来 解析或格式化日期
格式化日期
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class Demo {
public static void main(String[] args) {
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println("格式化后的日期为:" + formatter.format(localDateTime));
}
}
解析格式化日期
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class Demo {
public static void main(String[] args) {
String dateString = "2020-02-03 11:22:33";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.parse(dateString,formatter);
}
}
java.time.Clock
Java 8增加了一个Clock时钟类用于获取当时的时间戳,或当前时区下的日期时间信息。以前用到System.currentTimeInMillis()和TimeZone.getDefault()的地方都可用Clock替换
import java.time.Clock;
public class Demo {
public static void main(String[] args) {
// Returns the current time based on your system clock and set to UTC.
Clock clock = Clock.systemUTC();
System.out.println("Clock : " + clock.millis());
// Returns time based on system clock zone
Clock defaultClock = Clock.systemDefaultZone();
System.out.println("Clock : " + defaultClock.millis());
}
}