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. vue学习笔记(五)---- vue动画

    官方文档:https://cn.vuejs.org/v2/guide/transitions.html 一.使用过度类名 没有使用动画之前: <body> <div id=" ...

  2. Selenium CHANGELOG[最新版本4.8.0 计划中]

    Selenium CHANGELOG[持续更新] 源文件 https://github.com/SeleniumHQ/selenium/blob/trunk/py/CHANGES 搬运工 对重点版本做 ...

  3. Nacos配置中心 (介绍与配置)

    Nacos配置中心 当微服务部署的实例越来越多,达到数十.数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错.我们需要一种统一配置管理方案,可以集中管理所有实例的配置. Nacos一方面可以将配置 ...

  4. ElasticSearch使用教程

    一.ElasticSearch使用说明 1. 索引 index,相当于数据库表Table 1.1 查看所有索引 GET _cat/indices?v 1.2 创建索引字段映射关系 PUT /test ...

  5. Web自动化测试怎么做呢?好!接下来我们就开始Web网页测试针对性的流程解析啦!!!

    前言 测试行业现在70%是以手工测试为主,那么只有20%是自动化测试,剩下的10%是性能测试. 有人可能会说,我现在做手工,我为什么要学自动化呢?我去学性能更好性能的人更少? 其实,性能的要求比自动化 ...

  6. Apache Hudi 流转批 场景实践

    背景 在某些业务场景下,我们需要一个标志来衡量hudi数据写入的进度,比如:Flink 实时向 Hudi 表写入数据,然后使用这个 Hudi 表来支持批量计算并通过一个 flag 来评估它的分区数据是 ...

  7. 很奇怪CSDN的审核

    https://www.cnblogs.com/lup9304/p/15310753.html https://www.cnblogs.com/lup9304/p/15328809.html 很奇怪C ...

  8. Python GDAL读取栅格数据并基于质量评估波段QA对指定数据加以筛选掩膜

      本文介绍基于Python语言中gdal模块,对遥感影像数据进行栅格读取与计算,同时基于QA波段对像元加以筛选.掩膜的操作.   本文所要实现的需求具体为:现有自行计算的全球叶面积指数(LAI).t ...

  9. 题解 Trie 但是你要最小化它的节点数量

    名字瞎取的 Description 给定 \(n\) 个字符串 \(s\),可以对 \(s_i\) 的字符打乱,将这些字符串加入一个 trie 里面求节点数量最小值. \(n\le 16, \sum ...

  10. php .inc 文件

    inc 文件顾名思义是include file的意思.即PHP的包含文件,这里用后缀来表示文件的作用, inc文件一般加载一些设置 举个例子   <? php//这里是数据库连接的配置信息db. ...