月光宝盒之时间魔法--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 ...
随机推荐
- 更新!ArcMap和ArcGIS Pro加载百度影像地图
上一篇文章写了ArcMap和ArcGIS Pro中加载百度地图 的方法 一次没有把百度影像加载的功能开发出来,趁这几天有空整理了下 加载方法按照上次那篇文章操作. 百度影像wmts加载地址:http: ...
- 13张PPT带你了解主动式消息队列处理集群
前言 偷偷和你们说,我搞了一份内部资料,该内部资料共有13张PPT,据作者透露,该PPT至少花了整整1周时间才编写完成,其内容简洁明了,内容深度足够,易于初学者理解,也给深度开发人员分享了不一样的消息 ...
- Spring学习之旅(二)--容器
在 Spring 应用中,所有的对象都在 Spring 容器(container) 里,容器负责对象的创建.配置.装配并管理它们的整个生命周期. Spring 容器 Spring 容器 并不是只有一个 ...
- Codeforces 396D
题意略. 思路: 很经典的逆序对计数问题. https://blog.csdn.net/v5zsq/article/details/79006684 这篇博客讲得很好. 当循环到n的时候,我们需要特殊 ...
- Java多线程之线程协作
Java多线程之线程协作 一.前言 上一节提到,如果有一个线程正在运行synchronized 方法,那么其他线程就无法再运行这个方法了.这就是简单的互斥处理. 假如我们现在想执行更加精确的控制,而不 ...
- HTML(五)列表,区块,布局,表单和输入
HTML 列表 无序列表 Coffee Tea Milk 默认是圆点,也可以 圆圈 正方形 有序列表 Coffee Tea Milk Coffee Tea Milk 默认是用数字排序 大写字母 小写字 ...
- HDU-5977 - Garden of Eden 点分治
HDU - 5977 题意: 给定一颗树,问树上有多少节点对,节点对间包括了所有K种苹果. 思路: 点分治,对于每个节点记录从根节点到这个节点包含的所有情况,类似状压,因为K<=10.然后处理每 ...
- CodeForces 765 F Souvenirs 线段树
Souvenirs 题意:给你n个数, m次询问, 对于每次一次询问, 求出询问区间内绝对值差值的最小值. 题解:先按查询的右端点从小到大sort一下,然后对于塞入一个数的时候, 就处理出所有左端点到 ...
- MongoDb 快速翻页方法
翻阅数据是MongoDB最常见的操作之一.一个典型的场景是需要在你的用户界面中显示你的结果.如果你是批量处理的数据,同样重要的是要让你的分页策略正确,以便你的数据处理可以规模化. 接下来,让我们通过一 ...
- 3. Sentinel源码分析— QPS流量控制是如何实现的?
Sentinel源码解析系列: 1.Sentinel源码分析-FlowRuleManager加载规则做了什么? 2. Sentinel源码分析-Sentinel是如何进行流量统计的? 上回我们用基于并 ...