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含义上同.

    0?wx_fmt=png

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自由转换.

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

0?wx_fmt=png

0?wx_fmt=png

注意:上面的很多方法都需要一个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时才会重新计算日历时间.

  • 0?wx_fmt=png

  • 0?wx_fmt=png

日期格式化

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

DateFormat

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

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

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

0?wx_fmt=png

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

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

0?wx_fmt=png

数据库存储时间实战

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

  • 这样做的优点是:读取时间时(一个Long类型整数),只需要按照用户的时区格式化为字符串就能正确地显示出来.

  • 当然这样做也存在缺陷,那就是当我们开发人员/DB直接查看数据库时,看到的只是一串数字,并不能清楚的知晓其对应的时间日期.

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

  • 从Date转换成Long 很简单:

    0?wx_fmt=png从Long转换成一个时间的String我们需要SimpleDateFormat的一个方法:


    0?wx_fmt=png
配置单例Formatter

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

0?wx_fmt=png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值