Java 8新特性之方法引用
Java 8新特性之Stream
Java 8新特性之Lambda
文章目录
Java 8 之前使用的时间类:Date存在缺点:
Not thread safe - java.util.Date是非线程安全的,使用时必须处理并发问题。而新的时间类是不可变的,并且没有 set 方法。
Poor design - java.util.Date中日期从1900开始,月从1开始,天从0开始,十分不统一;原来的API提供了很少的时间操作。
Difficult time zone handing - 原来的API需要花费大量代码处理区域时间。
Java 8 加入了新的API:java.time
Java.time包中的是类是不可变且线程安全的。新的时间及日期API位于java.time中
- Local - 简单时间API
- Zoned - 区域时间API
* Instance 时间戳 * LocalDate 不包含时间的日期 * LocalTime 不包含日期的时间 * LocalDateTime 包含时间及日期(没有偏移信息/时区) * ZonedDateTime 包含时区的完整的日期时间,偏移量是以UTC/格林威治时间为基准的。
基础学习
LocalDate、LocalTime和LocalDateTime。。(Instant)
LocalDate
-
LocalDate date = LocalDate.of(2014,3,18); int year = date.getYear(); Month month = date.getMonth(); int day = date.getDayOfMonth(); DayOfWeek dow = date.getDayOfWeek(); 星期几 int len = date.lengthOfMonth(); 这个月有几天 boolean leap = date.isLeapYear(); LocalDate today = LocalDate.now(); 当前日期 //使用Temporal读取LocalDate的值 int year1= date.get(ChronoField.YEAR); int month1= date.get(ChronoField.MONTH_OF_YEAR); int day1= date.get(ChronoField.DAY_OF_MONTH);
-
运行结果:
2014-03-18 2014 MARCH 18 TUESDAY 31 false 2019-12-23 2014 3 18
LocalTime
-
LocalTime time = LocalTime.of(13,45,20); int hour = time.getHour(); int minute = time.getMinute(); int second = time.getSecond(); //也可以使用重载方法,自定义如何格式化日期 LocalDate date1 = LocalDate.parse("2014-03-18"); LocalTime time1 = LocalTime.parse("13:45:20");
-
运行结果:
13:45:20 13 45 20 2014-03-18 13:45:20
LocalDateTime
-
LocalDate date = LocalDate.parse("2014-03-18"); LocalTime time = LocalTime.parse("13:45:20"); LocalDateTime dt1 = LocalDateTime.of(2014,Month.MARCH,18,13,45,20); LocalDateTime dt2 = LocalDateTime.of(date,time); //date加一个time转换成LocalDateTime LocalDateTime dt3 = date.atTime(13,15,20); LocalDateTime dt4 = date.atTime(time); //time加一个date转换成LocalDateTime LocalDateTime dt5 = time.atDate(date); LocalDate date1 = dt1.toLocalDate(); LocalTime time1 = dt1.toLocalTime();
-
运行结果
2014-03-18T13:45:20 2014-03-18T13:45:20 2014-03-18T13:15:20 2014-03-18T13:45:20 2014-03-18T13:45:20 2014-03-18 13:45:20
Instant(目前我也不知道这啥)
-
Instant i1 = Instant.ofEpochSecond(3); Instant i2 = Instant.ofEpochSecond(3,0); Instant i3 = Instant.ofEpochSecond(2,1000000000); Instant i4 = Instant.ofEpochSecond(4,-1000000000);
-
运行结果:
1970-01-01T00:00:03Z 1970-01-01T00:00:03Z 1970-01-01T00:00:03Z 1970-01-01T00:00:03Z
Duration(持续)、Period(期间)
Duration(时间间隔)
-
LocalTime time1 = LocalTime.of(13,45,20); LocalTime finalTime = time1 .plus(Duration.ofSeconds(30)); LocalTime time2 = LocalTime.of(14,48,50); LocalDateTime dateTime1 = LocalDateTime.of(2014,Month.MARCH,18,13,45,20); LocalDateTime dateTime2 = LocalDateTime.of(2016,Month.MARCH,20,15,50,50); Instant instant1 = Instant.ofEpochSecond(4,-1000000000); Instant instant2 = Instant.ofEpochSecond(2,1000000000); Duration d1 = Duration.between(time1,time2); Duration d2 = Duration.between(dateTime1,dateTime2); Duration d3 = Duration.between(instant1,instant2); Period tenDays = Period .between(LocalDate.of(2014,3,8) ,LocalDate.of(2014,3,18)); /**************/ LocalTime time = LocalTime.now(); LocalTime time2 = time.plusMinutes(1).plusSeconds(20); Duration between = Duration.between(time, time2); long distance = Duration.between(time, time2).getSeconds(); long distance2 = ChronoUnit.SECONDS.between(time, time2);
-
运行结果
PT1H3M30S PT17594H5M30S //此处没有给出运行结果 PT0S P10D /***********/ PT1M20S 80 80
Period(日期间隔)
-
Duration threeMinutes = Duration.ofMinutes(3); Duration threeMinutes2 = Duration.of(3,ChronoUnit.MINUTES); Period tenDays2 = Period.ofDays(10); Period threeWeeks = Period.ofWeeks(3); Period twoYearsSixMonthsOneDay = Period.of(2,6,1); LocalDate date1 = LocalDate.parse("2018-01-01"); LocalDate date2 = LocalDate.parse("2019-02-02"); Period dd = Period.between(date1,date2); int days = Period.between(date1, date2).getDays(); //这块是一个小坑,排除月份的日期相减 long days2 = ChronoUnit.DAYS.between(date1, date2);
-
运行结果
PT3M PT3M P10D P21D P2Y6M1D date P1Y1M1D days 1 days2 397
操纵(TemporalAdjuster)、解析、格式化日期
操纵日期
普通方式
-
LocalDate date = LocalDate.of(2014,3,18); //直观方式操纵LocalDate属性 LocalDate date1 = date.withYear(2011); LocalDate date2 = date.withDayOfYear(25); LocalDate date3 = date.with(ChronoField.MONTH_OF_YEAR,9); //以相对方式修改LocalDate属性 date1 = date.plusWeeks(1); date2 = date.minusYears(3); date3 = date.plus(6,ChronoUnit.MONTHS);
-
运行结果:
2014-03-18 2011-03-18 2014-01-25 2014-09-18 2014-03-18 2014-03-25 2011-03-18 2014-09-18
TemporalAdjuster操纵日期
-
LocalDate date1 = LocalDate.of(2014,3,18); LocalDate date2 = date1.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)); LocalDate date3 = date2.with(TemporalAdjusters.lastDayOfMonth());
-
运行结果
2014-03-18 2014-03-23 2014-03-31
方法 | 描述 |
---|---|
dayOfWeekInMonth | 创建一个新的日期,它的值为同一个月中每一周的第几天 |
firstDayOfMonth | 创建一个新的日期,它的值为当月的第一天 |
firstDayOfNextMonth | 创建一个新的日期,它的值为下月的第一天 |
firstDayOfNextYear | 创建一个新的日期,它的值为明年的第一天 |
firstDayOfYear | 创建一个新的日期,它的值为当年的第一天 |
firstInMonth | 创建一个新的日期,它的值为同一个月中,第一个符合星期几要求的值 |
lastDayOfMonth | 创建一个新的日期,它的值为当月的最后一天 |
lastDayOfNextMonth | 创建一个新的日期,它的值为下月的最后一天 |
lastDayOfNextYear | 创建一个新的日期,它的值为明年的最后一天 |
lastDayOfYear | 创建一个新的日期,它的值为今年的最后一天 |
lastInMonth | 创建一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值 |
next / previous | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期 |
nextOrSame / previousOrSame | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象 |
格式化、解析日期-时间对象
-
LocalDate date = LocalDate.of(2014,3,18); //使用本来就有的格式转化为字符串 String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE); String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE); LocalDate date1 = LocalDate.parse("20140318",DateTimeFormatter.BASIC_ISO_DATE); LocalDate date2 = LocalDate.parse("2014-03-18",DateTimeFormatter.ISO_LOCAL_DATE); //使用自己设定的格式转化为字符串 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); String formattedDate = date.format(formatter); LocalDate date3 = LocalDate.parse(formattedDate, formatter); DateTimeFormatter italianFormatter = DateTimeFormatter.ofPattern("d.MMMM yyyy", Locale.ITALIAN); formattedDate = date.format((italianFormatter)); date3 = LocalDate.parse(formattedDate,italianFormatter);
-
运行结果
2014-03-18 20140318 2014-03-18 2014-03-18 2014-03-18 2014-03-18 Value(DayOfMonth,2)'/'Value(MonthOfYear,2)'/'Value(YearOfEra,4,19,EXCEEDS_PAD) 18/03/2014 2014-03-18 Value(DayOfMonth)'.'Text(MonthOfYear)' 'Value(YearOfEra,4,19,EXCEEDS_PAD) 18.marzo 2014 2014-03-18
处理不同时区(这里有点难)
示例一 、大陆-东京时区啥啥啥
-
//由localDateTime 获取tokyoDateTime LocalDateTime localDateTime = LocalDateTime.now(); LocalDateTime tokyoDateTime = LocalDateTime.ofInstant(LocalDateTime.now().toInstant(ZoneOffset .of("+08:00")),ZoneId.of("Asia/Tokyo")); //假设本地为东京,获取大陆LocalDateTime LocalDateTime dateTime1 = LocalDateTime.now(); LocalDateTime dateTime2 = LocalDateTime.ofInstant(dateTime1.toInstant(ZoneOffset.of("+09:00")) ,ZoneId.systemDefault()); ZoneId zoneId = ZoneId.of("Asia/Tokyo"); ZonedDateTime zonedDateTime = ZonedDateTime.of(dateTime1, zoneId);
-
运行结果:
localDateTime***** 2019-12-24T13:31:32.277755700 tokyoDateTime***** 2019-12-24T14:31:32.277755700 2019-12-24T13:31:32.277755700 2019-12-24T12:31:32.277755700 Asia/Tokyo 2019-12-24T13:31:32.277755700+09:00[Asia/Tokyo]
示例二
-
//LocalDate(.atStartOfDay) + ZoneId -> ZoneDateTime ZoneId romeZone = ZoneId.of("Europe/Rome"); LocalDate date = LocalDate.of(2014,3,18); ZonedDateTime zdt1 = date.atStartOfDay(romeZone); //LocalDateTime(.atZone) + ZoneId -> ZoneDateTime LocalDateTime dateTime = LocalDateTime.of(2014,3,18,13,45); ZonedDateTime zdt2 = dateTime.atZone(romeZone); //Instant(.atZone) + ZoneId -> ZoneDateTime Instant instant = Instant.now(); ZonedDateTime zdt3 = instant.atZone(romeZone); ```
- 运行结果
2014-03-18T00:00+01:00[Europe/Rome] 2014-03-18T13:45+01:00[Europe/Rome] 本地instant2019-12-24T05:54:37.954459900Z 2019-12-24T06:54:37.954459900+01:00[Europe/Rome]
示例三
-
//注意一下 zonedDateTime = ZonedDateTime.parse("2015-05-03T10:15:30+01:00[Europe/Paris]"); //然后,通过创建ZoneOffset并为localDateTime实例进行设置,将时间增加了两个小时: dateTime = LocalDateTime.now(); ZoneOffset offset = ZoneOffset.of("+02:00"); OffsetDateTime offSetByTwo = OffsetDateTime.of(dateTime, offset); LocalTime maxTime = LocalTime.MAX;
-
运行结果
2015-05-03T11:15:30+02:00[Europe/Paris] 2019-12-24T12:07:44.748674600 +02:00 2019-12-24T12:07:44.748674600+02:00 23:59:59.999999999
打印两地ZoneDateTime
-
dateTime = LocalDateTime.now(); zonedDateTime = dateTime.atZone(ZoneId.systemDefault()); zonedDateTime = dateTime.atZone(ZoneId.of("Asia/Tokyo")); LocalDateTime 2019-12-24T11:19:22.717692200 本地ZonedDateTime2019-12-24T11:19:22.717692200+08:00[Asia/Shanghai] 东京ZonedDateTime2019-12-24T11:19:22.717692200+09:00[Asia/Tokyo]
补充知识
日期兼容问题
-
//由Date和Calender转换为LocalDateTime LocalDateTime dateTime3 = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault()); LocalDateTime dateTime4 = LocalDateTime.ofInstant(new Calendar() {...}.toInstant(),ZoneId.systemDefault()); //所述LocalDateTime可以从历元秒来构造如下。以下代码的结果将是LocalDateTime,表示2016-06-13T11:34:50: LocalDateTime dateTime5 = LocalDateTime.ofEpochSecond(1465817690, 0, ZoneOffset.UTC);
-
运行结果
2019-12-24T10:32:28.246 1970-01-01T08:00 //canlender直接new不好,懒得学,想了解自己去看 2016-06-13T11:34:50
所有ZoneId
-
Set<String> allZoneIds = ZoneId.getAvailableZoneIds(); for(String str: allZoneIds) { System.out.println(str); }
-
常用(主要是我认识的不多)
Europe/London GMT CET Europe/Paris Asia/Hong_Kong Asia/Tokyo Asia/Shanghai Europe/Rome
杂乱区域
Local Date-Time 的简单使用
-
public String Local() { //获取当前日期时间 LocalDateTime currentTime = LocalDateTime.now(); System.out.println("当前日期时间:"+currentTime); LocalDate date1 = currentTime.toLocalDate(); System.out.println("当前日期:"+ date1); Month month = currentTime.getMonth(); int day = currentTime.getDayOfMonth(); int seconds = currentTime.getSecond(); System.out.println("月: " + month +", 日: " + day +", 秒: " + seconds); //给定了日期与年份 date2:2012-12-10T16:10:38.992224100 LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012); System.out.println("给定天数与年份:"+ date2); //给定日期 date3:2014-12-12 LocalDate date3 = LocalDate.of(2014, Month.DECEMBER,12); System.out.println("由给定日期创建日期:"+ date3); //给定时间 date4:22:15 LocalTime date4 = LocalTime.of(22,15); System.out.println("由给定时间创建时间:" + date4); //解析字符串 date5:20:15:30 LocalTime date5 = LocalTime.parse("20:15:30"); System.out.println("由给定时间创建时间:" + date5); return "1"; }
- 运行结果
当前日期时间:2019-12-18T16:10:38.992224100 当前日期:2019-12-18 月: DECEMBER, 日: 18, 秒: 38 给定天数与年份:2012-12-10T16:10:38.992224100 由给定日期创建日期:2014-12-12 由给定时间创建时间:22:15 由给定时间创建时间:20:15:30
Zoned 的简单使用
-
public String Zoned() { //获取当前时间日期 //date1:2012-12-12T13:05:10+08:00[Asia/Shanghai] ZonedDateTime date1 = ZonedDateTime.parse("2012-12-12T10:10:10+05:05[Asia/Shanghai]"); System.out.println("date1:"+date1); //ZoneId:Europe/Paris ??? ZoneId id = ZoneId.of("Europe/Paris"); System.out.println("ZoneId:"+ id); //Asia/Shanghai ZoneId currentZone = ZoneId.systemDefault(); System.out.println(currentZone); return "2"; }
-
运行结果:
date1:2012-12-12T13:05:10+08:00[Asia/Shanghai] ZoneId:Europe/Paris Asia/Shanghai
Chrono Units Enum
-
java.time.temporal.ChronoUnit
枚举类用来用表示年、月、日等,这取代原来使用 int值来表示public String ChronoUnit() { //Get the current date LocalDate today = LocalDate.now(); System.out.println("Current date: " + today); //add 1 week to the current date LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS); System.out.println("Next week: " + nextWeek); //add 1 month to the current date LocalDate nextMonth = today.plus(1, ChronoUnit.MONTHS); System.out.println("Next month: " + nextMonth); //add 1 year to the current date LocalDate nextYear = today.plus(1, ChronoUnit.YEARS); System.out.println("Next year: " + nextYear); //add 10 years to the current date LocalDate nextDecade = today.plus(1, ChronoUnit.DECADES); System.out.println("Date after ten year: " + nextDecade); return null; }
-
运行结果:
Current date: 2019-12-18 Next week: 2019-12-25 Next month: 2020-01-18 Next year: 2020-12-18 Date after ten year: 2029-12-18
Period and Duration
Java 8 中两个类Period和Duration处理时间差:
-
Period - 处理日期差。
-
Duration - 处理时间差。
public String pd() { /*****testPeriod*****/ //Get the current date LocalDate date1 = LocalDate.now(); System.out.println("Current date: " + date1); //add 1 month to the current date LocalDate date2 = date1.plus(1, ChronoUnit.MONTHS); System.out.println("Next month: " + date2); Period period = Period.between(date2, date1); System.out.println("Period: " + period); /*****testDuration*****/ LocalTime time1 = LocalTime.now(); Duration twoHours = Duration.ofHours(2); LocalTime time2 = time1.plus(twoHours); Duration duration = Duration.between(time1, time2); System.out.println("Duration: " + duration); return null; }
-
运行结果:
Current date: 2019-12-18 Next month: 2020-01-18 Period: P-1M Duration: PT2H
Backward Compatibility
-
toInstant()方法用来将老的Date对象转换为LocalDateTime或ZonedDateTime对象
public String testBackwardCompatability() { //Get the current date Date currentDate = new Date(); System.out.println("Current date: " + currentDate); //Get the instant of current date in terms of milliseconds Instant now = currentDate.toInstant(); ZoneId currentZone = ZoneId.systemDefault(); LocalDateTime localDateTime = LocalDateTime.ofInstant(now, currentZone); System.out.println("Local date: " + localDateTime); ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(now, currentZone); System.out.println("Zoned date: " + zonedDateTime); return null; }
-
运行结果:
Current date: Wed Dec 18 16:38:04 CST 2019 Local date: 2019-12-18T16:38:04.741 Zoned date: 2019-12-18T16:38:04.741+08:00[Asia/Shanghai]
参考文档:https://blog.csdn.net/weixin_37547589/article/details/90064465
-
LocalDateTime 为日期时间的计算提供了很大的方便, 在构造对象/运算/toString等方便都非常便利。
-
3个常用的类:
java.time.LocalDateTime; 推荐使用 java.time.LocalDate; java.time.LocalTime; Instant Duration Period