Java 8新的时间日期库的20个使用示例(上)

640?wx_fmt=gif

除了lambda表达式,stream以及几个小的改进之外,Java 8还引入了一套全新的时间日期API,在本篇教程中我们将通过几个简单的任务示例来学习如何使用Java 8的这套API。

Java对日期,日历及时间的处理一直以来都饱受诟病,尤其是它决定将java.util.Date定义为可修改的以及将SimpleDateFormat实现成非线程安全的。看来Java已经意识到需要为时间及日期功能提供更好的支持了,这对已经习惯使用Joda时间日期库的社区而言也是件好事。关于这个新的时间日期库的最大的优点就在于它定义清楚了时间日期相关的一些概念,比方说,瞬时时间(Instant),持续时间(duration),日期(date),时间(time),时区(time-zone)以及时间段(Period)。同时它也借鉴了Joda库的一些优点,比如将人和机器对时间日期的理解区分开的。Java 8仍然延用了ISO的日历体系,并且与它的前辈们不同,java.time包中的类是不可变且线程安全的。新的时间及日期API位于java.time包中,下面是里面的一些关键的类:

– Instant——它代表的是时间戳– LocalDate——不包含具体时间的日期,比如2014-01-14。它可以用来存储生日,周年纪念日,入职日期等。– LocalTime——它代表的是不含日期的时间– LocalDateTime——它包含了日期及时间,不过还是没有偏移信息或者说时区。– ZonedDateTime——这是一个包含时区的完整的日期时间,偏移量是以UTC/格林威治时间为基准的。

新的库还增加了ZoneOffset及Zoned,可以为时区提供更好的支持。有了新的DateTimeFormatter之后日期的解析及格式化也变得焕然一新了。随便提一句,我是在去年这个时候Java正要推出这个新功能时写的这篇文章,所以你会发现示例中的时间都还是去年的。你运行下这些例子,它们返回的值肯定都是正确的。

Java 8是如何处理时间及日期的

有人问我学习一个新库的最佳途径是什么?我的回答是,就是在实际项目中那样去使用它。在一个真实的项目中会有各种各样的需求,这会促使开发人员去探索和研究这个新库。简言之,只有任务本身才会真正促使你去探索及学习。java 8的新的日期及时间API也是一样。为了学习Java 8的这个新库,这里我创建了20个以任务为导向的例子。我们先从一个简单的任务开始,比如说如何用Java 8的时间日期库来表示今天,接着再进一步生成一个带时间及时区的完整日期,然后再研究下如何完成一些更实际的任务,比如说开发一个提醒类的应用,来找出距离一些特定日期比如生日,周日纪念日,下一个帐单日,下一个溢价日或者信用卡过期时间还有多少天。

示例1 如何 在Java 8中获取当天的日期

Java 8中有一个叫LocalDate的类,它能用来表示今天的日期。这个类与java.util.Date略有不同,因为它只包含日期,没有时间。因此,如果你只需要表示日期而不包含时间,就可以使用它。

|LocalDate today = LocalDate.now(); System.out.println("Today's Local date : " + today);	
|	
|Output	
|Today's Local date : 2014-01-14

你可以看到它创建了今天的日期却不包含时间信息。它还将日期格式化完了再输出出来,不像之前的Date类那样,打印出来的数据都是未经格式化的。

示例2 如何在Java 8中获取当前的年月日

LocalDate类中提供了一些很方便的方法可以用于提取出年月日以及其它的日期属性。使用这些方法,你可以获取到任何你所需要的日期属性,而不再需要使用java.util.Calendar这样的类了:

|LocalDate today = LocalDate.now(); 	
|int year = today.getYear();	
|int month = today.getMonthValue(); 	
|int day = today.getDayOfMonth(); 	
|System.out.printf("Year : %d Month : %d day : %d \t %n", year, month, day); 	
|	
|Output 	
|Today's Local date : 2014-01-14	
|Year : 2014 Month : 1 day : 14

