Java 8中新增了新的日期处理包java.time,解决了jdk 1.7之前日期类Calendar,DateFormat线程不安全的问题,为了熟悉API特地学习了一下,写此博客作为记录,并分享给大家。
详细使用方法请参考下面的代码:
package top.jacktgq.demo2;
import java.sql.Timestamp;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.MonthDay;
import java.time.Period;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalQuery;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;
import java.util.TimeZone;
import org.junit.Test;
/**
*
* @Title: Java8TimeClassesMethodTest.java
* @Package top.jacktgq.demo2
* @Description: Date-Time API中的所有类均生成不可变实例,他们是线程安全的,并且这些类不提供公共构造函数,
* 也就是说没办法通过new的方式直接创建,需要采用工厂方法加以实例化。
* @author CandyWall
* @date 2020年5月13日 下午3:08:37
* @version V1.0
*/
public class Java8TimeClassesMethodTest {
@Test
/**
* now()方法入门
*/
public void demo1() {
//使用now方法创建Instant类的实例对象
Instant instantNow = Instant.now();
//使用now方法创建LocalDate类的实例对象
LocalDate localDateNow = LocalDate.now();
//使用now方法创建LocalTime类的实例对象
LocalTime localTimeNow = LocalTime.now();
//使用now方法创建LocalDateTime类的实例对象
LocalDateTime localDateTime = LocalDateTime.now();
//将实例对象都打印到控制台查看内容
System.out.println("Instant" + "\t:" + instantNow);
System.out.println("LocalDate" + "\t:" + localDateNow);
System.out.println("LocalTime" + "\t:" + localTimeNow);
System.out.println("LocalDateTime" + "\t:" + localDateTime);
}
@Test
/**
* 使用now()方法创建Year、YearMonth、MonthDay类的实例
*/
public void demo2() {
//使用now()方法创建Year类的实例
Year year = Year.now();
//使用now()YearMonth类的实例
YearMonth yearMonth = YearMonth.now();
//使用now()MonthDay类的实例
MonthDay monthDay = MonthDay.now();
System.out.println("Year:" + "\t:" + year);
System.out.println("YearMonth:" + "\t:" + yearMonth);
System.out.println("MonthDay:" + "\t:" + monthDay);
}
@Test
/**
* of()方法
*/
public void demo3() {
//初始化2020年5月13日的LocalDate对象
LocalDate localDate = LocalDate.of(2020, 5, 13);
System.out.println("LocalDate:" + "\t:" + localDate);
//初始化下午3:30分30秒的LocalTime对象 -> 如果是晚上的时间,需要加12.
//LocalTime.of()方法的重载形式有以下几种,可以根据实际情况自行使用。
//LocalTime.of(int hour, int minute) -> 根据小时/分钟生成对象。
//LocalTime.of(int hour, int minute, int second) -> 根据小时/分钟/秒生成对象
//LocalTime.of(int hour, int minute, int second, int nanoOfSecond) -> 根据小时/分钟/秒/毫秒/纳生成对象
//注意:如果秒和纳秒都是0的话,那么默认不会封装这些数据,只显示小时和分钟
LocalTime localTime = LocalTime.of(15, 30, 30, 90);
System.out.println("LocalTime:" + "\t:" + localTime);
//初始化2020年5月13日 下午3:30分30秒的LocalDateTime对象
//LocalDateTime.of()方法的重载形式有以下几种,可以根据实际情况自行使用
//LocalDateTime.of(int year, int month, int dayofMonth, int hour, int minute) -> 根据 年/月/日/时/分 生成对象
//LocalDateTime.of(int year, int month, int dayofMonth, int hour, int minute, int second, int nanoOfSecond) -> 根据 年/月/日/时/分/秒/纳秒 生成对象
LocalDateTime localDateTime = LocalDateTime.of(2020, 5, 13, 15, 30, 30, 90);
System.out.println("LocalDateTime:" + "\t:" + localDateTime);
//LocalDateTime的of()方法的特殊用法:
//LocalDateTime.of(LocalDate localDate, LocalTime localTime)
System.out.println("LocalDateTime的of()方法的特殊用法:" + LocalDateTime.of(localDate, localTime));
}
@Test
/**
* 时区相关
*/
public void demo4() {
//获取所有的时区信息
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
for(String zoneId : availableZoneIds) {
System.out.println(zoneId);
}
//获取当前系统默认的时区信息 -> 中国
System.out.println("系统默认时区:" + ZoneId.systemDefault());
}
@Test
/**
* 为LocalDateTime添加时区信息
*/
public void demo5() {
//1、封装LocalDateTime对象,参数自定义 -> 2020年5月14日 15点00分38秒
LocalDateTime localDateTime = LocalDateTime.of(2020, 5, 14, 15, 0, 38);
//2、LocalDateTime对象现在只是封装了一个时间,并没有时区相关的数据,所以需要添加时区信息到对象中,使用atZone()方法
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println("Asia/Shanghai对应的当前时间是:" + zonedDateTime);
//3、更改时区查看其它时区的当前时间,通过withZoneSameInstant()方法即可更改
ZonedDateTime tokyoZonedDateTime = zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
System.out.println("Asia/Tokyo对应的当前时间是:" + tokyoZonedDateTime);
}
@Test
public void demo6() {
//在初始化LocalDate和LocalDateTime的时候,月份的参数建议传入枚举类
//2020年5月14日15点12分36秒
LocalDateTime localDateTime = LocalDateTime.of(2020, Month.MAY, 15, 12, 36);
System.out.println(localDateTime);
//Month枚举类 -> of()方法可以根据传入的数字返回对应的枚举
Month month = Month.of(12);
System.out.println(month);
}
@Test
/**
* 创建当前时间(不带时区)
* 创建当前时间(只包含年月日)
* 创建当前时间(包含年月日时分秒并且带有时区)
* 创建2012年12月31日7时38分46秒的日期对象 月份使用枚举表示
* 创建7时38分46秒的时间对象
*/
public void test01() {
//1、创建当前时间(不带时区)
LocalTime localTime1 = LocalTime.now();
System.out.println("LocalTime:\t" + localTime1);
//2、创建当前时间(只包含年月日)
LocalDate localDate = LocalDate.now();
System.out.println("LocalDate:\t" + localDate);
//3、创建当前时间(包含年月日时分秒并且带有时区)
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println("ZonedDateTime:\t" + zonedDateTime);
//4、创建2012年12月31日7时38分46秒的日期对象 月份使用枚举表示
LocalDateTime localDateTime = LocalDateTime.of(2012, Month.DECEMBER, 31, 7, 38, 46);
System.out.println("LocalDateTime:\t" + localDateTime);
//5、创建7时38分46秒的时间对象
LocalTime localTime2 = LocalTime.of(7, 38, 46);
System.out.println("localTime2:\t" + localTime2);
}
@Test
/**
* 日期的计算
*/
public void demo7() {
//封装LocalDate对象
LocalDate localDate = LocalDate.now();
System.out.println("当前日期是:" + localDate);
//计算当前日期的4天后的日期
System.out.println("当前日期的4天后的日期是:" + localDate.plusDays(4));
//计算当前日期3周后的日期
System.out.println("计算当前日期3周后的日期是:" + localDate.plusWeeks(3));
//计算当前日期5个月后的日期
System.out.println("计算当前日期5个月后的日期是:" + localDate.plusMonths(5));
//计算当前日期2年后的日期
System.out.println("计算当前日期2年后的日期是:" + localDate.plusYears(2));
//如果需要计算当前日期之前的日期只需要调用LocalDate.minus()方法即可
}
@Test
public void demo8() {
//封装LocalTime对象
LocalTime localTime = LocalTime.now();
System.out.println("当前时间是:" + localTime);
//计算当前时间的500纳秒后的时间
System.out.println("当前时间的500纳秒后的时间是:" + localTime.plusNanos(500));
//计算当前时间的45秒后的时间
System.out.println("当前时间的45秒后的时间是:" + localTime.plusSeconds(45));
//计算当前时间的19分钟后的时间
System.out.println("当前时间的19分钟后的时间是:" + localTime.plusMinutes(19));
//计算当前时间的3小时后的时间
System.out.println("当前时间的3小时后的时间是:" + localTime.plusHours(3));
//如果需要计算当前时间之前的时间只需要调用LocalDate.minus()方法即可
}
@Test
public void demo9() {
//需求:今天程序员小张查看自己的车辆保险记录的时候看到了还有2年3月8天就到期了,计算到期的日期是什么时候
LocalDate localDate = LocalDate.now();
//写法一:
System.out.println("当前日期是:" + localDate + ",保险到期的日期是:" + localDate.plusYears(2).plusMonths(3).plusDays(8));
//写法二:
System.out.println("当前日期是:" + localDate + ",保险到期的日期是:" + localDate.plus(Period.of(2, 3, 8)));
}
@Test
public void demo10() {
//结婚10年称为锡婚,2020年2月2日11时11分11秒称为对称日,
//很多情侣准备在那天结婚,如果在那天结婚了,那么锡婚会发生在什么时候?
LocalDateTime marryTime = LocalDateTime.of(2020, Month.FEBRUARY, 2, 11, 11, 11);
LocalDateTime tin_marriageTime = marryTime.plus(1, ChronoUnit.DECADES);
System.out.println("如果在 " + marryTime + " 的时候结婚,那么锡婚发生的时间点在:" + tin_marriageTime);
System.out.println("如果锡婚后的半天需要请所有的亲戚朋友们吃饭,那么吃饭的时间节点是:" + tin_marriageTime.plus(1, ChronoUnit.HALF_DAYS));
}
@Test
public void demo11() {
//修改日期或者时间中的某个值
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("当前时间是:" + localDateTime);
//将日期修改成1号
//写法一:
System.out.println("将当前日期修改成2019年1月1日14时08分26秒:"
+ localDateTime.withYear(2019)
.withMonth(1)
.withDayOfMonth(1)
.withHour(14)
.withMinute(8)
.withSecond(26));
//写法二:
System.out.println("将当前日期修改成2019年1月1日14时08分26秒:"
+ localDateTime.with(ChronoField.YEAR, 2019)
.with(ChronoField.MONTH_OF_YEAR, 1)
.with(ChronoField.DAY_OF_MONTH, 1)
.with(ChronoField.HOUR_OF_DAY, 14)
.with(ChronoField.MINUTE_OF_HOUR, 8)
.with(ChronoField.SECOND_OF_MINUTE, 26));
}
@Test
public void test02() {
//使用三种方式计算2019年7月19日14时38分34秒后的3年7个月18天后是什么时候
LocalDateTime localDateTime = LocalDateTime.of(2019, 7, 19, 14, 38, 34);
//方式一:
System.out.println("2019年7月19日14时38分34秒后的3年7个月18天后是:" +
localDateTime.plusYears(3).plusMonths(7).plusDays(18));
//方式二:
System.out.println("2019年7月19日14时38分34秒后的3年7个月18天后是:" +
localDateTime.plus(Period.of(3, 7, 18)));
//方式三:
System.out.println("2019年7月19日14时38分34秒后的3年7个月18天后是:" +
localDateTime.plus(3, ChronoUnit.YEARS)
.plus(7, ChronoUnit.MONTHS)
.plus(18, ChronoUnit.DAYS));
}
@Test
public void demo12() {
//封装日期为当前时间
LocalDateTime now = LocalDateTime.now();
System.out.println("当前时间为:" + now);
//通过with()方法传入TemporalAdjuster类的实现类对象,就可以进行更改,
//实现类对象室友TemporalAdjuster类的静态方法来提供的
//修改时间为当月第一天
System.out.println("将时间修改为当月的第一天,具体时间为:" + now.with(TemporalAdjusters.firstDayOfMonth()));
//修改时间为下个月的第一天
System.out.println("将时间修改为下个月的第一天,具体时间为:" + now.with(TemporalAdjusters.firstDayOfNextMonth()));
//修改时间为下一年的第一天
System.out.println("将时间修改为下一年的第一天,具体时间为:" + now.with(TemporalAdjusters.firstDayOfNextYear()));
//修改时间为本年的第一天
System.out.println("将时间修改为本年的第一天,具体时间为:" + now.with(TemporalAdjusters.firstDayOfYear()));
//修改时间为本月的最后一天
System.out.println("将时间修改为本月的最后一天,具体时间为:" + now.with(TemporalAdjusters.lastDayOfMonth()));
//修改时间为本年的最后一天
System.out.println("将时间修改为本年的最后一天,具体时间为:" + now.with(TemporalAdjusters.lastDayOfYear()));
//总结:TemporalAdjuster是一个接口,with方法实际上传入的是这个接口的实现类对象,
//TemporalAdjusters并不是TemporalAdjuster的实现类,
//只不过TemporalAdjusters的静态方法实现了TempopralAdjuster,并且将实现类对象返回了。
}
@Test
public void demo13() {
//封装日期对象为当前日期
LocalDate now = LocalDate.now();
//将当前日期修改为下个周日
System.out.println("下一个周日是:" + now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)));
//将当前日期修改为上一个周日
System.out.println("上一个周日是:" + now.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)));
}
@Test
public void demo14() {
//假如员工一个月中领取工资,发薪日是每个月的15号,如果发薪日是周末,则调整为周五
LocalDate payDate = LocalDate.of(2018, 12, 15);
LocalDate realPayDate = LocalDate.from(new TemporalAdjuster() {
@Override
public Temporal adjustInto(Temporal temporal) {
//1、Temporal是日期时间对象的父接口,实际上可以理解为传入的就是LocalDate或者LocalTime对象
LocalDate payDate = LocalDate.from(temporal);
//2、判断当前封装的日期中的日期是不是当月15号,如果不是则修改为15号
if(payDate.getDayOfMonth() != 15) {
payDate = payDate.withDayOfMonth(15);
}
//3、判断payDate对象中封装的星期是不是周六或者周日,如果是周末的话则改为上一个周五
if(payDate.getDayOfWeek() == DayOfWeek.SATURDAY ||
payDate.getDayOfWeek() == DayOfWeek.SUNDAY) {
payDate = payDate.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
}
return payDate;
}
}.adjustInto(payDate));
System.out.println("这个月的实际发薪日是:" + realPayDate);
}
@Test
public void demo15() {
//计算当前时间距离劳动节还有多少天
LocalDate now = LocalDate.now();
//调用now的query()方法,然后将我们自己实现的UtilDayQueryImpl作为参数传入即可
Long dayCount = now.query(new TemporalQuery<Long>() {
@Override
public Long queryFrom(TemporalAccessor temporal) {
//1、TemporalAccessor是LocalDateTime的顶级父接口,
//LocalDate就是接口的实现类,将temporal转换为为LocalDate进行使用
LocalDate now = LocalDate.from(temporal);
//2、封装当年的劳动节日期,年份从now中获取,月份:Month.MAY,日期:1 -> 2020年5月1日
LocalDate laborDay = LocalDate.of(now.getYear(), Month.MAY, 1);
//3、判断当前时间是否已经超过了当年的劳动节,如果超过了当年的劳动节,则laborDay加1年
if(now.isAfter(laborDay)) {
laborDay = laborDay.plusYears(1);
}
//4、通过ChronoUnit的between()方法来计算两个时间点的差值
return ChronoUnit.DAYS.between(now, laborDay);
}
});
System.out.println("当前的日期是:" + now + ",距离下一个五一劳动节还有 " + dayCount + " 天");
//计算当前时间距离下一个圣诞节/儿童节/劳动节各相差多少天
Long[] daysArray = now.query(new TemporalQuery<Long[]>() {
@Override
public Long[] queryFrom(TemporalAccessor temporal) {
LocalDate now = LocalDate.from(temporal);
return new Long[] {getDate(now, 12, 25), getDate(now, 6, 1), getDate(now, 5, 1)};
}
//根据当前日期和下一个节日的日期,获取距离下一个日期的差值
private Long getDate(LocalDate now, int month, int day) {
LocalDate festivalDay = LocalDate.of(now.getYear(), month, day);
if(now.isAfter(festivalDay)) {
festivalDay = festivalDay.plusYears(1);
}
return ChronoUnit.DAYS.between(now, festivalDay);
}
});
for(Long days : daysArray) {
System.out.println(days);
}
}
@Test
/**
* java.util.Date转换为java.time.LocalDate
*/
public void demo16() {
//初始化一个Date对象
Date d = new Date();
//方法一:使用Instant类完成转换
//1、将Date对象转换成Instant对象
Instant instant = d.toInstant();
//2、Date类中包含日期信息和时间信息,但是不提供时区信息,和Instant类一样,
//通过Instant类的atZone方法添加时区信息进行转换
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
//3、将ZonedDateTime通过toLocalDate()方法转换为LocalDate对象
LocalDate localDate1 = zonedDateTime.toLocalDate();
System.out.println("转换之前的java.util.Date对象是:" + d);
System.out.println("转换之后的java.time.LocalDate对象是:" + localDate1);
//方法二:将Java.util.Date先转换成java.sql.Date
//再将java.sql.Date转换成java.time.LocalDate
//java.sql.Date类构造的时候需要毫秒值 -> java.util.Date类中提供了一个获取毫秒值的方法getTime()
java.sql.Date date = new java.sql.Date(d.getTime());
LocalDate localDate2 = date.toLocalDate();
System.out.println("转换之前的java.util.Date对象是:" + d);
System.out.println("转换之后的java.time.LocalDate对象是:" + localDate2);
}
@Test
/**
* java.sql.Date转换为java.time.LocalDate
* java.sql.TimeStamp转换为java.time.LocalDateTime
*/
public void demo17() {
//初始化java.sql.Date对象
java.sql.Date d = new java.sql.Date(System.currentTimeMillis());
//java.sql.Date类中自带了转换为LocalDate的方法toLocalDate()
LocalDate localDate = d.toLocalDate();
System.out.println("转换之前的java.sql.Date对象是:" + d);
System.out.println("转换之后的java.time.LocalDate对象是:" + localDate);
//初始化java.sql.TimeStamp对象
Timestamp t = new Timestamp(System.currentTimeMillis());
LocalDateTime localDateTime = t.toLocalDateTime();
System.out.println("转换之前的java.sql.TimeStamp对象是:" + t);
System.out.println("转换之后的java.time.LocalDateTime对象是:" + localDateTime);
}
@Test
/**
* java.util.Calendar转换为java.time.ZonedDateTime
*/
public void demo18() {
//1、初始化一个Calendar对象
Calendar calendar = Calendar.getInstance();
//2、Calendar对象自java 1.1版本开始提供了一个方法getTimeZone()用于获取时区对象
//要将Calendar转换为ZonedDateTime对象,需要先获取时区对象。
TimeZone timeZone = calendar.getTimeZone();
//3、从java 1.8版本开始TimeZone类提供了一个方法可以获取到ZoneId ->
//拿ZoneId对象来构建ZonedDateTime对象
ZoneId zoneId = timeZone.toZoneId();
//4、ZonedDateTime类有一个ofInstant()方法,
//可以将一个Instant对象和ZoneId独享封装为一个ZonedDateTime对象
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(calendar.toInstant(), zoneId);
System.out.println("转换之前的java.util.Calendar对象是:" + calendar);
System.out.println("转换之后的java.time.ZonedDateTime对象是:" + zonedDateTime);
}
@Test
/**
* java.util.calendar类转换成java.time.LocalDateTime
*/
public void demo19() {
//1、初始化一个Calendar对象
Calendar calendar = Calendar.getInstance();
//2、通过get方法获取到Calendar对象中封装的数据
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1;
int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
LocalDateTime localDateTime = LocalDateTime.of(year, month, dayOfMonth, hourOfDay, minute, second);
System.out.println("转换之前的java.util.Calendar对象是:" + calendar);
System.out.println("转换之后的java.time.LocalDateTime对象是:" + localDateTime);
}
@Test
/**
* 日期格式化和字符串转日期
*/
public void demo20() {
//对LocalDateTime进行格式化和解析,初始化LocalDateTime对象
LocalDateTime now = LocalDateTime.now();
System.out.println("没有格式化的String是:" + now);
//now对象可以直接调用format方法进行格式化
String s1 = now.format(DateTimeFormatter.ISO_DATE_TIME);
System.out.println("按照ISO_DATE_TIME格式化之后String是:" + s1);
String s2 = now.format(DateTimeFormatter.ISO_DATE);
System.out.println("按照ISO_DATE格式化之后String是:" + s2);
//解析字符串的方式通过LocalDateTime类的静态方法parse方法传入需要解析的字符串即可
LocalDateTime localDateTime = LocalDateTime.parse(s1);
System.out.println("将ISO_DATE_TIME格式的字符串转成LocalDateTime的结果是:" + localDateTime);
LocalDate localDate = LocalDate.parse(s2);
System.out.println("将ISO_DATE格式的字符串转成LocalDateTime的结果是:" + localDate);
}
@Test
/**
* 本地日期格式化(将根据当前系统所处环境-中国)
*/
public void demo21() {
LocalDateTime now = LocalDateTime.now();
//通过DateTimeFormatter的ofLocalizedDate指定解析格式
System.out.println("FormatStyle.FULL:" +
now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)));
System.out.println("FormatStyle.LONG:" +
now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)));
System.out.println("FormatStyle.MEDIUM:" +
now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));
System.out.println("FormatStyle.SHORT:" +
now.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)));
}
@Test
/**
* 自定义日期格式化
*/
public void demo22() {
LocalDateTime now = LocalDateTime.now();
//通过DateTimeFormatter提供的ofPattern方法自定义格式化方式
System.out.println("将LocalDateTime按照yyyy/MM/dd HH:mm:ss:SSS格式进行格式化:" +
now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss:SSS")));
System.out.println("将LocalDateTime按照yyyy年MM月dd日 HH:mm:ss:SSS格式进行格式化:" +
now.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss:SSS")));
}
@Test
/**
* 练习:将2020年5月20日22时22分22秒格式化为以下格式:2020-05月-18---22:22分22秒
*/
public void test03() {
LocalDateTime now = LocalDateTime.of(2020, 5, 20, 22, 22, 22);
System.out.println("将LocalDateTime按照yyyy-MM月-dd---HH:mm分ss秒格式进行格式化:" +
now.format(DateTimeFormatter.ofPattern("yyy-MM月-dd---HH:mm分ss秒")));
}
}