博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java中日期的换算处理
阅读量:6367 次
发布时间:2019-06-23

本文共 12268 字,大约阅读时间需要 40 分钟。

JAVA8中的日期API是JSR-310的实现,并且是工作在ISO-8601日历系统基础上的,但我们也可以在非ISO的日历上。

JDK8的日期API大致分为以下几个包:

1 java.time包:JDK8中的基础包,所有常用的基础类都是这个包的一部分,如LocalDate,LocalTime,LocalDateTime等等,所有这些类都是不可变且线程安全的;2 java.time.chrono包:这个包为非ISO的日历系统定义了一些API,我们可以在借助这个包中的一些类扩展我们自己的日历系统;3 java.time.format包:这个包很明显了,格式化和解析日期时间对象,一般java.time包中的类都差不多能满足我们的需求了,如果有需要,可以调用这个包下的类自定义解析方式;4 java.time.temporal包:这个包很有意思,封装了一些获取某个特定日期和时间的接口,比如某月的第一天或最后一天,并且这些方法都是属于特别好认的方法。5 java.time.zone包:这个包就是时区相关的类了。

在JDK1.8中,我们经常使用的大约有如下几个类:LocalDate, LocalTime, LocalDateTime, DateTimeFormatter等,所以我们主要看一下这几个类的相关方法。

1. 日期API

1.1 LocalDate

java.time.LocalDate这个类,是用来表示日期的,也仅包含日期,用起来十分方便,方法也十分简单。我们来看一些小例子:

