月光宝盒之时间魔法--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 ...
随机推荐
- SpringBoot 配置 AOP 打印日志
在项目开发中,日志系统是必不可少的,用AOP在Web的请求做入参和出参的参数打印,同时对异常进行日志打印,避免重复的手写日志,完整案例见文末源码. 一.Spring AOP AOP(Aspect-Or ...
- thinkPHP中的文章详情页实现“上一篇下一篇”功能经验分享
前段时间在公司中接触到了用thinkPHP搭建的项目,其中涉及到了文章详情页上一篇下一篇翻页的功能实现效果. 因为刚接触这套框架和PHP,所以整理一下实现该功能的经验方法. 如果有不到位的地方,欢迎指 ...
- 理解Java反射机制
理解Java反射机制 转载请注明出处,谢谢! 一.Java反射简介 什么是反射? Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在.灵活掌握Java反射机制,对学习框架技术有很大 ...
- String类的intern()方法,随常量池发生的变化
JVM的知识这里总结的很详细:https://github.com/doocs/jvm/blob/master/README.md,因此在本博客也不会再对其中的东西重复总结了. intern的作用 简 ...
- Java开发必备技能
--------转载自B站up主 codeSheep 基础知识 编程语言:Java Python C 基本算法 基本网络知识:TCP/IP HTTP/HTTPS 基本的设计模式 工具方面 操作系统: ...
- 关于Socket、TCP/IP、HTTP、FTP及网络编程
来源:陶邦仁 链接:http://blog.jobbole.com/99694/ 既然是网络传输,涉及几个系统之间的交互,那么首先要考虑的是如何准确的定位到网络上的一台或几台主机,再者如何进行可靠高效 ...
- POJ-2230-Watchcow-欧拉回路的路径输出+结构体
Watchcow 这道题的题意好理解,就是要从1出发,每条边都走两遍,最后再回到1: 但是,我一开始没有想到和欧拉回路有什么关系: 学了求欧拉的dfs()后,试了一下发现和样例差不多: 感觉求回路,什 ...
- 牛客-长沙理工校赛C-取手机
传送门:https://www.nowcoder.com/acm/contest/96/C 参考:http://www.cnblogs.com/Dillonh/p/8835074.html 题意: d ...
- Codeforces 919D Substring (拓扑排序+树形dp)
题目:Substring 题意:给你一个有向图, 一共有n个节点 , m条变, 一条路上的价值为这个路上出现过的某个字符最多出现次数, 现求这个最大价值, 如果价值可以无限大就输出-1. 题解:当这个 ...
- 用C#实现的几种常用数据校验方法整理(CRC校验;LRC校验;BCC校验;累加和校验)
CRC即循环冗余校验码(Cyclic Redundancy Check):是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定.循环冗余检查(CRC)是一种数据传输检错 ...