可以看到,在Java 8中获取年月信息非常简单,只需使用对应的getter方法就好了,无需记忆,非常直观。你可以拿它和Java中老的获取当前年月日的写法进行一下比较。

示例3 在Java 8中如何获取某个特定的日期

在第一个例子中,我们看到通过静态方法now()来生成当天日期是非常简单的,不过通过另一个十分有用的工厂方法LocalDate.of(),则可以创建出任意一个日期,它接受年月日的参数,然后返回一个等价的LocalDate实例。关于这个方法还有一个好消息就是它没有再犯之前API中的错,比方说,年只能从1900年开始,月必须从0开始,等等。这里的日期你写什么就是什么,比如说,下面这个例子中它代表的就是1月14日,没有什么隐藏逻辑。

|LocalDate dateOfBirth = LocalDate.of(2010, 01, 14); 	
|System.out.println("Your Date of birth is : " + dateOfBirth); 	
|	
|Output : Your Date of birth is : 2010-01-14

可以看出,创建出来的日期就是我们所写的那样,2014年1月14日。

示例4 在Java 8中如何检查两个日期是否相等

如果说起现实中实际的处理时间及日期的任务,有一个常见的就是要检查两个日期是否相等。你可能经常会碰到要判断今天是不是某个特殊的日子,比如生日啊,周年纪念日啊,或者假期之类。有的时候,会给你一个日期,让你检查它是不是某个日子比方说假日。下面这个例子将会帮助你在Java 8中完成这类任务。正如你所想的那样,LocalDate重写了equals方法来进行日期的比较,如下所示:

|LocalDate date1 = LocalDate.of(2014, 01, 14); if(date1.equals(today)){ 	
|  System.out.printf("Today %s and date1 %s are same date %n", today, date1); 	
|} 	
|	
|Output 	
|today 2014-01-14 and date1 2014-01-14 are same date

在本例中我们比较的两个日期是相等的。同时,如果在代码中你拿到了一个格式化好的日期串,你得先将它解析成日期然后才能比较。你可以将这个例子与Java之前比较日期的方式进行下比较,你会发现它真是爽多了。

示例5 在Java 8中如何检查重复事件,比如说生日

在Java中还有一个与时间日期相关的实际任务就是检查重复事件,比如说每月的帐单日,结婚纪念日,每月还款日或者是每年交保险费的日子。如果你在一家电商公司工作的话,那么肯定会有这么一个模块,会去给用户发送生日祝福并且在每一个重要的假日给他们捎去问候,比如说圣诞节,感恩节,在印度则可能是万灯节(Deepawali)。如何在Java中判断是否是某个节日或者重复事件?使用MonthDay类。这个类由月日组合,不包含年信息,也就是说你可以用它来代表每年重复出现的一些日子。当然也有一些别的组合,比如说YearMonth类。它和新的时间日期库中的其它类一样也都是不可变且线程安全的,并且它还是一个值类(value class)。我们通过一个例子来看下如何使用MonthDay来检查某个重复的日期:

|LocalDate dateOfBirth = LocalDate.of(2010, 01, 14); 	
|MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth()); 	
|MonthDay currentMonthDay = MonthDay.from(today); 	
|if(currentMonthDay.equals(birthday)){ 	
|  System.out.println("Many Many happy returns of the day !!"); 	
|}else{ 	
|  System.out.println("Sorry, today is not your birthday"); 	
|} 	
|	
|Output: Many Many happy returns of the day !!

虽然年不同,但今天就是生日的那天,所以在输出那里你会看到一条生日祝福。你可以调整下系统的时间再运行下这个程序看看它是否能提醒你下一个生日是什么时候,你还可以试着用你的下一个生日来编写一个JUnit单元测试看看代码能否正确运行。

示例6 如何在Java 8中获取当前时间

