Java 时间与日期处理

王下邀月熊

18 小时前

Java 时间与日期处理 从属于笔者的 现代 Java 开发系列文章,涉及到的引用资料声明在 Java 学习与实践资料索引中。

Java 时间与日期处理

在 Java 8 之前,我们最常见的时间与日期处理相关的类就是 Date、Calendar 以及 SimpleDateFormatter 等等。不过 java.util.Date 也是被诟病已久,它包含了日期、时间、毫秒数等众多繁杂的信息,其内部利用午夜 12 点来区分日期,利用 1970-01-01 来计算时间;并且其月份从 0 开始计数,而且用于获得年、月、日等信息的接口也是太不直观。除此之外,java.util.Date与 SimpleDateFormatter 都不是类型安全的,而 JSR-310 中的 LocalDate 与 LocalTime 等则是不变类型,更加适合于并发编程。JSR 310 实际上有两个日期概念。第一个是 Instant,它大致对应于 java.util.Date 类,因为它代表了一个确定的时间点,即相对于标准 Java 纪元(1970年1月1日)的偏移量;但与 java.util.Date 类不同的是其精确到了纳秒级别。另一个则是 LocalDate、LocalTime 以及 LocalDateTime 这样代表了一般时区概念、易于理解的对象。

Class / TypeDescriptionYearRepresents a year.YearMonthA month within a specific year.LocalDateA date without an explicitly specified time zone.LocalTimeA time without an explicitly specified time zone.LocalDateTimeA combination date and time without an explicitly specified time zone.

最新 JDBC 映射将把数据库的日期类型和 Java 8 的新类型关联起来:

SQLJavadateLocalDatetimeLocalTimetimestampLocalDateTimedatetimeLocalDateTime

时间与日期基础概念

标准时间

GMT 即「格林威治标准时间」( Greenwich Mean Time,简称 G.M.T. ),指位于英国伦敦郊区的皇家格林威治天文台的标准时间,因为本初子午线被定义为通过那里的经线。然而由于地球的不规则自转,导致 GMT 时间有误差,因此目前已不被当作标准时间使用。UTC 是最主要的世界时间标准,是经过平均太阳时(以格林威治时间 GMT 为准)、地轴运动修正后的新时标以及以「秒」为单位的国际原子时所综合精算而成的时间。UTC 比 GMT 来得更加精准。其误差值必须保持在 0.9 秒以内,若大于 0.9 秒则由位于巴黎的国际地球自转事务中央局发布闰秒,使 UTC 与地球自转周期一致。不过日常使用中,GMT 与 UTC 的功能与精确度是没有差别的。协调世界时区会使用 “Z” 来表示。而在航空上,所有使用的时间划一规定是协调世界时。而且 Z 在无线电中应读作 “Zulu”(可参见北约音标字母),协调世界时也会被称为 “Zulu time”。

TimeZone&UTC Offsets: 时区与偏移

人们经常会把时区与 UTC 偏移量搞混,UTC 偏移量代表了某个具体的时间值与 UTC 时间之间的差异,通常用 HH:mm 形式表述。而 TimeZone 则表示某个地理区域,某个 TimeZone 中往往会包含多个偏移量,而多个时区可能在一年的某些时间有相同的偏移量。譬如 America/Chicago, America/Denver, 以及 America/Belize 在一年中不同的时间都会包含 -06:00 这个偏移。

时间戳

Unix 时间戳表示当前时间到 1970 年 1 月 1 日 00:00:00 UTC 对应的秒数。注意,JavaScript 内的时间戳指的是当前时间到 1970 年 1 月 1 日 00:00:00 UTC 对应的毫秒数,和 Unix 时间戳不是一个概念,后者表示秒数,差了 1000 倍。

时间数字字符串格式

RFC2822

YYYY/MM/DD HH:MM:SS ± timezone(时区用4位数字表示)
// eg 1992/02/12 12:23:22+0800

ISO 8601

国际标准化组织的国际标准 ISO 8601 是日期和时间的表示方法,全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》。目前最新为第三版 ISO8601:2004,第一版为 ISO8601:1988,第二版为 ISO8601:2000。年由 4 位数组成,以公历公元 1 年为 0001 年,以公元前 1 年为 0000 年,公元前 2 年为 -0001 年,其他以此类推。应用其他纪年法要换算成公历,但如果发送和接受信息的双方有共同一致同意的其他纪年法,可以自行应用。

YYYY-MM-DDThh:mm:ss ± timezone(时区用HH:MM表示)
1997-07-16T08:20:30Z
// “Z”表示UTC标准时区,即"00:00",所以这里表示零时区的`1997年7月16日08时20分30秒`
//转换成位于东八区的北京时间则为`1997年7月17日16时20分30秒`
1997-07-16T19:20:30+01:00
// 表示东一区的1997年7月16日19时20秒30分,转换成UTC标准时间的话是1997-07-16T18:20:30Z

