1、Java8 Date Time API 简介

1.1、新旧 Date Time API 对比

包位置对比

1、Java8之前的日期、时间分布在java.util和java.sql的包中,此外用于格式化和解析的类在java.text包下,位置分散凌乱,不便于查找使用,类命名具有误导性,

示例:

java.util.Date:实际作用应该是DateTime,提供getDay(),getHours(),getMinutes()等方法,且getDay()方法获取的是星期几

java.sql.Date:代表日期,与java.util.Date同名,且大量过时方法,没有关联时区不支持国际化

java.sql.Timestamp

java.text.SimpleDateFormat:格式化

2、Java8开始,功能集中在java.time包下面,且各个包、类的命名及作用清晰,

每个类内提供 Format 和 Parse方法,可以直接调用java.time.LocalDateTime#getDayOfMonth、java.time.LocalDateTime#getHour 等方法

每个类提供通用方法,如:加、减、格式化、解析、从日期/时间中提取单独部分,等等。

java.time 根目录下: LocalDate、LocalTime、LocalDateTime、Instant类Chrono/chronology 日历系统:包含很多年表,包括日本、泰国、民国等format 格式化:时间格式化及解析temporal 时态包:时态的一些操作定义、底层框架和扩展特性,例如:获取月份最后一天zone 时区:时区的支持类

安全性

1、Java8之前 所有Date类都是可变的,在别处的修改会影响该日期值,所以应该返回该日期的克隆而不是日期本身

多线程下使用 静态的 SimpleDateFormat 实例 时存在线程安全问题,如: ava.lang.NumberFormatException: multiple points错误、格式化的时间与输入的时间不一致等问题。

原因:

java.text.SimpleDateFormat#format(java.util.Date, java.lang.StringBuffer, java.text.Format.FieldDelegate)

// 源码
private StringBuffer format(Date date, StringBuffer toAppendTo,
                               FieldDelegate delegate) {
   // 多线程问题,thread1 赋值之后,中断;thread2 赋值,中断;thread1回来数据值已变更
   calendar.setTime(date);
  ...
}

/**
解决:
1.作为方法内部局部变量使用,但每次调用就需要新创建一个实例
2.使用ThreadLocal,每个线程持有一个simpleDateFormat对象
3.同步simpleDateFormat对象,当一个线程调用此方法时,其他调用此方法的线程就要等待
*/
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String formatDate(Date date) throws Exception{
   synchronized(sdf) {
       return sdf.formate(date);
  }
}

2、Java8时所有Date类都具有不变性(final 修饰类),且每次调用都会返回新的对象,所以每次的修改都能保证原对象不变。

// todo Java8 format 如何解决

// 源码
public LocalDate plusDays(long daysToAdd) {
   if (daysToAdd == 0) {
       return this;
  }
   long mjDay = Math.addExact(toEpochDay(), daysToAdd);
   return LocalDate.ofEpochDay(mjDay);
}

public static LocalDate ofEpochDay(long epochDay) {
   long zeroDay = epochDay + DAYS_0000_TO_1970;
   // .......
   return new LocalDate(year, month, dom);
}

2、Java8 Date Time API 示例

2.1 java.time.LocalDate 日期类,默认格式为 yyyy-MM-dd

// 当前日期
LocalDate today = LocalDate.now();
System.out.println("当前日期=" + today); // 当前日期=2018-12-27

// 指定日期
LocalDate firstDay_2018 = LocalDate.of(2018, Month.JANUARY, 1);
System.out.println("指定日期=" + firstDay_2018); // 指定日期=2018-01-01

// 其他时区当前日期
LocalDate todayNew_York = LocalDate.now(ZoneId.of("America/New_York"));
System.out.println("纽约当前日期=" + todayNew_York); //洛杉矶当前日期=2018-12-27

LocalDate dateFromBase = LocalDate.ofEpochDay(365); // 01/01/1970
System.out.println("开始日期增加 365 天 = " + dateFromBase); //开始日期增加 365 天 = 1971-01-01

LocalDate hundredDay2014 = LocalDate.ofYearDay(2018, 90);
System.out.println("年份第一天增加 90 天=" + hundredDay2014); //年份第一天增加 100 天=2018-03-31

2.2 java.time.LocalTime 时间类

LocalTime time = LocalTime.now();
System.out.println("当前时间=" + time); // 当前时间=14:55:50.494

LocalTime specificTime = LocalTime.of(12, 20, 25, 40);
System.out.println("具体时间=" + specificTime); // 具体时间=12:20:25.000000040

