1.JDK8新特性之日期处理
1.1.带着问题学习
1.jdk8日期和 java.util.Date有哪些不同?
2.jdk8解决了哪些复杂的日期问题和提供了哪些现成的方法?
1.2.基本介绍
JDK8推出了lambda表达式、streams流、日期这些新特性以及一系列小优化,在这里主要介绍日期。
Java处理日期、日历和时间的不足之处:将 java.util.Date 设定为可变类型,以及 SimpleDateFormat 的非线程安全使其应用非常受限。然后 jdk8 中替换了SimpleDateFormat,在上面增加新的特性。
全新API的众多好处之一就是,明确了日期时间概念,例如:瞬时(instant)、长短(duration)、日期、时间、时区和周期。
同时继承了Joda 库按人类语言和计算机各自解析的时间处理方式。不同于老版本,新API基于ISO标准日历系统,java.time包下的所有类都是不可变类型而且线程安全。
注意:不要总想着把jdk8的LocalDate转换成Date,直接使用LocalDate替换Date就行了,包括数据库对应的Date属性。
1.3.关键类
- Instant:瞬时实例。
- LocalDate:本地日期,不包含具体时间 例如:2014-01-14 可以用来记录生日、纪念日、加盟日等。
- LocalTime:本地时间,不包含日期,但是包含毫秒值,例如:获取当前时间 含有毫秒值 17:18:41.571,去掉毫秒值可以用LocalTime.now().withNano(0)。
- LocalDateTime:组合了日期和时间,但不包含时差和时区信息。
- ZonedDateTime:最完整的日期时间,包含时区和相对UTC或格林威治的时差。
新API还引入了 ZoneOffSet 和 ZoneId 类,使得解决时区问题更为简便。解析、格式化时间的DateTimeFormatter类也全部重新设计。
2.怎么使用
2.1.LocalDate
/**
* 处理日期 LocalDate
*/
@Test
public static void localDateTest() {
// 获取当前日期 2020-06-16
LocalDate today = LocalDate.now();
System.out.println(today);
// 构造日期 2020-06-16
LocalDate today2 = LocalDate.of(2020, 6, 16);
System.out.println(today2);
// 构造日期 2020-06-16 字符串严格按照yyyy-MM-dd
LocalDate today3 = LocalDate.parse("2020-06-16");
System.out.println(today3);
// 本月第一天 2020-06-01
LocalDate firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth());
System.out.println(firstDayOfMonth);
// 本月第二天 2020-06-02 第n天
LocalDate secondDayOfMonth = today.withDayOfMonth(2);
System.out.println(secondDayOfMonth);
// 本月最后一天 2020-06-30 方便解决任何年份的二月份多少天
LocalDate lastDayOfMonth = today3.with(TemporalAdjusters.lastDayOfMonth());
System.out.println(lastDayOfMonth);
// 获取2020年12月的第一个周一 2020-12-07
LocalDate firstDayOf201712 = LocalDate.parse("2020-12-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
System.out.println(firstDayOf201712);
}
结果
2020-06-16
2020-06-16
2020-06-16
2020-06-01
2020-06-02
2020-06-30
2020-12-07
2.2.LocalTime
/**
* 处理时间 LocalTime
*/
@Test
public static void localTimeTest() {
//获取当前时间 含有毫秒值 17:18:41.571
LocalTime now = LocalTime.now();
System.out.println(now);
//获取当前时间 去掉毫秒值 17:45:41
LocalTime now1 = LocalTime.now().withNano(0);
System.out.println(now1);
//00:46:46.651 提供了把时分秒都设为0的方法
LocalTime now2 = LocalTime.now().withHour(0);
System.out.println(now2);
//构造时间 00:20:55
LocalTime time1 = LocalTime.of(0, 20, 55);
System.out.println(time1);
//构造时间 05:43:22
LocalTime time2 = LocalTime.parse("05:43:22");
System.out.println(time2);
//标准时间 2020-06-16T17:53:15.930
LocalDateTime lt = LocalDateTime.now();
System.out.println(lt);
}
结果
12:41:49.366
12:41:49
00:41:49.366
00:20:55
05:43:22
2020-06-16T12:41:49.378
2.3.LocalDateTime
/**
* 处理时间 LocalDateTime
*/
@Test
public static void localDateTimeTest() {
LocalDateTime time = LocalDateTime.now();
// 字符串表示
System.out.println(time.toString());
// 获取时间(LocalTime)
System.out.println(time.toLocalTime());
// 获取日期(LocalDate)
System.out.println(time.toLocalDate());
// 获取当前时间月份的第几天
System.out.println(time.getDayOfMonth());
// 获取当前周的第几天
System.out.println(time.getDayOfWeek());
// 获取当前时间在该年属于第几天
System.out.println(time.getDayOfYear());
System.out.println(time.getHour());
System.out.println(time.getMinute());
System.out.println(time.getMonthValue());
System.out.println(time.getMonth());
System.out.println("-----------------------------------");
// 格式化输出
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY/MM/dd HH:mm:ss");
System.out.println(time.format(formatter));
// 格式化输出
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(time.format(formatter2));
// 格式化输出
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("HH:mm");
System.out.println(time.format(formatter3));
// 构造时间
LocalDateTime startTime = LocalDateTime.of(2018, 1, 1, 20, 31, 20);
LocalDateTime endTime = LocalDateTime.of(2018, 1, 3, 20, 31, 20);
// 比较时间
System.out.println(time.isAfter(startTime));
System.out.println(time.isBefore(endTime));
// 时间运算,相加相减
System.out.println(time.plusYears(2)); // 加2年
System.out.println(time.plusDays(2)); // 加两天
System.out.println(time.minusYears(2)); // 减两年
System.out.println(time.minusDays(2)); // 减两天
// 获取毫秒数(使用Instant)
System.out.println(time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
// 获取秒数(使用Instant)
System.out.println(time.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond());
}
结果
2020-06-16T12:43:03.232
12:43:03.232
2020-06-16
16
TUESDAY
168
12
43
6
JUNE
-----------------------------------
2020/06/16 12:43:03
2020-06-16 12:43:03
12:43
true
false
2022-06-16T12:43:03.232
2020-06-18T12:43:03.232
2018-06-16T12:43:03.232
2020-06-14T12:43:03.232
1592282583232
1592282583
2.4.LocalDate和Date互转
import org.junit.Test;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;
/**
* Jdk8 日期辅助类
* @author zhiqiang.feng
* @date-time 2020/1/16 17:04
**/
public class DateUtil {
/**
* 将LocalDateTime转为自定义的时间格式的字符串
*
* @param localDateTime
* @param format
* @return
*/
public static String getDateTimeAsString(LocalDateTime localDateTime, String format) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
return localDateTime.format(formatter);
}
/**
* 将long类型的timestamp转为LocalDateTime
*
* @param timestamp
* @return
*/
public static LocalDateTime getDateTimeOfTimestamp(long timestamp) {
Instant instant = Instant.ofEpochMilli(timestamp);
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone);
}
/**
* 将LocalDateTime转为long类型的timestamp
*
* @param localDateTime
* @return
*/
public static long getTimestampOfDateTime(LocalDateTime localDateTime) {
ZoneId zone = ZoneId.systemDefault();
Instant instant = localDateTime.atZone(zone).toInstant();
return instant.toEpochMilli();
}
/**
* 将某时间字符串转为自定义时间格式的LocalDateTime
*
* @param time
* @param format
* @return
*/
public static LocalDateTime parseStringToDateTime(String time, String format) {
DateTimeFormatter df = DateTimeFormatter.ofPattern(format);
return LocalDateTime.parse(time, df);
}
/**
* Date -> LocalDate
*
* @param date
* @return
*/
public static LocalDate transDateToLocalDate(Date date) {
// atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
}
/**
* LocalDate->Date
*
* @param localDate
* @return
*/
public static Date transLocalDateToDate(LocalDate localDate) {
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
}
/**
* Date -> LocalDateTime
*
* @param date
* @return
*/
public static LocalDateTime transDateToLocalDateTime(Date date) {
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}
/**
* LocalDateTime -> Date
*
* @param localDateTime
* @return
*/
private static Date transLocalDateTimeToDate(LocalDateTime localDateTime) {
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
}
/**
* Date -> LocalTime
*
* @param date
* @return
*/
public static LocalTime transDateToLocalTime(Date date) {
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
}
/**
* LocalTime -> Date
*
* @param localTime
* @return
*/
private static Date transLocalTimeToDate(LocalTime localTime) {
return Date.from(LocalDateTime.of(LocalDate.now(), localTime)
.atZone(ZoneId.systemDefault()).toInstant());
}
}
3.总结
1.jdk8的DateTimeFormatter是线程安全的,而SimpleDateFormat不是线程安全的。
2.LocalDate:本地日期,不包含具体时间 例如:2014-01-14 可以用来记录生日、纪念日、加盟日等。
3.LocalTime:本地时间,不包含日期,但是包含毫秒值,例如:获取当前时间 含有毫秒值 17:18:41.571,去掉毫秒值可以用LocalTime.now().withNano(0)。
4.LocalDateTime:组合了日期和时间,但不包含时差和时区信息。
5.ZonedDateTime:最完整的日期时间,包含时区和相对UTC或格林威治的时差。
4.参考
Java8新特性之日期处理(也总结的很好):
https://segmentfault.com/a/1190000012922933