时间戳

在 Java 8 之前,我们使用 java.sql.Timestamp 来表示时间戳对象,可以通过以下方式创建与获取对象:

// 利用系统标准时间创建
Timestamp timestamp = new Timestamp(System.currentTimeMillis());// 从 Date 对象中创建
new Timestamp((new Date()).getTime());// 获取自 1970-01-01 00:00:00 GMT 以来的毫秒数
timestamp.getTime();

在 Java 8 中,即可以使用 java.time.Instant 来表示自从 1970-01-01T00:00:00Z 之后经过的标准时间:

// 基于静态函数创建
Instant instant = Instant.now();// 基于 Date 或者毫秒数转换
Instant someInstant = someDate.toInstant();
Instant someInstant = Instant.ofEpochMilli(someDate.getTime());// 基于 TimeStamp 转换
Instant instant = timestamp.toInstant();// 从 LocalDate 转化而来
LocalDate.now().atStartOfDay().toInstant(ZoneOffset.UTC)// 从 LocalDateTime 转化而来
ldt.atZone(ZoneId.systemDefault()).toInstant();// 获取毫秒
long timeStampMillis = instant.toEpochMilli();// 获取秒
long timeStampSeconds = instant.getEpochSecond();

Clock 方便我们去读取当前的日期与时间。Clock 可以根据不同的时区来进行创建,并且可以作为System.currentTimeMillis()的替代。这种指向时间轴的对象即是Instant类。Instants 可以被用于创建java.util.Date对象。

Clock clock = Clock.systemDefaultZone();
long millis = clock.millis();Instant instant = clock.instant();
Date legacyDate = Date.from(instant);   // legacy java.util.Date

Date

// 默认创建
Date date0 = new Date();// 从 TimeStamp 中创建
Date date1 = new Date(time);// 基于 Instant 创建
Date date = Date.from(instant);// 从格式化字符串中获取
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
java.util.Date dt=sdf.parse("2005-2-19");// 从 LocalDateTime 中转化而来
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());

基于 Date 的日期比较常常使用以下方式:

  • 使用 getTime() 方法获取两个日期(自1970年1月1日经历的毫秒数值),然后比较这两个值。
  • 使用方法 before(),after() 和 equals()。例如,一个月的12号比18号早,则 new Date(99, 2, 12).before(new Date (99, 2, 18)) 返回true。
  • 使用 compareTo() 方法,它是由 Comparable 接口定义的,Date 类实现了这个接口。

Calendar

Date 用于记录某一个含日期的、精确到毫秒的时间。重点在代表一刹那的时间本身。 Calendar 用于将某一日期放到历法中的互动——时间和年、月、日、星期、上午、下午、夏令时等这些历法规定互相作用关系和互动。我们可以通过 Calendar 内置的构造器来创建实例:

Calendar.Builder builder =new Calendar.Builder();
Calendar calendar1 = builder.build();
Date date = calendar.getTime();

在 Calendar 中我们则能够获得较为直观的年月日信息:

// 2017,不再是 2017 - 1900 = 117
int year =calendar.get(Calendar.YEAR);int month=calendar.get(Calendar.MONTH)+1;int day =calendar.get(Calendar.DAY_OF_MONTH);int hour =calendar.get(Calendar.HOUR_OF_DAY);int minute =calendar.get(Calendar.MINUTE);int seconds =calendar.get(Calendar.SECOND);

除此之外,Calendar 还提供了一系列 set 方法来允许我们动态设置时间,还可以使用 add 等方法进行日期的加减。

SimpleDateFormat

SimpleDateFormat 用来进行简单的数据格式化转化操作:

Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");

LocalDateTime

LocalDate

// 取当前日期:
LocalDate today = LocalDate.now();// 根据年月日取日期,12月就是12:
LocalDate crischristmas = LocalDate.of(2017, 5, 15); // 根据指定格式字符串取
LocalDate endOfFeb = LocalDate.parse("2017-05-15"); // 严格按照ISO yyyy-MM-dd验证,02写成2都不行,当然也有一个重载方法允许自己定义格式
LocalDate.parse("2014-02-29"); // 无效日期无法通过:DateTimeParseException: Invalid date// 通过自定义时间字符串格式获取
DateTimeFormatter germanFormatter =DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.GERMAN);LocalDate xmas = LocalDate.parse("24.12.2014", germanFormatter);
System.out.println(xmas);   // 2014-12-24// 获取其他时区下日期
LocalDate localDate = LocalDate.now(ZoneId.of("GMT+02:30"));// 从 LocalDateTime 中获取实例
LocalDateTime localDateTime = LocalDateTime.now();
LocalDate localDate = localDateTime.toLocalDate();

日期操作