public static void testDate() {    // 1. 获取当前日期(年月日) -----打印输出-----2018-01-29    LocalDate localDate = LocalDate.now();    System.out.println(localDate.toString());    // 2. 根据年月日构建Date ----打印输出-----2018-01-30    LocalDate localDate1 = LocalDate.of(2018, 01, 30);    // 3. 字符串转换日期,严格按照yyyy-MM-dd格式,02写成2都不行,也可以自定义格式 -----打印输出-----2018-01-30。无效日期无法通过:DateTimeParseException: Invalid date    LocalDate localDate2 = LocalDate.parse("2018-01-30");    // 4. 获取本月第一天 -----打印输出-----2018-01-01    LocalDate firstDayOfMonth = localDate.with(TemporalAdjusters.firstDayOfMonth());    // 5. 获取本月第二天  -----打印输出-----2018-01-02    LocalDate secondDayOfMonth = localDate.withDayOfMonth(2);    // 6. 获取本月最后一天,再也不用计算是28,29,30还是31-----打印输出-----2018-01-31    LocalDate lastDayOfMonth = localDate.with(TemporalAdjusters.lastDayOfMonth());    // 7. 明天 -----打印输出----- 2018-01-30    LocalDate tomorrowDay = localDate.plusDays(1L);    // 8. 昨天 -----打印输出----- 2018-01-28    LocalDate yesterday = localDate.minusDays(1L);    // 9. 获取本年第120天 -----打印输出----- 2018-04-30    LocalDate day = localDate.withDayOfYear(120);    // 10. 计算两个日期间的天数    long days = localDate.until(localDate1, ChronoUnit.DAYS);    System.out.println(days);    // 11. 计算两个日期间的周数    long weeks = localDate.until(localDate1, ChronoUnit.WEEKS);    System.out.println(weeks);    // 12. 取2015年1月第一个周一,这个计算用Calendar要死掉很多脑细胞:    LocalDate firstMondayOf2015 = LocalDate.parse("2015-01-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)); // 2015-01-05}
1.2 LocalTime

同样,和LocalDate相对应的另一个类就是LocalTime,这个类恰好和LocalDate相反,它表示的全是时间,不包含日期。例子如下:

public static void testTime() {    // 1. 获取当前时间,包含毫秒数 -----打印输出----- 21:03:26.315    LocalTime localTime = LocalTime.now();    // 2. 你可能想清除毫秒数:    LocalTime now = LocalTime.now().withNano(0)); // 11:09:09    // 3. 构建时间 -----打印输出----- 12:15:30    LocalTime localTime1 = LocalTime.of(12, 15, 30);    // 4. 获取当前时间,不包含毫秒数 -----打印输出----- 21:01:56    LocalTime localTime2 = localTime.withNano(0);    // 5. 字符串转为时间,还可以有其他格式,比如12:15, 12:15:23.233    // -----打印输出----- 12:15:30    LocalTime localTime3 = LocalTime.parse("12:15:30");}
1.3 LocalDateTime

LocalDateTime就和原先的java.util.Date很像了,既包含日期,又包含时间,它经常和DateTimeFormatter一起使用。

public static void testDateTime() {    // 1. 获取当前年月日 时分秒 -----打印输出----- 2018-01-29T21:23:26.774    LocalDateTime localDateTime = LocalDateTime.now();    // 2. 通过LocalDate和LocalTime构建 ----- 打印输出----- 2018-01-29T21:24:41.738    LocalDateTime localDateTime1 = LocalDateTime.of(LocalDate.now(), LocalTime.now());    // 3. 构建年月日 时分秒 -----打印输出----- 2018-01-29T19:23:13    LocalDateTime localDateTime2 = LocalDateTime.of(2018, 01, 29, 19, 23, 13);    // 4. 格式化当前时间 ----打印输出----- 2018/01/29    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");    System.out.println(formatter.format(localDateTime2));}

使用LocalDateTime的with开头的方法可以设置相应的时间,小时,分钟等,比如:

// 设置分钟数LocalDateTime localDateTime = LocalDateTime.now().withMinute(23);

需要注意的有两点:

1 LocalDateTime默认的格式是 2018-01-29T21:23:26.774 这种格式,这可能与我们经常使用的格式不太符合,所以我们可以指定格式。2 DateTimeFormatter本身提供了许多静态格式化常量,我们可以参考使用,如果不能满足我们的需求的话,我们可以自定义;
1.4 TemporalAdjusters

该类是一个计算用的类,提供了各种各样的计算方法。比如某个月的第一天,某个月的最后一天,某一年的第一天,某一年的第几天等各种计算方法。该类内部实现基本上全都是通过JDK8的Lambda表达式来实现的。随便举一些例子,都很简单。

LocalDate localDate = LocalDate.now();        // 1. 本月第一天LocalDate firstDayOfMonth = localDate.with(TemporalAdjusters.firstDayOfMonth());// 2. 本月最后一天LocalDate lastDayOfMonth = localDate.with(TemporalAdjusters.lastDayOfMonth());// 3. 本年第一天LocalDate firstDayOfYear = localDate.with(TemporalAdjusters.firstDayOfYear());// 4. 下个月第一天LocalDate firstDayOfNextMonth = localDate.with(TemporalAdjusters.firstDayOfNextMonth());// 5. 本年度最后一天LocalDate lastDayOfYear = localDate.with(TemporalAdjusters.lastDayOfYear());System.out.println(firstDayOfMonth);System.out.println(lastDayOfMonth);System.out.println(firstDayOfYear);System.out.println(firstDayOfNextMonth);System.out.println(lastDayOfYear);

打印输出:

2018-01-012018-01-312018-01-012018-02-012018-12-31
1.5 Period和Duration

  Period是基于ISO-8601标准的日期系统,用于计算两个日期间的年,月,日的差值。比如'2年,3个月,4天';而Duration和Period很像,但Duration计算的是两个日期间的秒,纳秒的值,是一种更为精确的计算方式;而ISO-8601系统是当今世界大部分地区采用的现代日历的阳历系统。

LocalDate localDate = LocalDate.now();LocalDate localDate1 = LocalDate.of(2018, 3, 28);Period period = Period.between(localDate, localDate1);System.out.println(period.getDays());System.out.println(period.getMonths());

当然如果我们看一下Period的between方法实现,就知道底层是通过LocalDate.until方法来实现的。同样,Period的between方法也就等同于LocalDate.until方法。

但这里有一个问题,就是Period的getDays方法返回的不是两个日期间总的天数,有点像月计算后剩余的天数,但也不完全是,所以不太清楚这个类实际的意义。看个例子:

LocalDate localDate1 = LocalDate.of(2018, 01, 30);LocalDate localDate2 = LocalDate.of(2018, 03, 01);Period period = Period.between(localDate1, localDate2);System.out.println(period.getDays());

打印:1

我们把第一行代码换一下值,再看一下:

LocalDate localDate1 = LocalDate.of(2018, 01, 29);

结果还是打印1。再换:

LocalDate localDate1 = LocalDate.of(2018, 01, 28);LocalDate localDate1 = LocalDate.of(2018, 01, 27);

上面两个分别打印12

所以说,在没搞清楚上面的方法之前,还是不要贸然使用,而如果要计算两个日期间的总的天数,可以用如下方法来计算:

System.out.println(localDate1.until(localDate2, ChronoUnit.DAYS));System.out.println(ChronoUnit.DAYS.between(localDate1, localDate2));

而对于Duration来说,就更简单了,计算两个时间之间的秒数,纳秒数:

LocalTime localTime1 = LocalTime.of(12, 12, 12);LocalTime localTime2 = LocalTime.of(12, 13, 27);Duration duration = Duration.between(localTime1, localTime2);System.out.println(duration.getSeconds());  // 75

但有一点需要注意,Duration中必须要支持秒数,如果没有的话,将会报错,如:

LocalDate localDate1 = LocalDate.of(2018, 02, 28);LocalDate localDate2 = LocalDate.of(2018, 02, 27);Duration duration = Duration.between(localDate1, localDate2);System.out.println(duration.getSeconds());

将会直接提示:

Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds    at java.time.LocalDate.until(LocalDate.java:1614)    at java.time.Duration.between(Duration.java:475)    at com.jdk8.DateTest.testPeriod(DateTest.java:40)    at com.jdk8.DateTest.main(DateTest.java:23)
1.6 ChronoUnit

  这个是个枚举类型,实现功能类型Period和Duration,但如果我们看它的底层实现,就可以看到它基本是基于Duration来实现的。这个枚举很简单,我们直接看一些例子就可以了:

LocalDateTime oldDate = LocalDateTime.of(2017, Month.AUGUST, 31, 10, 20, 55);LocalDateTime newDate = LocalDateTime.of(2018, Month.NOVEMBER, 9, 10, 21, 56);System.out.println(oldDate);System.out.println(newDate);// count between dateslong years = ChronoUnit.YEARS.between(oldDate, newDate);long months = ChronoUnit.MONTHS.between(oldDate, newDate);long weeks = ChronoUnit.WEEKS.between(oldDate, newDate);long days = ChronoUnit.DAYS.between(oldDate, newDate);long hours = ChronoUnit.HOURS.between(oldDate, newDate);long minutes = ChronoUnit.MINUTES.between(oldDate, newDate);long seconds = ChronoUnit.SECONDS.between(oldDate, newDate);long milis = ChronoUnit.MILLIS.between(oldDate, newDate);long nano = ChronoUnit.NANOS.between(oldDate, newDate);System.out.println("\n--- Total --- ");System.out.println(years + " years");System.out.println(months + " months");System.out.println(weeks + " weeks");System.out.println(days + " days");System.out.println(hours + " hours");System.out.println(minutes + " minutes");System.out.println(seconds + " seconds");System.out.println(milis + " milis");System.out.println(nano + " nano");

打印结果:

2017-08-31T10:20:552018-11-09T10:21:56--- Total --- 1 years14 months62 weeks435 days10440 hours626401 minutes37584061 seconds37584061000 milis37584061000000000 nano
1.7 Clock

  时钟系统,用于查找当前时刻。通过指定一个时区,我们可以获取到当前的时刻,日期,时间。所以可以使用一个时钟来代替System.currenttimemillis()TimeZone.getDefault()

在应用程序的最佳实践是将时钟传递给任何需要当前即刻的方法:

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

我们可以简单测试一下:

// 系统默认Clock systemDefaultClock = Clock.systemDefaultZone();System.out.println("Current DateTime with system default clock: " + LocalDateTime.now(systemDefaultClock));System.out.println(systemDefaultClock.millis());// 世界协调时UTCClock systemUTCClock = Clock.systemUTC();System.out.println("Current DateTime with UTC clock: " + LocalDateTime.now(systemUTCClock));System.out.println(systemUTCClock.millis());//芝加哥Clock clock = Clock.system(ZoneId.of(ZoneId.SHORT_IDS.get("CST")));System.out.println("Current DateTime with CST clock: " + LocalDateTime.now(clock));System.out.println(clock.millis());

打印:

Current DateTime with system default clock: 2018-02-02T16:26:07.6651517559967665Current DateTime with UTC clock: 2018-02-02T08:26:07.6651517559967665Current DateTime with CST clock: 2018-02-02T02:26:07.6671517559967667

并且我们可以使用 millis 方法来代替 System.currenttimemillis()

更多有关Clock方法实例可以参考下面链接(没找到JDK8的,不过可以参考JDK9的):

1.8 其他

其中还有一些类没有详细说明,比如:

1 Instant,表示的是时间戳,用于记录某一时刻的更改(JDK8之前的Timestamp);2 ZoneId 时区标志,比如用于标志欧洲/巴黎;3 ZoneOffset 时区偏移量,与UTC的偏移量;4 ZonedDateTime 与时区有关的日历系统,比如2007-12 03t10:15:30+01欧洲/巴黎;5 OffsetDateTime 用于与UTC偏移的日期时间,如如2007-12 03t10:15:30+01:00。

2. 转换

2.1 java.util.Date与LocalDate,LocalTime,LocalDateTime替换

将Date转换为LocalDate,LocalTime,LocalDateTime可以借助于ZonedDateTime和Instant,实现如下:

Date date = new Date();System.out.println("current date: " + date);// Date -> LocalDateTimeLocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();System.out.println("localDateTime by Instant: " + localDateTime);// Date -> LocalDateLocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();System.out.println("localDate by Instant: " + localDate);// Date -> LocalTimeLocalTime localTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();System.out.println("localTime by Instant: " + localTime);//2. Date -> LocalDateTimelocalDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());System.out.println("localDateTime by ofInstant: " + localDateTime);

output:

current date: Fri Feb 02 16:43:13 CST 2018localDateTime by Instant: 2018-02-02T16:43:13.073localDateTime by ofInstant: 2018-02-02T16:43:13.073localDate by Instant: 2018-02-02localTime by Instant: 16:43:13.073

由于JDK8实现了向下兼容,所以Date里在JDK8版本引入了2个方法,from

toInstant,所以我们可以借助这两个方法来实现LocalDateTime到Date的转换。将LocalDateTime转为Date如下:

LocalDateTime localDateTime = LocalDateTime.now();System.out.println("localDateTime: " + localDateTime);// LocalDateTime -> DateDate date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());System.out.println("LocalDateTime -> current date: " + date);// LocalDate -> Date,时间默认都是00LocalDate localDate = LocalDate.now();date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());System.out.println("LocalDate -> current date: " + date);

output:

localDateTime: 2018-02-02T16:55:52.464LocalDateTime -> current date: Fri Feb 02 16:55:52 CST 2018LocalDate -> current date: Fri Feb 02 00:00:00 CST 2018

而单独的LocalTime转为Date没什么意义,所以如果LocalTime要转为Date,一般借助于LocalDate和LocalDateTime来实现就可以了。

2.2 日期与字符串的转换

 日期与字符串的转换比较简单。先说转换成日期格式,通过LocalDate,LocalTime,LocalDateTime的parse方法和DateTimeFormatter来实现:

LocalDate localDate = LocalDate.parse("2018-09-09", DateTimeFormatter.ofPattern("yyyy-MM-dd"));LocalDateTime localDateTime = LocalDateTime.parse("2018-09-10 12:12:12", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:ss:mm"));

而将日期转为字符串,可以通过format方法和DateTimeFormatter来实现:

String localDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));String localDateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:ss:mm"));

 

总结

1 java.time包下其实还有一些其他的类与方法,如查询是否是闰年,日期比较,获取某一年的某一天等等,我们可以等用到的时候再去查看不迟。并且我们可以将我们常用的方法封装成util包供我们在使用的时候直接调用。2 JDK8提供的这套API接口基本上封装了我们平时常用的所有与日期时间的相关操作,所以如果升级了JDK8,在处理日期和时间的时候尽量多用新的API。3 JDK8中新的日期不但命名优雅,通俗易懂,而且提供了向下兼容的能力,可以无缝连接。4 如果用到了Period,注意它的getDays方法。

作者:骑着乌龟去看海
链接:
來源:简书

转载地址:http://vfrma.baihongyu.com/

你可能感兴趣的文章
Heartbeat+DRBD+MFS高可用
查看>>
要感谢那些曾经慢待你的人
查看>>
常见的global cache等待事件
查看>>
第 7 章 多主机管理 - 047 - 管理 Machine
查看>>
CentOS5和6的系统启动流程
查看>>
怎么看域客户端是否继承了组策略
查看>>
linux防止DDoS***
查看>>
6.4 Linked List 重做
查看>>
小米路由
查看>>
QT 学习 之 窗口拖拽 实现
查看>>
PHP的ftp文件,多文件上传操作类
查看>>
js中清空数组的方法
查看>>
python def说明
查看>>
Java根据IP获取国家省级地市信息
查看>>
自动安装系统及网络安装服务
查看>>
11g RAC 更改归档模式 ,归档文件存放在ASM 磁盘组
查看>>
Visual Studio安装项目中将用户选择的安装路径写入注册表的方法[转]
查看>>
【转载】VBA:调用文件夹对话框的几种方法
查看>>
centos rm命令恢复删除的文件
查看>>
eclipse修改源码导出jar包
查看>>