众所周知Java的时间和日期对象异常恶心...所幸JDK8终于更新了这部分。
1、Instant和Duration
一个Instant类似于一个Date,同时包含日期和时刻信息,是时间线上的一个点,Duration则是两个Instant之间的间隔。
//创建Instant对象
Instant startInstant = Instant.now();
//some code...
Instant endInstant = Instant.now();
//得到两个时刻点的间隔
Duration timeElapsed = Duration.between(formerInstant,afterInstant);
long days = timeElapsed.toDays();
long hours = timeElapsed.toHours();
long minutes = timeElapsed.toMinutes();
long millis = timeElapsed.toMillis();
long nanos = timeElapsed.toNanos();
System.out.println(days+"-"+hours+"-"+minutes+"-"+millis+"-"+nanos);
还可以对Duration对象直接进行运算操作
//注意Instant和Duration都是不可变类,所有的操作都不会改变Duration对象本身
//plus和minus方法
duration1.plus(duration2);
//plusXX和minusXX方法
duration1.plusDays(1);
//multipliedBy和dividedBy方法
duration1.multipliedBy(2);
//isZero和isNegative方法
boolean negative = duration1.isNegative();
boolean zero = duration1.isZero();
Duration还可以通过ofXX直接创建
Duration.ofDays(15);
Duration.ofHours(15);
2、LocalDate
LocalDate是一个带有年份、月份、当月天数的日期,不包含时区信息。
//创建LocalDate对象
//使用now方法获取当前日期
LocalDate localDate = LocalDate.now();
//使用of方法创建,注意1就代表一月,1就代表周一,和Calendar中不同
LocalDate localDate1 = LocalDate.of(2017,1,1);
//plusXX、minusXX方法
LocalDate localDate2 = localDate.plusDays(1);
LocalDate localDate3 = localDate.plusYears(1);
//plus、minus方法,加上一个时段(duration或period)
localDate.plus(Duration.ofDays(15));
localDate.minus(Duration.ofDays(15));
//withDayOfWeek、withDayOfMonth修改日期,日期都从1开始
//withYear、withMonth修改年份、月份
localDate.withDayOfMonth(2);
localDate.withDayOfMonth(3);
localDate.withMonth(3);
localDate.withYear(1982);
//getXX方法获取日期
localDate.getDayOfMonth();
localDate.getYear();
//获取两个日期之间的Period对象
Period per = localDate1.until(localDate);
//输出P2M22D
System.out.println(per);
//可以用ChronoUnit制定输出的格式
long until = localDate1.until(localDate, ChronoUnit.DAYS);
//输出81
System.out.println(until);
//isBefore、isAfter比较前后
boolean before = localDate.isBefore(localDate1);
3、TemporalAdjuster
TemporalAdjuster为日期校正对象,用来对LocalDate对象进行一些校正操作,例如:
LocalDate localDate = LocalDate.now();
//next和previous方法、nextOrSame和previousOrSame方法
//获取当前日期的下一个周四
LocalDate localDate1 = localDate.with(TemporalAdjusters.next(DayOfWeek.THURSDAY));
//获取当前日期(如果当前是周一)或当前日期的前一个周四
LocalDate localDate2 = localDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.THURSDAY));
//dayOfWeekInMonth方法获取指定的当月的第几个周几
localDate.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.MONDAY));
//lastInMonth当月的最后一个周几
localDate.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY));
//lastDayOfMonth、firstDayOfMonth、lastDayOfYear、firstDayOfYear...等一系列顾名思义的日期
localDate.with(TemporalAdjusters.lastDayOfMonth());
还可以通过重写来自定义TemporalAdjuster对象
//自定义日期操作,计算下一个工作日
TemporalAdjuster NEXT_WORKDAY = temporal -> {
//注意一定要对Temporal对象进行强转
LocalDate result = (LocalDate)temporal;
do{
result = result.plusDays(1);
}while (result.getDayOfWeek().getValue()>=6);
return result;
};
4、LocalTime、LocalDate和LocalDateTime
LocalDate(本地日期)只带有日期信息,相对的LocalTime(本地时间)则只带有一天内的时刻信息,而没有日期信息。
LocalDateTime则是LocalDate和LocalTime的结合,这两个类的方法都和LocalDate的方法类似。
5、ZonedDateTime
和LocalDate(本地日期)相对应的,还有一种时间ZonedDate(带时区的时间)。
在不需要考虑时区的场合中,使用LocalDate比较合理,也能避免“夏令时”等带来的可能的错误
但是在需要考虑时区变化的场合中,使用ZonedDateTime就比较方便。
由于我很少有可能会接触到时区变化,这里不做详解。
6、DateTimeFormatter格式化和解析
LocalDateTime localDateTime = LocalDateTime.now();
//直接使用对象的toString方法就可以得到默认的输出格式
localDateTime.toString();
//使用DateTimeFormatter的预定义的标准格式
//诸如此类的预定义格式还有很多,可以查阅API查看
DateTimeFormatter.ISO_DATE.format(localDateTime);
//和之前使用的SimpleDateFormat类似,也可以自定义格式,具体格式同样可以查阅API
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("E yyyy-MM-dd HH:mm:ss");
String formatedTime = dateTimeFormatter.format(localDateTime);
7、和前版本对象的相互转化
Instant类似与之前的Date类,可以通过toInstant方法和from方法相互转化。
类似的,ZonedDateTime和GregorianCalendar类似,可以通过toZonedDateTime和from相互转化。
7.1、将LocalDate转回Date
public static void main(String[] args) {
LocalDate localDate = LocalDate.now();
localDate.minusDays(5);
System.out.println(localDate);
Instant instant = localDate.atStartOfDay(ZoneId.systemDefault()).toInstant();
System.out.println(Date.from(instant));
}
8、具体操作示例
8.1、获取一个月中的所有工作日(节假日类似)
public class Main {
public static void main(String[] args) {
//自定义日期操作,计算下一个工作日
TemporalAdjuster NEXT_WORKDAY = temporal -> {
//注意一定要对Temporal对象进行强转
LocalDate result = (LocalDate)temporal;
do{
result = result.plusDays(1);
}while (result.getDayOfWeek().getValue()>=6);
return result;
};
List list = new ArrayList<>();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate localDate1 = LocalDate.of(2017,2,1);
LocalDate localDate2 = LocalDate.of(2017,2,28);
do {
list.add(Integer.parseInt(dateTimeFormatter.format(localDate1)));
localDate1 = localDate1.with(NEXT_WORKDAY);
}while (localDate1.isBefore(localDate2)||localDate1.isEqual(localDate2));
System.out.println(Arrays.toString(list.toArray()));
}
}