LocalTime timeLos_Angeles = LocalTime.now(ZoneId.of("America/Los_Angeles"));
System.out.println("洛杉矶当前时间=" + timeLos_Angeles); // 洛杉矶当前时间=22:55:50.495

LocalTime specificSecondTime = LocalTime.ofSecondOfDay(10000);
System.out.println("1000 秒= " + specificSecondTime); //10000th second time= 02:46:40

2.3 java.time.LocalDateTime 日期时间类

LocalDateTime today = LocalDateTime.now();
System.out.println("当前日期时间=" + today); // 当前日期时间=2018-12-28T15:15:01.364

today = LocalDateTime.of(LocalDate.now(), LocalTime.now());
System.out.println("当前日期时间=" + today); // 当前日期时间=2018-12-28T15:15:01.365

LocalDateTime specificDate = LocalDateTime.of(2014, Month.JANUARY, 1, 10, 10, 30);
System.out.println("具体日期时间=" + specificDate); // 具体日期时间=2014-01-01T10:10:30

LocalDateTime todayLos_Angeles = LocalDateTime.now(ZoneId.of("America/Los_Angeles"));
System.out.println("洛杉矶当前日期时间=" + todayLos_Angeles); // 洛杉矶当前日期时间=2018-12-27T23:15:01.366

LocalDateTime dateFromBase = LocalDateTime.ofEpochSecond(10000, 0, ZoneOffset.UTC);
System.out.println("初始日期加 10000 秒 = " + dateFromBase); // 初始日期加 10000 秒 = 1970-01-01T02:46:40

2.4 java.time.Instant 时间戳

Instant timestamp = Instant.now();
System.out.println("当前时间 = " + timestamp); //当前时间 = 2018-12-28T07:36:40.572Z

long timestampLong = timestamp.toEpochMilli();
System.out.println("时间戳 = "+ timestampLong); // 时间戳 = 1545982600572

Instant specificTime = Instant.ofEpochMilli(timestampLong);
System.out.println("具体时间 = " + specificTime); // 具体时间 = 2018-12-28T07:36:40.572Z

3、Java8 及旧 API 常用操作实例

3.1 获取当前日期

LocalDate newCurrentDate = LocalDate.now(); //2018-12-17
LocalDate newSetDate = LocalDate.of(2018, 12, 17);
Date oldCurrentDate = new Date(); // Thu Dec 27 11:20:47 CST 2018

