月光宝盒之时间魔法--java时间的前生今世
月光宝盒花絮
“曾经有一份真诚的爱情摆在我的面前,但是我没有珍惜,等到了失去的时候才后悔莫及,尘世间最痛苦的事莫过于此。如果可以给我一个机会再来一次的话,我会跟那个女孩子说我爱她,如果非要把这份爱加上一个期限,我希望是一万年!”---大话西游之仙履奇缘
《大话西游之大圣娶亲》(又名《大话西游之仙履奇缘》)是周星驰彩星电影公司1994年制作和出品的一部经典的无厘头搞笑爱情片,改编依据是吴承恩所撰写的神怪小说《西游记》,该片是《大话西游》系列的第二部,由刘镇伟导演,技安编剧,周星驰制作,周星驰、朱茵、莫文蔚、蔡少芬、陆树铭、吴孟达等人主演。
该片主要讲述了至尊宝为了救白晶晶而穿越回到五百年前,遇见紫霞仙子之后发生一段感情并最终成长为孙悟空的故事。该片于1995年2月4日在香港首映并入围第十五届香港电影金像奖最佳编剧奖和最佳男主角奖,周星驰凭借该片获得第一届香港电影金紫荆奖最佳男主角奖和第二届香港电影评论学会奖最佳男主角奖。
java中关于时间的设计经历了Date,Calendar,到最后引用第三方包joda time,都发生了什么?让我们看看吧
java时间前生之Date
在Java平台首次发布时,它唯一支持日历计算类的就是Date 类。这个类在能力方面是受限的,特别是当需要支持国际化时,它就暴露出了一个基本的设计缺陷:Date实例是易变的。Date会产生什么问题呢?请看一下下面程序的输出:
public static void main(String[] args) {
Date date=new Date(2018,12,31,0,0,0);
System.out.println(date.getYear());
System.out.println(date.getMonth());
System.out.println(date.getDay());
}
我们想打印出的结果是
2018
12
31
可是,运行后的结果打印
2019
0
5
穿越了吗?还是我的机器有问题?
换了别的机器依然如此。代码是不会骗人的,只好进源码看看
/**
* Allocates a <code>Date</code> object and initializes it so that
* it represents the instant at the start of the minute specified by
* the <code>year</code>, <code>month</code>, <code>date</code>,
* <code>hrs</code>, and <code>min</code> arguments, in the local
* time zone.
*
* @param year the year minus 1900.
* @param month the month between 0-11.
* @param date the day of the month between 1-31.
* @param hrs the hours between 0-23.
* @param min the minutes between 0-59.
* @see java.util.Calendar
* @deprecated As of JDK version 1.1,
* replaced by <code>Calendar.set(year + 1900, month, date,
* hrs, min)</code> or <code>GregorianCalendar(year + 1900,
* month, date, hrs, min)</code>.
*/
@Deprecated
public Date(int year, int month, int date, int hrs, int min) {
this(year, month, date, hrs, min, 0);
}
程序大揭秘
- 设置年份是从1900开始的,即2018-1900=118
- 设置月份是从0开始的,即0~11,12等于下一年119年的第一个月即值为0
- day返回的是是周几
/**
* Returns the day of the week represented by this date. The
* returned value (<tt>0</tt> = Sunday, <tt>1</tt> = Monday,
* <tt>2</tt> = Tuesday, <tt>3</tt> = Wednesday, <tt>4</tt> =
* Thursday, <tt>5</tt> = Friday, <tt>6</tt> = Saturday)
* represents the day of the week that contains or begins with
* the instant in time represented by this <tt>Date</tt> object,
* as interpreted in the local time zone.
*
* @return the day of the week represented by this date.
* @see java.util.Calendar
* @deprecated As of JDK version 1.1,
* replaced by <code>Calendar.get(Calendar.DAY_OF_WEEK)</code>.
*/
@Deprecated
public int getDay() {
return normalize().getDayOfWeek() - BaseCalendar.SUNDAY;
}
java时间前生之Calenar
在1.1 版中,Calendar 类被添加到了Java 平台中,以矫正Date的缺点,由此大部分的Date 方法就都被弃用了。遗憾的是,这么做只能使情况更糟。我们的程序说明Date 和Calendar API 有许多问题。
public static void main(String[ ] args) {
Calendar cal = Calendar.getInstance();
cal.set(2018, 12, 31); // Year, Month, Day
System.out.print(cal.get(Calendar.YEAR) + " ");
Date d = cal.getTime();
System.out.println(d.getDay());
}
来干活吧,运行输出结果:
2019 4
代码是不会骗人的,进源码看看吧
/**
* Sets the values for the calendar fields <code>YEAR</code>,
* <code>MONTH</code>, and <code>DAY_OF_MONTH</code>.
* Previous values of other calendar fields are retained. If this is not desired,
* call {@link #clear()} first.
*
* @param year the value used to set the <code>YEAR</code> calendar field.
* @param month the value used to set the <code>MONTH</code> calendar field.
* Month value is 0-based. e.g., 0 for January.
* @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
* @see #set(int,int)
* @see #set(int,int,int,int,int)
* @see #set(int,int,int,int,int,int)
*/
public final void set(int year, int month, int date)
{
set(YEAR, year);
set(MONTH, month);
set(DATE, date);
}
从上面的理解中,月份是从0开始的即0~11 代表 1月。。。。。12月
接着date又是从1开始的,为什么同一个方法设计的如此怪异?
程序揭秘
1.标准的(西历)日历只有12 个月,该方法调用肯定应该抛出一IllegalArgumentException 异常,对吗?它是应该这么做,但是它并没有这么做。Calendar 类直接将其替换为下一年,即:2019
有两种方法可以订正这个问题。你可以将cal.set 调用的第二个参数由12 改为11,但是这么做容易引起混淆,因为数字11 会让读者误以为是11 月。更好的方式是使用Calendar 专为此目的而定义的常量,即Calendar.DECEMBER
2. Date.getDay 返回的是Date实例所表示的星期日期,而不是月份日期。这个返回值是基于0 的,从星期天开始计算,即:4
有两种方法可以订正这个问题。你可以调用Date.date 这一名字极易让人混淆的方法,它返回的是月份日期。然而,与大多数Date 方法一样,它已经被弃用了,
因此你最好是将Date 彻底抛弃,直接调用Calendar 的get(Calendar.DAY_OF_MONTH)方法。
上例只是掀开了Calendar 和Date 缺陷的冰山一角。这些API 简直就是雷区。Calendar 其他的严重问题包括弱类型(几乎每样事物都是一个int)、过于复杂的状态空间、拙劣的结构、不一致的命名以及不一致的雨衣等。在使用Calendar和Date 的时候一定要当心,千万要记着查阅API 文档。
对API 设计者来说,其教训是:如果你不能在第一次设计时就使它正确,那么至少应该在第二次设计时应该使它正确,绝对不能留到第三次设计时去处理。如果你对某个API 的首次尝试出现了严重问题,那么你的客户可能会原谅你,并且会再给你一次机会。如果你第二次尝试又有问题,你可能会永远坚持这些错误了。
java时间后世之Joda Time
JDK在8之前的版本,对日期时间的处理相当麻烦,有些方法设计非常反人类。而Joda-Time使用起来不仅方便,而且可读性强。虽然JDK 8引用了新的时间处理类,而且参与设计的人也正是Joda-Time的作者,但是由于各种原因,很多项目还是使用的JDK7,使用Joda-Time还是一个不错的选择。
Joda-Time提供了一组Java类包用于处理包括ISO8601标准在内的date和time。可以利用它把JDK Date和Calendar类完全替换掉,而且仍然能够提供很好的集成。
Joda-Time主要的特点包括:
1. 易于使用:Calendar让获取"正常的"的日期变得很困难,使它没办法提供简单的方法,而Joda-Time能够 直接进行访问域并且索引值1就是代表January。
2. 易于扩展:JDK支持多日历系统是通过Calendar的子类来实现,这样就显示的非常笨重而且事实 上要实现其它日历系统是很困难的。Joda-Time支持多日历系统是通过基于Chronology类的插件体系来实现。
3. 提供一组完整的功能:它打算提供 所有关系到date-time计算的功能.Joda-Time当前支持8种日历系统,而且在将来还会继续添加,有着比JDK Calendar更好的整体性能等等。
joda time示例
//jdk
Calendar calendar=Calendar.getInstance();
calendar.set(2012, Calendar.NOVEMBER, 15, 18, 23,55); //Joda-time
DateTime dateTime=new DateTime(2012, 12, 15, 18, 23,55);
更详细的参考:https://www.joda.org/joda-time/
参考资料:
【1】https://www.iteye.com/blog/persevere-1755237
【2】java解惑
月光宝盒之时间魔法--java时间的前生今世的更多相关文章
- Java NIO 的前生今世 之四 NIO Selector 详解
Selector Selector 允许一个单一的线程来操作多个 Channel. 如果我们的应用程序中使用了多个 Channel, 那么使用 Selector 很方便的实现这样的目的, 但是因为在一 ...
- Netty 源码分析之 番外篇 Java NIO 的前生今世
简介 Java NIO 是由 Java 1.4 引进的异步 IO. Java NIO 由以下几个核心部分组成: Channel Buffer Selector NIO 和 IO 的对比 IO 和 NI ...
- 揭秘 BPF map 前生今世
揭秘 BPF map 前生今世 本文地址:https://www.ebpf.top/post/map_internal 1. 前言 众所周知,map 可用于内核 BPF 程序和用户应用程序之间实现双向 ...
- 数据库时间和 java 时间不一致解决方案
java添加 date 到数据库,时间不一致 使用 date 添加到数据库,数据库显示的时候和date时间相差 8 个小时,这是由于 mysql 上的时区的问题,这里有两个解决方案: 方案一: 设置数 ...
- Java的前生今世
Java作为一门编程语言,自诞生以来已经流行了20多年,在学习它之前,我们有必要先了解一下它的历史,了解它是如何一步步发展到今天这个样子. 孕育 上世纪90年代,硬件领域出现了单片式计算机系统,比如电 ...
- RPC 原理的前生今世
(如果感觉有帮助,请帮忙点推荐,添加关注,谢谢!你的支持是我不断更新文章的动力.本博客会逐步推出一系列的关于大型网站架构.分布式应用.设计模式.架构模式等方面的系列文章) 在校期间大家都写过不少程序, ...
- 线程中sleep()方法和wait()方法的前生今世
先看再点赞,给自己一点思考的时间,如果对自己有帮助,微信搜索[程序职场]关注这个执着的职场程序员.我有什么:职场规划指导,技能提升方法,讲不完的职场故事,个人成长经验. 不知道大家有没有这种感觉,在公 ...
- 我的Android前生今世之缘-学习经验-安卓入门教程(六)
关注我,每天都有优质技术文章推送,工作,学习累了的时候放松一下自己. 本篇文章同步微信公众号 欢迎大家关注我的微信公众号:「醉翁猫咪」 据我所知,网上教学资料一堆一堆的,那么还有很多人说,如何学习? ...
- RCNN,Fast RCNN,Faster RCNN 的前生今世:(4) Fast RCNN 算法详解
继2014年的RCNN之后,Ross Girshick在15年推出Fast RCNN,构思精巧,流程更为紧凑,大幅提升了目标检测的速度.在Github上提供了源码. 同样使用最大规模的网络,Fast ...
随机推荐
- tab栏切换制作
tab栏切换制作 先上图 要求1:默认状态,第一个选项卡被选中,展示第一个选项卡的内容 策略:第一个选项卡默认有被选中的样式,第一个选项卡对应的display: block,其他的dispaly设为n ...
- js如何使用radio
<input name="sex" type="radio" value="男" checked="checked" ...
- 2019年 iPad无法充电
2019年 iPad无法充电 到售后网点检测没毛病,可能是apple产品做了低温保护逻辑机制低温无法充电,或者说是冬天温度跟iPad电池充电温度要求不符.各位有遇到情况的可以看看是不是这种问题,这问 ...
- 随笔编号-01 如何比较日期类型的String 大小浅谈.
有三种解决方法: 第一种直接用字符串类的compareTo方法: String t1="20160707"; String t2="20160708"; int ...
- 实战docker,编写Dockerfile定制tomcat镜像,实现web应用在线部署
最初在tomcat上部署web应用的方式,是通过maven的maven-compiler-plugin插件先打成war包,再将war包复制到tomcat的webapps目录下,后来用上了tomcat7 ...
- CopyOnWriteArrayList笔记
CopyOnWriteArrayList笔记 一.前言 Java 5.0 在java.util.concurrent 包中提供了多种并发容器类来改进同步容器的性能. ConcurrentHashMap ...
- 8、kubernetes之存储卷资源
一.存储卷的类型 emptyDir:在宿主机上分一块内存空间给pod当做存储空间 hostPath:在宿主机上分一块磁盘空间给pod当做存储空间 网络存储: SAN:iSCSI,FC NAS:nfs, ...
- MSIL实用指南-加载和保存参数
本篇讲解怎么加载和保存参数,以及参数起始序号的确定. 参数的加载加载参数的指令是Ldarg.Ldarg_S.Ldarg_0.Ldarg_1.Ldarg_2.Ldarg_3.Ldarg_0是加载第0个参 ...
- [转]Android ImageView的scaleType属性与adjustViewBounds属性
Android ImageView的scaleType属性与adjustViewBounds属性 ImageView的scaleType的属性有好几种,分别是matrix(默认).center.c ...
- 渗透之路基础 -- SQL进阶(盲注和报错注入)
SQL注入之盲注 实战过程中,大多情况下很少会有回显,这个时候就要去使用盲注技术 盲注,Blind SQL Injection,听这名字就感觉整个过程就是一个盲目的过程 当注入时,没有任何提示的时候, ...