// 取本月第1天
LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth()); // 2014-12-01// 取本月第2天
LocalDate secondDayOfThisMonth = today.withDayOfMonth(2); // 2014-12-02// 取本月最后一天,再也不用计算是28,29,30还是31
LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth()); // 2014-12-31// 取下一天
LocalDate firstDayOf2015 = lastDayOfThisMonth.plusDays(1); // 变成了2015-01-01// 取2015年1月第一个周一
LocalDate firstMondayOf2015 = LocalDate.parse("2015-01-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)); // 2015-01-05

LocalTime

// 获取其他时区下时间
LocalTime localTime = LocalTime.now(ZoneId.of("GMT+02:30"));// 从 LocalDateTime 中获取实例
LocalDateTime localDateTime = LocalDateTime.now();
LocalTime localTime = localDateTime.toLocalTime();- 12:00
- 12:01:02
- 12:01:02.345

LocalDateTime

// 通过时间戳创建
LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochSecond(1450073569l), TimeZone.getDefault().toZoneId());// 通过 Date 对象创建
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());// 通过解析时间字符串创建
DateTimeFormatter formatter =DateTimeFormatter.ofPattern("MMM dd, yyyy - HH:mm");LocalDateTime parsed = LocalDateTime.parse("Nov 03, 2014 - 07:13", formatter);
String string = formatter.format(parsed);
System.out.println(string);     // Nov 03, 2014 - 07:13

  • 获取年、月、日等信息
LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31, 23, 59, 59);DayOfWeek dayOfWeek = sylvester.getDayOfWeek();
System.out.println(dayOfWeek);      // WEDNESDAYMonth month = sylvester.getMonth();
System.out.println(month);          // DECEMBERlong minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY);
System.out.println(minuteOfDay);    // 1439

  • 时间格式化展示
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.of(1986, Month.APRIL, 8, 12, 30);
String formattedDateTime = dateTime.format(formatter); // "1986-04-08 12:30"

时间操作

localDateTime.plusDays(1);
localDateTime.minusHours(2);

时区转换

Timezones 以 ZoneId 来区分。可以通过静态构造方法很容易的创建,Timezones 定义了 Instants 与 Local Dates 之间的转化关系:

System.out.println(ZoneId.getAvailableZoneIds());
// prints all available timezone idsZoneId zone1 = ZoneId.of("Europe/Berlin");
ZoneId zone2 = ZoneId.of("Brazil/East");
System.out.println(zone1.getRules());
System.out.println(zone2.getRules());// ZoneRules[currentStandardOffset=+01:00]
// ZoneRules[currentStandardOffset=-03:00]
LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());
ZoneId losAngeles = ZoneId.of("America/Los_Angeles");
ZoneId berlin = ZoneId.of("Europe/Berlin");// 2014-02-20 12:00
LocalDateTime dateTime = LocalDateTime.of(2014, 02, 20, 12, 0);// 2014-02-20 12:00, Europe/Berlin (+01:00)
ZonedDateTime berlinDateTime = ZonedDateTime.of(dateTime, berlin);// 2014-02-20 03:00, America/Los_Angeles (-08:00)
ZonedDateTime losAngelesDateTime = berlinDateTime.withZoneSameInstant(losAngeles);int offsetInSeconds = losAngelesDateTime.getOffset().getTotalSeconds(); // -28800// a collection of all available zones
Set<String> allZoneIds = ZoneId.getAvailableZoneIds();// using offsets
LocalDateTime date = LocalDateTime.of(2013, Month.JULY, 20, 3, 30);
ZoneOffset offset = ZoneOffset.of("+05:00");// 2013-07-20 03:30 +05:00
OffsetDateTime plusFive = OffsetDateTime.of(date, offset);// 2013-07-19 20:30 -02:00
OffsetDateTime minusTwo = plusFive.withOffsetSameInstant(ZoneOffset.ofHours(-2));

时差

Period 类以年月日来表示日期差,而 Duration 以秒与毫秒来表示时间差;Duration 适用于处理 Instant 与机器时间。

// periodsLocalDate firstDate = LocalDate.of(2010, 5, 17); // 2010-05-17
LocalDate secondDate = LocalDate.of(2015, 3, 7); // 2015-03-07
Period period = Period.between(firstDate, secondDate);int days = period.getDays(); // 18
int months = period.getMonths(); // 9
int years = period.getYears(); // 4
boolean isNegative = period.isNegative(); // falsePeriod twoMonthsAndFiveDays = Period.ofMonths(2).plusDays(5);
LocalDate sixthOfJanuary = LocalDate.of(2014, 1, 6);// add two months and five days to 2014-01-06, result is 2014-03-11
LocalDate eleventhOfMarch = sixthOfJanuary.plus(twoMonthsAndFiveDays);// durationsInstant firstInstant= Instant.ofEpochSecond( 1294881180 ); // 2011-01-13 01:13
Instant secondInstant = Instant.ofEpochSecond(1294708260); // 2011-01-11 01:11Duration between = Duration.between(firstInstant, secondInstant);// negative because firstInstant is after secondInstant (-172920)
long seconds = between.getSeconds();// get absolute result in minutes (2882)
long absoluteResult = between.abs().toMinutes();// two hours in seconds (7200)
long twoHoursInSeconds = Duration.ofHours(2).getSeconds();

