java8是如何处理时间及日期的
一、简介
java8中的java.time包中的类是不可变且线程安全的。新的时间及日期API位于java.time中,下面是一些关键类的简单介绍:
●Instant——它代表的是时间戳
●LocalDate——不包含具体时间的日期,比如2014-01-14。它可以用来存储生日,周年纪念日,入职日期等。
●LocalTime——它代表的是不含日期的时间
●LocalDateTime——它包含了日期及时间,不过还是没有偏移信息或者说时区。
●ZonedDateTime——这是一个包含时区的完整的日期时间,偏移量是以UTC/格林威治时间为基准的。
二、实用实例
1、日期的获取
java8中有个叫LocalDate的类,能用来表示今天的日期。这个类与java.util.Date略有不同,因为它只包含日期,没有时间。
LocalDate是用来表示无时间的日期,他有一个plus()方法可以用来增加日,星期,月,ChronoUnit则用来表示时间单位,LocalDate也是不可变的,因此任何修改操作都会返回一个新的实例
public static void main(String[] args) {
LocalDate today = LocalDate.now();
System.out.println("今天的日期是:"+today);
int year = today.getYear();
int monthValue = today.getMonthValue();
int dayOfMonth = today.getDayOfMonth();
System.out.println("今天的日期是:"+year+"年"+monthValue+"月"+dayOfMonth+"日");
LocalDate years = today.plusYears(1);
System.out.println("明年的今天是:"+years);
LocalDate months = today.plusMonths(2);
System.out.println("两个月后是:"+months);
LocalDate minusMonths = today.minusMonths(2);
System.out.println("两个月前是:"+minusMonths);
LocalDate localDate = LocalDate.of(2018, 8, 25);//月份从1开始,与之前版本的api不同
System.out.println("指定的日期是:"+localDate);
}
输出:
今天的日期是:2018-08-24
今天的日期是:2018年8月24日
明年的今天是:2019-08-24
两个月后是:2018-10-24
两个月前是:2018-06-24
指定的日期是:2018-08-25
2、日期的比较
LocalDate重写了equals方法来进行日期的比较,如下所示
public static void main(String[] args) {
LocalDate today = LocalDate.now();
System.out.println("今天是:"+today);
boolean leapYear = today.isLeapYear();
System.out.println("今年是闰年么:"+leapYear);
LocalDate localDate = LocalDate.of(2018, 8, 25);
System.out.println("今天是2018-08-25么:"+localDate.equals(today));
boolean before = today.isBefore(localDate);
System.out.println("今天在2018-08-25之前么:"+before);
Period between = Period.between(today, localDate);
int days = between.getDays();
System.out.println("今天与2018-08-25相差几天:"+days);
}
输出:
今天是:2018-08-24
今年是闰年么:false
今天是2018-08-25么:false
今天在2018-08-25之前么:true
今天与2018-08-25相差几天:1
3、日期的重复事件,比如账单日、生日
在java中还有一个与时间日期相关的任务就是检查重复事件,比如每月的账单日、生日
如何在java中判断是否是某个节日或者重复事件,使用MonthDay类。这个类由月日组合,不包含年信息,可以用来代表每年重复出现的一些日期或其他组合。他和新的日期库中的其他类一样也都是不可变且线程安全的,并且它还是一个值类
public static void main(String[] args) {
//LocalDate today = LocalDate.now();
LocalDate dayOfBirth = LocalDate.of(1991, 8, 24);
MonthDay birthDay = MonthDay.of(dayOfBirth.getMonth(), dayOfBirth.getDayOfMonth());
MonthDay now = MonthDay.now();
if(now.equals(birthDay)){
System.out.println("今天是你的生日");
}else {
System.out.println("今天不是你的生日");
}
}
输出:
今天是你的生日
4、时间的获取
这个与第一个例子获取当前日期非常相似,这里用的是LocalTime类,默认的格式是hh:mm:ss:nnn
很多时候需要对时间进行操作,比如加一个小时来计算之后的时间,java8提供了更方便的方法 如plusHours,这些方法返回的是一个新的LocalTime实例的引用,因为LocalTime是不可变的
public static void main(String[] args) {
LocalTime now = LocalTime.now();
System.out.println("当前时间是:"+now);
LocalTime plusHours = now.plusHours(2);
System.out.println("两小时后是:"+plusHours);
LocalTime minusHours = now.minusHours(2);
System.out.println("两个小时前是:"+minusHours);
LocalTime plusMinutes = now.plusMinutes(40);
System.out.println("40分钟后是:"+plusMinutes);
}
输出:
当前时间是:15:14:34.650
两小时后是:17:14:34.650
两个小时前是:13:14:34.650
40分钟后是:15:54:34.650
5、时钟的使用
java8自带了Clock类,可以用来获取某个时区下(所以对时区是敏感的)当前的瞬时时间、日期。用来代替System.currentTimelnMillis()与TimeZone.getDefault()方法
public static void main(String[] args) {
Clock systemDefaultZone = Clock.systemDefaultZone();
System.out.println("systemDefaultZone:"+systemDefaultZone);
Clock systemUTC = Clock.systemUTC();
System.out.println("systemUTC:"+systemUTC);
//获取时间戳
long currentTimeMillis = System.currentTimeMillis();
System.out.println(currentTimeMillis);
long epochMilli = Instant.now().toEpochMilli();
System.out.println(epochMilli);
}
输出:
systemDefaultZone:SystemClock[Asia/Shanghai]
systemUTC:SystemClock[Z]
1535095670978
1535095670978
6、不同时区的处理
java8中不仅将日期和时间进行了分离,同时还有时区。比如ZonId代表的是某个特定时区,ZonedDateTime代表带时区的时间,等同于以前的GregorianCalendar类。使用该类,可以将本地时间转换成另一个时区中的对应时间。
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
ZoneId act = ZoneId.of(ZoneId.SHORT_IDS.get("CST"));//美国芝加哥,属于西五区
ZonedDateTime zonedDateTime = ZonedDateTime.of(now, act);
System.out.println("zonedDateTime:"+zonedDateTime);
}
输出:
zonedDateTime:2018-08-24T15:36:42.265-05:00[America/Chicago]
7、带时区的日期与时间
在java8中,可以使用ZoneOffset来代表某个时区,可以使用它的静态方法ZoneOffset.of()方法来获取对应的时区,只要获得了这个偏移量,就可以用这个偏移量和LocalDateTime创建一个新的OffsetDateTime
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println("now:"+now);
ZoneOffset zoneOffset = ZoneOffset.of("+02:30");
OffsetDateTime offsetDateTime = OffsetDateTime.of(now, zoneOffset);
System.out.println("offsetDateTime:"+offsetDateTime);
}
输出:
now:2018-08-24T16:23:13.667
offsetDateTime:2018-08-24T16:23:13.667+02:30
8,日期的解析/格式化
在java8之前,时间日期的格式化非常麻烦,经常使用SimpleDateFormat来进行格式化,但是SimpleDateFormat并不是线程安全的。在java8中,引入了一个全新的线程安全的日期与时间格式器。并且预定义好了格式。
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println("now:"+now);
LocalDate localDate = now.toLocalDate();
LocalTime localTime = now.toLocalTime();
String format = now.format(DateTimeFormatter.ISO_DATE_TIME);
System.out.println("ISO_DATE_TIME:"+format);
format = now.format(DateTimeFormatter.ISO_DATE);
System.out.println("ISO_DATE:"+format);
format = now.format(DateTimeFormatter.ISO_TIME);
System.out.println("ISO_TIME:"+format);
String dateTimeString = "2018-08-24 16:54:32";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.parse(dateTimeString, dateTimeFormatter);
System.out.println("localDateTime"+localDateTime);
format = now.format(dateTimeFormatter);
System.out.println("format:"+format);
}
输出:
now:2018-08-24T17:01:12.553
ISO_DATE_TIME:2018-08-24T17:01:12.553
ISO_DATE:2018-08-24
ISO_TIME:17:01:12.553
localDateTime2018-08-24T16:54:32
format:2018-08-24 17:01:12
三、使用中需要注意的关键点:
●Instant 它代表的是时间戳
●LocalDate 它表示的是不带时间的日期
●LocalTime - 它表示的是不带日期的时间
●LocalDateTime - 它包含了时间与日期,不过没有带时区的偏移量
●ZonedDateTime - 这是一个带时区的完整时间,它根据UTC/格林威治时间来进行时区调整
●OffsetDateTime类实际上包含了LocalDateTime与ZoneOffset。它用来表示一个包含格林威治时间偏移量(+/-小时:分,比如+06:00或者 -08:00)的完整的日期(年月日)及时间(时分秒,纳秒)。
●DateTimeFormatter类用于在Java中进行日期的格式化与解析。与SimpleDateFormat不同,它是不可变且线程安全的,如果需要的话,可以赋值给一个静态变量。DateTimeFormatter类提供了许多预定义的格式器,你也可以自定义自己想要的格式。当然了,根据约定,它还有一个parse()方法是用于将字符串转换成日期的,如果转换期间出现任何错误,它会抛出DateTimeParseException异常。类似的,DateFormatter类也有一个用于格式化日期的format()方法,它出错的话则会抛出DateTimeException异常。