这与第一个例子中获取当前日期非常相似。这次我们用的是一个叫LocalTime的类,它是没有日期的时间,与LocalDate是近亲。这里你也可以用静态工厂方法now()来获取当前时间。默认的格式是hh:mm:ss:nnn,这里的nnn是纳秒。可以和Java 8以前如何获取当前时间做一下比较。

|LocalTime time = LocalTime.now(); System.out.println("local time now : " + time);	
|	
|Output 	
|local time now : 16:33:33.369 // in hour, minutes, seconds, nano seconds

可以看到,当前时间是不包含日期的,因为LocalTime只有时间,没有日期。

示例7 如何增加时间里面的小时数

很多时候我们需要增加小时,分或者秒来计算出将来的时间。Java 8不仅提供了不可变且线程安全的类,它还提供了一些更方便的方法譬如plusHours()来替换原来的add()方法。顺便说一下,这些方法返回的是一个新的LocalTime实例的引用,因为LocalTime是不可变的,可别忘了存储好这个新的引用。

|LocalTime time = LocalTime.now(); 	
|LocalTime newTime = time.plusHours(2); // adding two hours 	
|System.out.println("Time after 2 hours : " + newTime); 	
|	
|Output : 	
|Time after 2 hours : 18:33:33.369

可以看到当前时间2小时后是16:33:33.369。现在你可以将它和Java中增加或者减少小时的老的方式进行下比较。一看便知哪种方式更好。

示例8 如何获取1周后的日期

这与前一个获取2小时后的时间的例子类似,这里我们将学会如何获取到1周后的日期。LocalDate是用来表示无时间的日期的,它有一个plus()方法可以用来增加日,星期,或者月,ChronoUnit则用来表示这个时间单位。由于LocalDate也是不可变的,因此任何修改操作都会返回一个新的实例,因此别忘了保存起来。

|LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS); 	
|System.out.println("Today is : " + today); 	
|System.out.println("Date after 1 week : " + nextWeek); 	
|	
|Output: 	
|Today is : 2014-01-14 	
|Date after 1 week : 2014-01-21

可以看到7天也就是一周后的日期是什么。你可以用这个方法来增加一个月,一年,一小时,一分钟,甚至是十年,查看下Java API中的ChronoUnit类来获取更多选项。

示例9 一年前后的日期

这是上个例子的续集。上例中,我们学习了如何使用LocalDate的plus()方法来给日期增加日,周或者月,现在我们来学习下如何用minus()方法来找出一年前的那天。

|LocalDate previousYear = today.minus(1, ChronoUnit.YEARS); 	
|System.out.println("Date before 1 year : " + previousYear); 	
|LocalDate nextYear = today.plus(1, YEARS); 	
|System.out.println("Date after 1 year : " + nextYear); 	
|	
|Output: 	
|Date before 1 year : 2013-01-14 	
|Date after 1 year : 2015-01-14

可以看到现在一共有两年,一个是2013年,一个是2015年,分别是2014的前后那年。

示例10 在Java 8中使用时钟

Java 8中自带了一个Clock类,你可以用它来获取某个时区下当前的瞬时时间,日期或者时间。可以用Clock来替代System.currentTimeInMillis()与 TimeZone.getDefault()方法.

|  // Returns the current time based on your system clock and set to UTC. 	
|Clock clock = Clock.systemUTC(); 	
|System.out.println("Clock : " + clock); 	
|	
| // Returns time based on system clock zone Clock defaultClock = 	
|Clock.systemDefaultZone();	
|System.out.println("Clock : " + clock); 	
|	
|Output: 	
|Clock : SystemClock[Z] 	
|Clock : SystemClock[Z]

你可以用指定的日期来和这个时钟进行比较,比如下面这样:

|public class MyClass { 	
|  private Clock clock; // dependency inject ... 	
|	
|public void process(LocalDate eventDate) { 	
|	
|if(eventDate.isBefore(LocalDate.now(clock)) { 	
|    ... 	
|    } 	
|  } 	
|}

(未完待续)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值