Java 时间与日期处理相关推荐

  1. Java 时间与日期处理 1

    Java 时间与日期处理 从属于笔者的现代 Java 开发系列文章,涉及到的引用资料声明在 Java 学习与实践资料索引中. Java 时间与日期处理 在 Java 8 之前,我们最常见的时间与日期处 ...

  2. JAVA 时间和日期的API

    从JDK8开始,Java.time包提供的新的日期和时间的API. 新的API严格区分了时刻,本地日期,本地时间,而且运算也更加方便. 其次,新API类型几乎全部是不变类型(和String使用类似) ...

  3. Java时间和日期指南

    长期以来,正确处理日期,时间,时区,夏时制,and年等一直是我的烦恼. 本文并不是一个全面的指南时域,请参阅日期和时间在Java中 -更详细,但略有下降,ekhem,日期. 它仍然是相关的,但是没有涵 ...

  4. Java时间和日期的处理

    1.Date类 构造方法 第一个构造函数使用当前日期和时间来初始化对象. Date( ) 第二个构造函数接收一个参数,该参数是从1970年1月1日起的毫秒数. Date(long millisec) ...

  5. Java 时间和日期类型的 Hibernate 映射

    以下情况下必须显式指定 Hibernate 映射类型 一个 Java 类型可能对应多个 Hibernate 映射类型. 例如: 如果持久化类的属性为 java.util.Date 类型, 对应的 Hi ...

  6. Java进阶,时间与日期,包装类,正则表达式

    Java时间与日期,包装类,正则表达式 一.时间与日期 1.Date Date类概述 Date类代表当前所在系统的日期时间信息. Date的构造器 名称 说明 public Date() 创建一个Da ...

  7. java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)...

    转载地址:http://www.devba.com/index.php/archives/4581.html java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明); ...

  8. Java时间日期格式转换

    突然忘记了时间格式怎么转换,特此做个记录 Java时间格式转换大全import java.text.*; import java.util.Calendar; public class VeDate ...

  9. 【Java】7.3 基本类 7.4 Java 8 的日期、时间类

    目录 String.StringBuffer和StringBuilder类 Rondom类 BigDecimal类 Java 8 新增的日期.时间包 String.StringBuffer和Strin ...

最新文章

  1. ORACLE SQL语句总结2
  2. ajax 无返回_AJAX技术学习
  3. Convolutional Neural Networks for Sentence Classification-学习笔记
  4. 完全用 gnu/linux 工作,怎样完全用 GNU/Linux 工作
  5. 一般项目中哪里体现了数据结构_优秀程序员都应该学习的数据结构与算法项目(GitHub 开源清单)...
  6. ansible-playbook 单个yml文件部署tomcat简单示例
  7. mips32和x86下的大小端模式判定
  8. SOAP、WSDL、 UDDI之间的关系
  9. i2c-tools 使用集锦
  10. 国外有哪些免费软件可以实现华为的多屏协同功能
  11. icon图标在线生成教程(svg转icon)
  12. 关于iPad上百度网盘中压缩包下载不能找到的问题
  13. 小程序(原生) 引入weUI组件
  14. icon和文本垂直居中对齐
  15. 解压chm后由hhc生成html索引页面
  16. java左值与右值问题_i++和++i以及左值,右值
  17. 【技术教程】ArcGIS入门教程来袭,零基础的同学快看过来!
  18. php升降调_音乐剪辑 合并 伴奏升降调等等 伴奏升降调软件下载
  19. 井字棋,叫上同桌来一把?
  20. komodo for linux,linux下Komodo安装日志

热门文章

  1. .net core 拼音转换,简繁转换,数字读法,货币读法
  2. 批量修改ppt字体大小及颜色
  3. elasticsearch 配置安全认证X-pack
  4. SpringBoot ( 三 ) 转页
  5. 电大计算机网络本科形成性考核,(2017年电大)中央电大计算机网络本科形成性考核册答案.doc...
  6. 国家项目答辩PPT注意事项
  7. 柔性机器人力控打磨与刚性机器人打磨的主要区别
  8. 关于交大教务网的掌上事务管理中心(服务外包大赛初审)一:概况
  9. 忘记iCloud密码的解决方案 - 仅适用于iOS 7.1以前(不含)
  10. WTI油价预测:病毒复苏及原油库存上升打压油价,原油多头面临双顶技术下行风险