3.2 获取月的某一天

  LocalDate lastDayOfThisMonth = newCurrentDate.with(TemporalAdjusters.lastDayOfMonth()); //2018-12-31
 LocalDate secondDayOfThisMonth = newCurrentDate.withDayOfMonth(2); //2018-12-02
 // 获取指定月份的最后一天
 LocalDate lastDayOfMonth = newCurrentDate.withMonth(11).with(TemporalAdjusters.lastDayOfMonth()); // 2018-11-30
  SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
 Calendar calendar = Calendar.getInstance();
 calendar.set(Calendar.DAY_OF_MONTH,
              calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
 String firstDayOfWeek = format.format(calendar.getTime());  // 2018-12-31
 // 获取指定月份的最后一天
 calendar.set(Calendar.MONTH, 11); // 月份从 0 开始
 calendar.set(Calendar.DAY_OF_MONTH, 0); // 2018-11-30
 

3.3 计算时间差

LocalDateTime start = LocalDateTime.of(2018, 11, 1, 0, 0, 0);
LocalDateTime end = LocalDateTime.of(2018, 12, 1, 0, 0, 0);
// Duration
Duration duration = Duration.between(start, end);
System.out.println("日期天数差:" + duration.toDays()); // 30
// Period
Period period = Period.between(start.toLocalDate(), end.toLocalDate());
System.out.println(period.getYears()+" 年 "+ period.getMonths()+" 月 "+ period.getDays()+" 日 "); // 0 年 1 月 0 日
// ChronoUnit
long daysDiff = ChronoUnit.DAYS.between(start, end);
System.out.println("日期天数差:" + daysDiff);
long hoursDiff = ChronoUnit.HOURS.between(start, end);
System.out.println("日期小时差:" + hoursDiff);
SimpleDateFormat simpleFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm");
/*天数差*/
Date fromDate1 = simpleFormat.parse("2018-12-01 00:00");  
Date toDate1 = simpleFormat.parse("2018-12-30 12:00");  
long from1 = fromDate1.getTime();  
long to1 = toDate1.getTime();  
int days = (int) ((to1 - from1) / (1000 * 60 * 60 * 24));  
System.out.println("两个时间之间的天数差为:" + days);

3.4 格式化

DateTimeFormatter formatter =
                            DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
String strDate = LocalDateTime.now().format(formatter);
System.out.println("系统自带年月日:"+ strDate); // 2018-12-17
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String strDate1 = LocalDateTime.now().format(formatter1);
System.out.println("指定年月日:"+ strDate1); // 2018-12-17
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String strDate2 = simpleDateFormat.format(new Date());
System.out.println("系统自带:"+strDate2);  // 2018-12-17
// org.apache.commons.lang3.time.DateFormatUtils
String strDate3 = DateFormatUtils.format(new Date(), "yyyy-MM-dd");
System.out.println("工具类:"+ strDate3); // 2018-12-17

3.5 解析

LocalDateTime parseDate1 = LocalDateTime.parse("2018-12-17 18:04:01",     
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println("Java8: "+ parseDate1); // Java8: 2018-12-17T18:04:01
try {
   SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
   Date date = simpleDateFormat.parse("2018-12-17 18:04:01");
   System.out.println("Java8 之前: " +date); // Java8 之前: Mon Dec 17 18:04:01 CST 2018
} catch (ParseException e) {
   e.printStackTrace();
}

3.6 获取毫秒

// 获取秒数
Long second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
System.out.println("second = "+ second);
// 获取毫秒数
Long milliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
System.out.println("milliSecond = "+milliSecond);
// LocalDateTime 获取毫秒数
System.out.println(Timestamp.valueOf(LocalDateTime.now()).getTime());
// Date 获取毫秒数
System.out.println(new java.util.Date().getTime());

3.7 Java8 对旧 Date API 的支持

// Date to Instant
Instant timestamp = new Date().toInstant();

// Calendar to Instant
Instant time = Calendar.getInstance().toInstant();
System.out.println("Instant = "+time); // Instant = 2018-12-28T07:45:31.652Z

// Instant 转 Date
Date dt = Date.from(Instant.now());
System.out.println("date = "+ dt); // date = Fri Dec 28 15:45:31 CST 2018

// java.util.TimeZone 转 java.time.ZoneId
ZoneId defaultZone = TimeZone.getDefault().toZoneId();
System.out.println("defaultZone = "+defaultZone); // defaultZone = Asia/Shanghai

/**
* java.time.ZoneId 转 java.util.TimeZone
* TimeZone =sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,
*             useDaylight=false,transitions=19,lastRule=null]
*/
TimeZone tz = TimeZone.getTimeZone(defaultZone);
System.out.println("TimeZone = "+ tz);

//java.util.GregorianCalendar#GregorianCalendar() 转 java.time.ZonedDateTime
ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();
System.out.println(gregorianCalendarDateTime); // 2018-12-28T15:45:31.672+08:00[Asia/Shanghai]

/**
* java.time.ZonedDateTime 转 java.util.GregorianCalendar#GregorianCalendar()
* GregorianCalendar = java.util.GregorianCalendar[time=1545983131672,areFieldsSet=true,
* areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
* offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null],
* firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2018,MONTH=11,WEEK_OF_YEAR=52,
*WEEK_OF_MONTH=4,DAY_OF_MONTH=28,DAY_OF_YEAR=362,DAY_OF_WEEK=6,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,
*HOUR=3,HOUR_OF_DAY=15,MINUTE=45,SECOND=31,MILLISECOND=672,ZONE_OFFSET=28800000,DST_OFFSET=0]
*/
GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime);
System.out.println("GregorianCalendar = "+gc);

 // Date 用的是 UTC 时间戳,所以与 LocalDateTime 等互转时需设置时区

Date in = new Date();
   LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
   Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());

