`

Java的日期API真烂

阅读更多

记得在我刚学Java的时候,真是搞不清楚Date和Calendar这两个类,后来我渐渐知道,原来不能全怪我啊,Java日期API之烂是公认的(不妨参见这篇文章,Tiago Fernandez做过一个投票,就是要选举最烂的Java API,结果Java日期API排行第二,仅次于臭名远扬的EJB2,嘿嘿)。

蛋疼的java.sql.Date

只有Date和Calendar搞定一切吗?那还好啊。当然不是!光Date就有java.util.Date和java.sql.Date,而且关系是java.sql.Date extends java.util.Date。为了把前者转成后者,我写了这样的代码:

1
2
Date date = new Date();
java.sql.Date d = new java.sql.Date(date.getTime());

居然不支持Date参数的构造器,我只好传入long类型的时间。接下去,我尝试把当前小时数取出来:

1
System.out.println(d.getHours());

悲剧出现了:

1
2
Exception in thread "main" java.lang.IllegalArgumentException
    at java.sql.Date.getHours(Date.java:177)

一看源码,坑爹啊:

1
2
3
public int getHours() {
    throw new java.lang.IllegalArgumentException();
}

在java.util.Date里面好好的方法怎么变成这个鸟样了?

方法注释给出了说明:

This method is deprecated and should not be used because SQL Date values do not have a time component.

也就是说,java.sql.Date是SQL中的单纯的日期类型,哪会有时分秒啊?我觉得它根本不应该设计成java.util.Date的子类。如果你把java.sql.Date通过JDBC插入数据库,你会发现时分秒都丢失了,因此如果你同时需要日期和时间,你应该使用Timestamp,它也是java.util.Date的子类。

另外还有一个java.util.Date的子类叫Time,java.sql包下面的Date、Time和Timestamp可以放在一起记忆。Date只包含年月日信息、Time只包含时分秒信息,而Timestamp则包含时间戳的完整信息。

现在知道人家抛出IllegalArgumentException的用心良苦了吧……

坑爹的year和month

看看Date类的构造器:

1
public Date(int year, int month, int day)

长得并不奇葩嘛。

好,现在我要输出2012年的1月1号了:

1
2
Date date = new Date(2012,1,1);
System.out.println(date);

结果,我傻眼了:

1
Thu Feb 01 00:00:00 CST 3912

等等,这是啥?3192年?

原来实际年份是要在你的年份参数上加上个起始年份1900。

更坑爹的是,月份参数我不是给了1吗?怎么输出二月(Feb)了?

Date里面的月份居然是用0~11表示的,换句话说,一月用0来表示,二月用1来表示。如果不用常量或者枚举,很容易踩到坑里去,对不对?

后来发现Go语言的time.Date方法,对于月份做了个恶心但是不容易坑人的处理(看奇葩的月份参数啊):

1
func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location)

我甚至怀疑Google这样处理是在用极端的方法鄙视Java(另,据我所知,JavaScript好像也是这样的,月份从0开始)……

坑爹的事情还没完,前面已经说了,构造函数的时间起始基准是1900年,可是getTime()方法却特立独行,返回的时间是相对于“1970-01-01 00:00:00”的毫秒数差值……

尝试Joda吧

最开始的时候,Date既要承载日期信息,又要做日期之间的转换,还要做不同日期格式的显示,职责较繁杂,从JDK 1.1 开始,这三项职责分开了:

  1. 使用Calendar类实现日期和时间字段之间转换;
  2. 使用DateFormat类来格式化和分析日期字符串;
  3. 而Date只用来承载日期和时间信息。

原有Date中的相应方法已废弃。不过,无论是Date,还是Calendar,都用着太不方便了,这是API没有设计好的地方。

比如Calendar的getInstance方法,并未提供一个指定年月日和时分秒的重载方法,每次要指定特定的日期时间,必须先获取一个表示当前时间的Calendar实例,再去设值,比如:

1
2
3
Calendar c = Calendar.getInstance();
c.set(2012, 0, 1, 11, 11, 11);
System.out.println(c.getTime());

注意上面代码中对于年份的传值——是的,和Date不一样的是,Calendar年份的传值不需要减去1900(当然月份的定义和Date还是一样),这种不一致真是让人抓狂!

打印:

1
Sun Jan 01 11:11:11 CST 2012

有很多开源库都在努力弥补Java的这一问题,比如Joda-Time,获取Calendar对象和设置时间完全可以合成一步完成:

1
DateTime dateTime = new DateTime(2012, 1, 1, 11, 11, 11, 0);

而且,一月份总是可以传1来表示了。

再如,如果要给上述时间增加3天再按格式输出的话,使用Joda更加便捷:

1
System.out.println(dateTime.plusDays(3).toString("E MM/dd/yyyy HH:mm:ss");

有兴趣的话请阅读此文,并下载Joda-Time使用。

JSR-310

众所周知Java的规范就是多、而且啰嗦,这帮老大们(Export Group中除了有Oracle的人,还有IBM、Google和RedHat的人)终于再也无法忍受Java那么烂的日期API了,于是就有了JSR-310(感兴趣的请移步),官方的描述叫做“This JSR will provide a new and improved date and time API for Java.”,目前的阶段还在“Early Draft Review 2”,有得等。

JSR-310将解决许多现有Java日期API的设计问题。比如Date和Calendar目前是可变对象,你可以随意改变对象的日期或者时间,而Joda就将DateTime对象设计成String对象一样地不可变,能够带来线程安全等等的好处,因此这一点也将被JSR-310采纳。

很多JSR规范都是在程序员的诋毁和谩骂声中萌芽的,然后会有开源项目来尝试解决Java的这些弊端,最后就轮到JSR就去抄他们的实现。除了新的日期API,再比如JCache(JSR-107),你知道它抄了多少EhCache的东西么……

 

转自:http://www.raychase.net/1098

分享到:
评论

相关推荐

    java api java api java api java api

    java apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava apijava api...

    JAVA_API1.6文档(中文)

    本文档是 Java 2 Platform Standard Edition 6.0 的 API 规范。 请参见: 描述 Java 2 Platform 软件包 java.applet 提供创建 applet 所必需的类和 applet 用来与其 applet 上下文通信的类。 java.awt 包含...

    JAVA-API-1.8.zip

    JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-API-1.8`JAVA-...

    Java API文档.docx

    Java API文档是Java编程语言的一部分,它是一组文档,提供了Java编程语言的标准类、接口、方法和属性的说明和示例。Java API文档通常包含在Java开发工具包(JDK)中,并可以通过Java编译器和Java虚拟机(JVM)使用。 ...

    java json api,json api

    java json api,json api

    JavaAPI文档中文版

    JavaAPI文档中文版,JavaAPI文档中文版,JavaAPI文档中文版,JavaAPI文档中文版,JavaAPI文档中文版,JavaAPI文档中文版,JavaAPI文档中文版,JavaAPI文档中文版,JavaAPI文档中文版,JavaAPI文档中文版,JavaAPI...

    Java8 API 文档.CHM

    Java8 API

    JAVA api 汉化版

    JAVA api JAVA api 汉化版JAVA api JAVA api 汉化版JAVA api JAVA api 汉化版JAVA api JAVA api 汉化版JAVA api JAVA api 汉化版JAVA api JAVA api 汉化版JAVA api JAVA api 汉化版

    JAVA8API-官方文档下载-中文版

    javaAPI 官方文档 中文版 良心!

    openCV java的API文档

    open CV2.9.4版本的java ApI

    java6 api中文文档

    java6 api中文文档java6 api中文文档java6 api中文文档java6 api中文文档java6 api中文文档java6 api中文文档java6 api中文文档

    Java8API文档(官方离线版)

    Java8API文档(官方离线版),下载即可使用浏览器离线打开!

    java1.8-api

    java1.8-api,帮助文档,javase

    java1.7 api 文档 中文版

    java1.7 api 文档 中文版

    中文JAVA API 文档

    中文JAVA API。

    Java——API6

    Java——API6

    JAVA_API_1.7中文

    JAVA_API_1.7中文JAVA_API_1.7中文JAVA_API_1.7中文JAVA_API_1.7中文JAVA_API_1.7中文JAVA_API_1.7中文JAVA_API_1.7中文JAVA_API_1.7中文JAVA_API_1.7中文JAVA_API_1.7中文JAVA_API_1.7中文JAVA_API_1.7中文JAVA_API...

    java_api大全

    txt文件内含百度网盘连接和密码,里面包含学习java的各种api手册。例如:javaEE.chm,CSS.chm,javascript.chm,DOM.chm,jquery.chm等等。文档太多就不一一列举了。很有帮助!!

    Java api Java api

    Java apiJava apiJava apiJava apiJava apiJava apiJava apiJava apiJava apiJava api

    JAVAapi-JAVA中文API

    JAVAapi-JAVA中文API,JAVAapi-JAVA中文API,JAVAapi-JAVA中文API。

Global site tag (gtag.js) - Google Analytics