月光宝盒之时间魔法--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 ...
随机推荐
- hmac模块和hashlib模块
hmac模块和hashlib模块 一.hash是什么 hash是一种算法(Python3.版本里使用hashlib模块代替了md5模块和sha模块,主要提供 SHA1.SHA224.SHA256. ...
- Top11 构建和测试API的工具
立刻像专业人士一样构建API 组织正在改变他们已经在软件应用项目中成功的微服务架构模型,这就是大多数微服务项目使用API(应用程序接口)的原因. 我们要为微服务喝彩,因为它相对于其他的模型有各种先进的 ...
- 细数 SharedPreferences 的那些槽点 !
前言 最近在处理一个历史遗留项目的时候饱受其害,主要表现为偶发性的 SharedPreferences 配置文件数据错乱,甚至丢失.经过排查发现是多进程的问题.项目中有两个不同进程,且会频繁的读写 S ...
- SQL语言分类之DDL、DML、DCL、DQL
SQL 语言共分为四大类: 数据控制语言 DCL 数据定义语言 DDL 数据操纵语言 DML 数据查询语言 DQL 一.数据控制语言 DCL 1.1 作用 用来设置或更改数据库用户或角色权限的语句,并 ...
- 使用JDBC驱动程序处理元数据
使用 JDBC 驱动程序处理元数据 一.前言 Java 通过JDBC获得连接以后,得到一个Connection 对象,可以从这个对象获得有关数据库管理系统的各种信息,包括数据库中的各个表,表中的各个列 ...
- 使用css实现水平垂直居中
1.通过absolute和margin实现(适用于弹窗,具体位置随浏览器屏幕大小变化改变)这种方式需要居中元素的父级必须采用绝对定位或相对定位,被居中元素的尺寸需要固定. <div class= ...
- angular8 + redux 管理状态
1. angular8.1.1 ----- package.json { "name": "angular-demo", "version" ...
- postman 接口参数化操作
最近一直忙于AI模型的准确率任务中,这种操作需要大量的数据才能计算出模型的准确率.所以这里问遇到的问题和之前数据随机参数化有点不同,之前的参数比如说用户姓名或用户身份证号,这样数据可以在postman ...
- 你好spring-cloud-kubernetes
关于spring-cloud-kubernetes spring-cloud-kubernetes是springcloud官方推出的开源项目,用于将Spring Cloud和Spring Boot应用 ...
- POJ-2155-Matrix二位树状数组应用
题目: 一个只有0和1构成的二维平面,给你两种指令,一种是区间的更新,即0变为1,1变为0:一种是查询一个点是1还是0: 由于是二进制,所以每次更新在相应的点上加一,最后对2取余即可. 至于二维的树状 ...