Java 日期时间处理

Date

java.util.Date对象表示一个精确到毫秒的瞬间; 但由于Date从JDK1.0起就开始存在了,历史悠久,而且功能强大(既包含日期,也包含时间),所以他的大部分构造器/方法都已Deprecated,因此就不再推荐使用(如果贸然使用的话,可能会出现性能/安全方面的问题);下面我仅介绍它还剩下的为数不多的几个方法(这些方法的共同点是Date与毫秒值的转换):

  • 构造器
  • Date(): 在底层调用System.currentTimeMillis()作为日期参数.
  • Date(long date): 根据指定的long整数(从1970-1-1 00:00:00以来经过的毫秒数)来生成Date对象.
  • 方法
  • boolean after(Date when): 测试this日期是否在指定日期when之后;
  • boolean before(Date when): 测试this日期是否在指定日期when之前;
  • long getTime(): 获取从1979-01-01 00:00:00 到Date对象之间经过的毫秒值;
  • void setTime(long time): 设置时间,time含义上同.

Calendar

由于Date存在缺陷,所以JDK又提供了java.util.Calendar来处理日期和时间.Calendar是一个抽象类,是所有日历类的模板,因此,我们可以继承Calendar来实现其他的历法(比如阴历);

Java中提供了一种Calendar的默认实现java.util.GregorianCalendar格里高利日历(其实JDK还默认提供了一款日本历法java.util.JapaneseImperialCalendar),也就是我们所说的公历. 使用Calendar.getInstance();获取的就是默认的GregorianCalendar,getInstance()方法的内部会调用cal = new GregorianCalendar(zone, aLocale);来生成一个格里高利日历实例.

  • Calendar还可以和Date自由转换.

Calendar类提供了大量访问/修改日期/时间的方法, 常用的方法如下:

注意:上面的很多方法都需要一个int类型的field参数, field是Calendar类的类变量, 如:Calendar.DATE Calendar.MONTH Calendar.HOUR Calendar.DAY_OF_WEEK, 但需要指出的是Calendar.MONTH月份的起始值不是1, 而是0(一月:0, 二月:1 …), Calendar.DAY_OF_WEEK代表的星期, 起始值是周日(周日:1, 周一:2 …)(其他细节请参考JDK文档).

  • 如果Calendar没有设置相关的值, 就以当前系统时间来设置.
  • add(int field, int amount)的功能非常强大, 如果需要增加某字段, 则让amount为正数, 如果要减少某字段的值, 让amount为负数. 且当超出他的允许范围时, 会发生进位.
  • roll()的含义与用法和add()的类似,但是当被修改的字段超出它允许的范围时, 他不会进位.
  • set(int field, int value)方法具有延迟修改的功能:他内部设置了一个成员变量,以指示日历字段field已经被修改,但是该Calendar所代表的时间不会立即修改, 他会直到下次调用get/getTime/getTimeInMillis/add/roll时才会重新计算日历时间.

日期格式化

完成字符串与日期对象的转化(format/parse)

DateFormat

java.text.DateFormat是一个抽象类, 他提供了如下几个方法获取DateFormat对象.

其实上面三个方法还可以指定日期/时间的样式, 如FULL/LONG/MEDIUM/SHOT, 通过这四个样式参数可以控制生成的格式化字符串. 但由于在我们的实际开发中很少直接用DateFormat类,因此就不对其做过多的介绍.而我们比较常用的是其子类SimpleDateFormat(其实上面几个getXxxInstance方法返回的也是SimpleDateFormat实例)

SimpleDateFormat

java.text.SimpleDateFormat可以非常灵活的格式化Date, 也可以用于解析各种格式的日期字符串.创建SimpleDateFormat对象时需要传入一个pattern字符串,这个pattern不是正则表达式,而是一个日期模板字符串.

在时间日期格式化时, 有下面几个方法是最常用的:

当然, pattern我们还可以根据我们的需求有其他的定制形式:

可以看出SimpleDateFormat把日期格式化成怎样的字符串以及能把怎样的字符串解析成Date, 完全取决于创建对象时指定的pattern参数,其他的pattern参数以及SimpleDateFormat的方法可以参考JDK文档.

数据库存储时间实战

由于时间存储会涉及到跨时区的问题(同一个UTC时间在各个时区显示的是不同的数值).因此,在我们向数据库中插入时间是需要小心谨慎,不能简单单单的使用数据库提供的TIMESTAMP或是DATETIME 类型,比较推荐的是选用一个整数类型(如BIGINT64位与Java的Long类型相同),来存储从`1970-01-01 00:00:00到时间点所经过的毫秒数(具体原因详见:如何正确地处理时间).

  • 这样做的优点是:读取时间时(一个Long类型整数),只需要按照用户的时区格式化为字符串就能正确地显示出来.
  • 当然这样做也存在缺陷,那就是当我们开发人员/DB直接查看数据库时,看到的只是一串数字,并不能清楚的知晓其对应的时间日期.

上面讲完了数据库该如何存储时间值,下面我们再聊一聊时间[存入/读出]数据库的转化问题:

  • 从Date转换成Long 很简单:

从Long转换成一个时间的String我们需要SimpleDateFormat的一个方法:

配置单例Formatter

由于在一个项目中时间格式化和解析的格式一般只有一种(我们应该不希望格式化之后的time到最后反而解析不出来),因此我们没有必要每次使用时都new出一个Formatter来,这样不光会造成性能下降还有可能造成时间形式不统一而出错.因此,我们可以在Sring的容器中装载一个Formatter Bean,使用时@Autowired就可以了:

原文发布于微信公众号 - java一日一条(mjx_java)

原文发表时间:2016-03-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏计算机视觉与深度学习基础

Leetcode 91 Decode Ways

A message containing letters from A-Z is being encoded to numbers using the fol...

22470
来自专栏个人随笔

论 ArrayList如何实现线程安全

一:使用synchronized关键字 二:使用Collections.synchronizedList();         假如你创建的代码如下:List<...

359140
来自专栏程序生活

Leetcode-Easy 101. Symmetric Tree

101. Symmetric Tree 描述: 判断一个颗二叉树是否左右对称 ? 思路: 将二叉树的左右节点对放在的队列里,然后出队,判断节...

35270
来自专栏Janti

springboot之使用redistemplate优雅地操作redis

3.1K30
来自专栏ACM小冰成长之路

HDU-1512-Monkey King

ACM模版 描述 ? 题解 典型的左偏树! 问题的核心是当两个猴子帮派中的大佬斗争之后,这两个大佬要强壮值减半并且两个帮派进行合并。那么涉及到的操作有优先队列的...

20760
来自专栏吾爱乐享

java之学习calendar类的综合案例分析及代码

14460
来自专栏小白鼠

Java面试题事务隔离级别JVM调优equals和hashCodesynchronized与LockMapSetListThreadLocal死锁多线程最佳实践扩容缓存消息队列应用拆分高可用

如果只重写了equals方法而没有重写hashCode方法的话,则会违反约定的第二条:相等的对象必须具有相等的散列码(hashCode)

19920
来自专栏社区的朋友们

理解 B+ 树算法

最近有接触到 b+ 树,花了点时间,顺便总结梳理下方便后续翻阅;时间仓促,且文中多是个人的理解,仅供参考。

1.1K00
来自专栏计算机视觉与深度学习基础

Leetcode 171 Excel Sheet Column Number

Related to question Excel Sheet Column Title Given a column title as appear in...

212100
来自专栏来自地球男人的部落格

[LeetCode] 134. Gas Station

【原题】 There are N gas stations along a circular route, where the amount of gas...

20780

扫码关注云+社区

领取腾讯云代金券