Java8 Date Time API 简介的更多相关文章

  1. java8 Date/Time API 新的日期处理工具

    接上篇文章 java8 新特性 由于上篇过于庞大,使得重点不够清晰,本篇单独拿出 java8 的 Date/Time api 进行说明,新的日期时间工具全部都在 java.time 及其子包中. 新 ...

  2. Java 8 Date Time API Example Tutorial – LocalDate, Instant, LocalDateTime, Parse and Format

    参考 Java 8 Date and Time API is one of the most sought after change for developers. Java has been mis ...

  3. Java之Date Time API (Java 8 新特性)

    Java 8 – Date Time API Java 8 comes with a much improved and much required change in the way date an ...

  4. Java8 Date与LocalDate互转

    Java8 日期时间API,新增了LocalDate.LocalDateTime.LocalTime等线程安全类,接下来要说的是LocalDate与java.util.Date之间的转换. 1.Loc ...

  5. Web Api 简介

    ASP.NET Web API 简介  ASP.NET MVC 4 包含了 ASP.NET Web API, 这是一个创建可以连接包括浏览器.移动设备等多种客户端的 Http 服务的新框架, ASP. ...

  6. ZooKeeper系列4:ZooKeeper API简介及编程

    问题导读: 1.ZooKeeper API 共包含几个包? 2.如何使用ZooKeeper API 创建zookeeper应用程序? 1)ZooKeeper API 简介   ZooKeeper AP ...

  7. WebSocket API简介

    WebSocket是html5新增加的一种通信协议,目前流行的浏览器都支持这个协议,例如Chrome,Safari,Firefox,Opera,IE等等,对该协议支持最早的应该是chrome,从chr ...

  8. 构建简单的 C++ 服务组件,第 1 部分: 服务组件体系结构 C++ API 简介

    构建简单的 C++ 服务组件,第 1 部分: 服务组件体系结构 C++ API 简介 熟悉将用于 Apache Tuscany SCA for C++ 的 API.您将通过本文了解该 API 的主要组 ...

  9. Raphael Js矢量库API简介:

    Raphael Js矢量库API简介:Raphael Javascript 是一个 Javascript的矢量库. 2010年6月15日,著名的JavaScript库ExtJS与触摸屏代码库项目jQT ...

  10. 开放数据接口 API 简介与使用场景、调用方法

    此文章对开放数据接口 API 进行了功能介绍.使用场景介绍以及调用方法的说明,供用户在使用数据接口时参考之用. 在给大家分享的一系列软件开发视频课程中,以及在我们的社区微信群聊天中,都积极地鼓励大家开 ...

随机推荐

  1. C# SMTP发邮件不支持465端口的解决方案

    C# 发邮件帮助类传送门(465端口除外): https://www.cnblogs.com/dennisdong/p/15953790.html 一.问题解惑,为什么465发送失败 查阅资料得知,. ...

  2. freertos内存pvPortMalloc 和 malloc 区别 ,以及全局变量占用情况

    1.FreeRtos占用内存 #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 30 * 1024 ) ) pvPortMalloc是从configTOTAL_ ...

  3. 硬件协议之i2c

    https://blog.csdn.net/ctyqy2015301200079/article/details/83830326  (此文章可能有误) 从目前来看,所有读写操作(包括ACK的读写)都 ...

  4. Spring(AOP的认识、实现)

    2:Spring AOP AOP (Aspect Oriented Programming) 面向切面编程 OOP(Object Oriented Programming)面向对象编程,用对象的思想来 ...

  5. Vulhub 漏洞学习之:ECShop

    Vulhub 漏洞学习之:ECShop 目录 Vulhub 漏洞学习之:ECShop 1 ECShop 2.x/3.x SQL注入/远程命令执行漏洞 1.1 环境安装 1.2 漏洞产生原因 1.3 漏 ...

  6. Vulhub 漏洞学习之:Dubbo

    Vulhub 漏洞学习之:Dubbo 目录 Vulhub 漏洞学习之:Dubbo 1 Aapche Dubbo Java反序列化漏洞(CVE-2019-17564) 1.1 环境安装 1.2 漏洞利用 ...

  7. AttributeError: module 'requests' has no attribute 'get' 报错分析

    这个报错与代码时没有关系 当文件名与调用模块名重合时,系统找不到我们调用的requests模块. 在命名时,我们要注意不要重合.

  8. 基于线程的并行-Python 并行编程学习笔记(一)

    前言 最近写一些模拟集群智能的算法,虽然机制简单,但是随着个体的增加,设计的计算量就比较大了,尤其是加上matplotlib进行动态展示,使得运算量骤增,看着画面也比较卡.之前想把算法转化成c++代码 ...

  9. jquery实现多图片上传

    在做后台管理的时候,遇到这样一个需求,实现多张图片上传并按选中的顺序显示.PS:图片上传的时候是即时上传到服务器,后台返回图片在服务器上的地址,在最后点击提交按钮的时候,把地址传给后端写入数据库即可. ...

  10. [转载]Net分布式系统之四:RabbitMQ消息队列应用

    消息通信组件Net分布式系统的核心中间件之一,应用与系统高并发,各个组件之间解耦的依赖的场景.本框架采用消息队列中间件主要应用于两方面:一是解决部分高并发的业务处理:二是通过消息队列传输系统日志.目前 ...