Java 8 推出了全新的日期时间API
8之前Java处理日期、日历和时间的方式一直为社区所诟病,将 java.util.Date设定为可变类型,以及SimpleDateFormat的非线程安全使其应用非常受限。
新API基于ISO标准日历系统,java.time包下的所有类都是不可变类型而且线程安全。
类的名称 | 描述 |
---|---|
Instant | 时间戳 |
Duration | 持续时间、时间差 |
LocalDate | 只包含日期,比如:2020-01-01 |
LocalTime | 只包含时间,比如:18:30:45 |
LocalDateTime | 包含日期和时间,比如:2020-01-01 22:24:45 |
Period | 时间段 |
ZoneOffset | 时间偏移量,比如:+8:30 |
ZonedDateTime | 带时区的时间 |
Clock | 时钟,比如获取目前的纽约时间 |
java.time.format.DateTimeFormatter | 时间格式化 |
1,获取当前日期,当前时间,日期+时间
Java 8 中的 LocalDate 用于表示当天日期。和java.util.Date不同,它只有日期,不包含时间。当你仅需要表示日期时就用这个类。
public static void main(String[] args) {
//获取今天的日期
LocalDate today = LocalDate.now();
System.out.println("今天的日期:"+today);
}
//Java 8中获取当前时间
LocalTime time = LocalTime.now();
System.out.println("获取当前的时间,不含有日期:"+time);
2,获取年月日
//获取年月日
LocalDate today = LocalDate.now();
int year = today.getYear();
int month = today.getMonthValue();
int day = today.getDayOfMonth();
System.out.println("year:"+year);
System.out.println("month:"+month);
System.out.println("day:"+day);
//获取年、月、日信息
public void getDetailDate(){
LocalDate today = LocalDate.now();
int year = today.getYear();
int month = today.getMonthValue();
int day = today.getDayOfMonth();
System.out.printf("Year : %d Month : %d day : %d t %n", year, month, day);
}
3,日期增加
通过增加小时、分、秒来计算将来的时间很常见。Java 8除了不变类型和线程安全的好处之外,还提供了更好的plusHours()方法替换add(),并且是兼容的。注意,这些方法返回一个全新的LocalTime实例,由于其不可变性,返回后一定要用变量赋值。
LocalTime time = LocalTime.now();
LocalTime newTime = time.plusHours(3);
System.out.println("三个小时后的时间为:"+newTime);
和上个例子计算3小时以后的时间类似,计算一周后的日期,LocalDate日期不包含时间信息,它的plus()方法用来增加天、周、月,ChronoUnit类声明了这些时间单位。由于LocalDate也是不变类型,返回后一定要用变量赋值。
LocalDate today = LocalDate.now();
System.out.println("今天的日期为:"+today);
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
System.out.println("一周后的日期为:"+nextWeek);
用同样的方法增加1个月、1年、1小时、1分钟甚至一个世纪,更多选项可以查看Java 8 API中的ChronoUnit类
LocalDate today = LocalDate.now();
LocalDate previousYear = today.minus(1, ChronoUnit.YEARS);
System.out.println("一年前的日期 : " + previousYear);
LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
System.out.println("一年后的日期:"+nextYear);
//计算一年前或一年后的日期
public void minusDate(){
LocalDate today = LocalDate.now();
LocalDate previousYear = today.minus(1, ChronoUnit.YEARS);
System.out.println("Date before 1 year : " + previousYear);
LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
System.out.println("Date after 1 year : " + nextYear);
}
Java 8中处理特定日期
我们通过静态工厂方法now()非常容易地创建了当天日期,你还可以调用另一个有用的工厂方法LocalDate.of()创建任意日期,该方法需要传入年、月、日做参数,返回对应的LocalDate实例。这个方法的好处是没再犯老API的设计错误,比如年度起始于1900,月份是从0开 始等等。
LocalDate date = LocalDate.of(2020,8,06);
System.out.println("自定义日期:"+date);
//处理特定日期
public void handleSpecilDate(){
LocalDate dateOfBirth = LocalDate.of(2018, 01, 21);
System.out.println("The specil date is : " + dateOfBirth);
}
Java 8中判断两个日期是否相等
LocalDate date1 = LocalDate.now();
LocalDate date2 = LocalDate.of(2020,8,07);
if(date1.equals(date2)){
System.out.println("时间相等");
}else{
System.out.println("时间不等");
}
//判断两个日期是否相等
public void compareDate(){
LocalDate today = LocalDate.now();
LocalDate date1 = LocalDate.of(2018, 01, 21);
if(date1.equals(today)){
System.out.printf("TODAY %s and DATE1 %s are same date %n", today, date1);
}
}
Java 8中检查像生日这种周期性事件
LocalDate date1 = LocalDate.now();
LocalDate date2 = LocalDate.of(2019,8,7);
MonthDay birthday = MonthDay.of(date2.getMonth(),date2.getDayOfMonth());
MonthDay currentMonthDay = MonthDay.from(date1);
if(currentMonthDay.equals(birthday)){
System.out.println("是你的生日");
}else{
System.out.println("你的生日还没有到");
}
//处理周期性的日期
public void cycleDate(){
LocalDate today = LocalDate.now();
LocalDate dateOfBirth = LocalDate.of(2018, 01, 21);
MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth());
MonthDay currentMonthDay = MonthDay.from(today);
if(currentMonthDay.equals(birthday)){
System.out.println("Many Many happy returns of the day !!");
}else{
System.out.println("Sorry, today is not your birthday");
}
}
Java 8的Clock时钟类
Java 8增加了一个Clock时钟类用于获取当时的时间戳,或当前时区下的日期时间信息。以前用到System.currentTimeInMillis()和TimeZone.getDefault()的地方都可用Clock替换。
Clock clock = Clock.systemUTC();
System.out.println("Clock : " + clock.millis());
Clock defaultClock = Clock.systemDefaultZone();
System.out.println("Clock : " + defaultClock.millis());
public void clock(){
// 根据系统时间返回当前时间并设置为UTC。
Clock clock = Clock.systemUTC();
System.out.println("Clock : " + clock);
// 根据系统时钟区域返回时间
Clock defaultClock = Clock.systemDefaultZone();
System.out.println("Clock : " + clock);
}
判断日期是早于还是晚于另一个日期
工作中常见的操作就是如何判断给定的一个日期是大于某天还是小于某天?在Java 8中,LocalDate类有两类方法isBefore()和isAfter()用于比较日期。调用isBefore()方法时,如果给定日期小于当前日期则返回true。
LocalDate today = LocalDate.now();
LocalDate tomorrow = LocalDate.of(2020,8,8);
if(tomorrow.isAfter(today)){
System.out.println("之后的日期:"+tomorrow);
}
LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
if(yesterday.isBefore(today)){
System.out.println("之前的日期:"+yesterday);
}
//如何用Java判断日期是早于还是晚于另一个日期
public void isBeforeOrIsAfter(){
LocalDate today = LocalDate.now();
LocalDate tomorrow = LocalDate.of(2018, 1, 29);
if(tomorrow.isAfter(today)){
System.out.println("Tomorrow comes after today");
}
//减去一天
LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
if(yesterday.isBefore(today)){
System.out.println("Yesterday is day before today");
}
}
Java 8中处理时区
Java 8不仅分离了日期和时间,也把时区分离出来了。现在有一系列单独的类如ZoneId来处理特定时区,ZoneDateTime类来表示某时区下的时间。这在Java 8以前都是 GregorianCalendar类来做的。下面这个例子展示了如何把本时区的时间转换成另一个时区的时间。
ZoneId america = ZoneId.of("America/New_York");
LocalDateTime localtDateAndTime = LocalDateTime.now();
ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localtDateAndTime, america );
System.out.println("Current date and time in a particular timezone : " + dateAndTimeInNewYork);
//获取特定时区下面的时间
public void getZoneTime(){
//设置时区
ZoneId america = ZoneId.of("America/New_York");
LocalDateTime localtDateAndTime = LocalDateTime.now();
ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localtDateAndTime, america );
System.out.println("现在的日期和时间在特定的时区 : " + dateAndTimeInNewYork);
}
表示信用卡到期这类固定日期,答案就在YearMonth
与 MonthDay检查重复事件的例子相似,YearMonth是另一个组合类,用于表示信用卡到期日、FD到期日、期货期权到期日等。还可以用这个类得到 当月共有多少天,YearMonth实例的lengthOfMonth()方法可以返回当月的天数,在判断2月有28天还是29天时非常有用。
YearMonth currentYearMonth = YearMonth.now();
System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
YearMonth creditCardExpiry = YearMonth.of(2019, Month.FEBRUARY);
System.out.printf("Your credit card expires on %s %n", creditCardExpiry);
//使用 YearMonth类处理特定的日期
public void checkCardExpiry(){
YearMonth currentYearMonth = YearMonth.now();
System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
YearMonth creditCardExpiry = YearMonth.of(2028, Month.FEBRUARY);
System.out.printf("Your credit card expires on %s %n", creditCardExpiry);
}
Java 8中检查闰年
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 8中可以用java.time.Period类来做计算。
下面这个例子中,我们计算了当天和将来某一天之间的月数。
LocalDate today = LocalDate.now();
LocalDate java8Release = LocalDate.of(2021, 12, 14);
Period periodToNextJavaRelease = Period.between(today, java8Release);
System.out.println("Months left between today and Java 8 release : "
+ periodToNextJavaRelease.getMonths() );
只能获取相差的月数,查看API获取相差年数
//计算两个日期之间的天数和月数
public void calcDateDays(){
LocalDate today = LocalDate.now();
LocalDate java8Release = LocalDate.of(2018, Month.MAY, 14);
Period periodToNextJavaRelease = Period.between(today, java8Release);
System.out.println("Months left between today and Java 8 release : "
+ periodToNextJavaRelease.getMonths() );
}
Java 8中获取当前的时间戳
Instant类有一个静态工厂方法now()会返回当前的时间戳,如下所示:
Instant timestamp = Instant.now();
System.out.println("What is value of this instant " + timestamp.toEpochMilli());
时间戳信息里同时包含了日期和时间,这和java.util.Date很像。实际上Instant类确实等同于 Java 8之前的Date类,你可以使用Date类和Instant类各自的转换方法互相转换,例如:Date.from(Instant) 将Instant转换成java.util.Date,Date.toInstant()则是将Date类转换成Instant类。
包含时差的时间
ZoneOffset类用来表示时区,举例来说印度与GMT或UTC标准时区相差+05:30,可以通过ZoneOffset.of()静态方法来 获取对应的时区。一旦得到了时差就可以通过传入LocalDateTime和ZoneOffset来创建一个OffSetDateTime对象。
public void ZoneOffset(){
LocalDateTime datetime = LocalDateTime.of(2018, Month.FEBRUARY, 14, 19, 30);
ZoneOffset offset = ZoneOffset.of("+05:30");
OffsetDateTime date = OffsetDateTime.of(datetime, offset);
System.out.println("Date and Time with timezone offset in Java : " + date);
}
测试代码
public class DateTest {
//获取今天的日期
public void getCurrentDate(){
LocalDate today = LocalDate.now();
System.out.println("Today's Local date : " + today);
//这个是作为对比
Date date = new Date();
System.out.println(date);
}
//获取年、月、日信息
public void getDetailDate(){
LocalDate today = LocalDate.now();
int year = today.getYear();
int month = today.getMonthValue();
int day = today.getDayOfMonth();
System.out.printf("Year : %d Month : %d day : %d t %n", year, month, day);
}
//处理特定日期
public void handleSpecilDate(){
LocalDate dateOfBirth = LocalDate.of(2018, 01, 21);
System.out.println("The specil date is : " + dateOfBirth);
}
//判断两个日期是否相等
public void compareDate(){
LocalDate today = LocalDate.now();
LocalDate date1 = LocalDate.of(2018, 01, 21);
if(date1.equals(today)){
System.out.printf("TODAY %s and DATE1 %s are same date %n", today, date1);
}
}
//处理周期性的日期
public void cycleDate(){
LocalDate today = LocalDate.now();
LocalDate dateOfBirth = LocalDate.of(2018, 01, 21);
MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth());
MonthDay currentMonthDay = MonthDay.from(today);
if(currentMonthDay.equals(birthday)){
System.out.println("Many Many happy returns of the day !!");
}else{
System.out.println("Sorry, today is not your birthday");
}
}
//获取当前时间
public void getCurrentTime(){
LocalTime time = LocalTime.now();
System.out.println("local time now : " + time);
}
//增加小时
public void plusHours(){
LocalTime time = LocalTime.now();
LocalTime newTime = time.plusHours(2); // 增加两小时
System.out.println("Time after 2 hours : " + newTime);
}
//如何计算一周后的日期
public void nextWeek(){
LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
System.out.println("Today is : " + today);
System.out.println("Date after 1 week : " + nextWeek);
}
//计算一年前或一年后的日期
public void minusDate(){
LocalDate today = LocalDate.now();
LocalDate previousYear = today.minus(1, ChronoUnit.YEARS);
System.out.println("Date before 1 year : " + previousYear);
LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
System.out.println("Date after 1 year : " + nextYear);
}
public void clock(){
// 根据系统时间返回当前时间并设置为UTC。
Clock clock = Clock.systemUTC();
System.out.println("Clock : " + clock);
// 根据系统时钟区域返回时间
Clock defaultClock = Clock.systemDefaultZone();
System.out.println("Clock : " + clock);
}
//如何用Java判断日期是早于还是晚于另一个日期
public void isBeforeOrIsAfter(){
LocalDate today = LocalDate.now();
LocalDate tomorrow = LocalDate.of(2018, 1, 29);
if(tomorrow.isAfter(today)){
System.out.println("Tomorrow comes after today");
}
LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
if(yesterday.isBefore(today)){
System.out.println("Yesterday is day before today");
}
}
//时区处理
public void getZoneTime(){
//设置时区
ZoneId america = ZoneId.of("America/New_York");
LocalDateTime localtDateAndTime = LocalDateTime.now();
ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localtDateAndTime, america );
System.out.println("现在的日期和时间在特定的时区 : " + dateAndTimeInNewYork);
}
//使用 YearMonth类处理特定的日期
public void checkCardExpiry(){
YearMonth currentYearMonth = YearMonth.now();
System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
YearMonth creditCardExpiry = YearMonth.of(2028, Month.FEBRUARY);
System.out.printf("Your credit card expires on %s %n", creditCardExpiry);
}
//检查闰年
public void isLeapYear(){
LocalDate today = LocalDate.now();
if(today.isLeapYear()){
System.out.println("This year is Leap year");
}else {
System.out.println("2018 is not a Leap year");
}
}
//计算两个日期之间的天数和月数
public void calcDateDays(){
LocalDate today = LocalDate.now();
LocalDate java8Release = LocalDate.of(2018, Month.MAY, 14);
Period periodToNextJavaRelease = Period.between(today, java8Release);
System.out.println("Months left between today and Java 8 release : "
+ periodToNextJavaRelease.getMonths() );
}
// 包含时差信息的日期和时间
public void ZoneOffset(){
LocalDateTime datetime = LocalDateTime.of(2018, Month.FEBRUARY, 14, 19, 30);
ZoneOffset offset = ZoneOffset.of("+05:30");
OffsetDateTime date = OffsetDateTime.of(datetime, offset);
System.out.println("Date and Time with timezone offset in Java : " + date);
}
// 获取时间戳
public void getTimestamp(){
Instant timestamp = Instant.now();
System.out.println("What is value of this instant " + timestamp);
}
// 使用预定义的格式化工具去解析或格式化日期
public void formateDate(){
String dayAfterTommorrow = "20180210";
LocalDate formatted = LocalDate.parse(dayAfterTommorrow, DateTimeFormatter.BASIC_ISO_DATE);
System.out.printf("Date generated from String %s is %s %n", dayAfterTommorrow, formatted);
}
public static void main(String[] args) {
DateTest dt = new DateTest();
dt.formateDate();
}
}
Java 8中使用格式化工具去解析或格式化日期
String dayAfterTommorrow = "20200807";
LocalDate formatted = LocalDate.parse(dayAfterTommorrow,
DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(dayAfterTommorrow+" 格式化后的日期为: "+formatted);
LocalDateTime date = LocalDateTime.now();
DateTimeFormatter format1 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
//日期转字符串
String str = date.format(format1);
System.out.println("日期转换为字符串:"+str);
DateTimeFormatter format2 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
//字符串转日期
LocalDate date2 = LocalDate.parse(str,format2);
System.out.println("日期类型:"+date2);
public class LocalDateTimeUtils {
/**
* 根据指定的格式来格式化一个日期<br/>
* 本方法不会返回null<br/>
* 格式化字符串中:<br/>
* <p>y 代表<b>年</b></p>
* <p>M 代表<b>月</b></p>
* <p>d 代表<b>日</b></p>
* <p>h 代表<b>十二进制的小时</b></p>
* <p>H 代表<b>二十四进制的小时</b></p>
* <p>m 代表<b>分钟</b></p>
* <p>s 代表<b>秒</b></p>
* <p>f 代表<b>毫秒</b></p>
*
* @param localDateTime 需要格式化的时间
* @param pattern 格式化
* @param locale 本地化
* @return 格式化后的字符串
*/
public static String format(LocalDateTime localDateTime, String pattern, Locale locale) {
if (localDateTime == null || pattern == null || pattern.length() == 0) {
return "";
}
return localDateTime.format(DateTimeFormatter.ofPattern(pattern, locale));
}
/**
* 根据指定的格式来格式化一个日期<br/>
* 本方法不会返回null<br/>
* 格式化字符串中:<br/>
* <p>y 代表<b>年</b></p>
* <p>m 代表<b>月</b></p>
* <p>d 代表<b>日</b></p>
* <p>h 代表<b>十二进制的小时</b></p>
* <p>H 代表<b>二十四进制的小时</b></p>
* <p>M 代表<b>分钟</b></p>
* <p>s 代表<b>秒</b></p>
* <p>f 代表<b>毫秒</b></p>
*
* @param localDateTime 需要格式化的时间
* @param pattern 格式化
* @return 格式化后的字符串
*/
public static String format(LocalDateTime localDateTime, String pattern) {
return format(localDateTime, pattern, Locale.getDefault());
}
/**
* 把日期格式化为"yyyy-MM-dd"的字符串
*
* @param localDateTime 需要格式化的日期
* @return "yyyy-MM-dd"样式的字符串
*/
public static String formatDate(LocalDateTime localDateTime) {
return format(localDateTime, "yyyy-MM-dd");
}
/**
* 把日期格式化为"yyyy-MM-dd HH:mm:ss"的字符串
*
* @param localDateTime 需要格式化的日期
* @return "yyyy-MM-dd HH:mm:ss"样式的字符串
*/
public static String formatDateTime(LocalDateTime localDateTime) {
return format(localDateTime, "yyyy-MM-dd HH:mm:ss");
}
/**
* 把日期格式化为"HH:mm:ss"的字符串
*
* @param localDateTime 需要格式化的日期
* @return "HH:mm:ss"样式的字符串
*/
public static String formatTime(LocalDateTime localDateTime) {
return format(localDateTime, "HH:mm:ss");
}
/**
* 把其他类型转换为{@link java.time.LocalDateTime}类型<br/>
* 本方法不会返回null,<b>当入参不在以下支持的类型列表中,会采用toString()准换为字符串后提供支持</b><br/>
* 本方法支持以下类型<br/>
* {@link java.sql.Date}<br/>
* {@link java.util.Date}<br/>
* {@link java.sql.Timestamp}<br/>
* {@link java.lang.String}<br/>
* 毫秒数的{@link java.lang.Long}<br/>
*
* @param obj 需要转换为LocalDateTime的对象
* @return LocalDateTime对象
*/
public static LocalDateTime parseToLocalDateTime(Object obj) {
if (obj == null) {
return LocalDateTime.now();
}
if (obj instanceof java.util.Date) {
return ((java.util.Date) obj).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
}
if (obj instanceof String) {
return LocalDateTime.parse((String) obj);
}
if (obj instanceof java.lang.Long) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli((long) obj), ZoneId.systemDefault());
}
return parseToLocalDateTime(obj.toString());
}
/**
* 获取到毫秒的时间戳
*
* @param localDateTime 时间
* @return 毫秒的时间戳
*/
public static long toMilli(LocalDateTime localDateTime) {
return localDateTime.toInstant(ZoneOffset.of(ZoneOffset.systemDefault().getId())).toEpochMilli();
}
/**
* 获取到秒的时间戳
*
* @param localDateTime 时间
* @return 秒的时间戳
*/
public static long toSecond(LocalDateTime localDateTime) {
return localDateTime.toInstant(ZoneOffset.of(ZoneOffset.systemDefault().getId())).getEpochSecond();
}
/**
* 获取月初
*
* @param localDateTime 日期时间
* @return 指定日期的月初
*/
public static LocalDateTime getMonthHeader(LocalDateTime localDateTime) {
return localDateTime.with(TemporalAdjusters.firstDayOfMonth());
}
public static LocalDateTime getLastofMonth(LocalDateTime localDateTime) {
return localDateTime.with(TemporalAdjusters.lastDayOfMonth());
}
}