`

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只包含时分秒信息,而Times则包含时间戳的完整信息。

现在知道人家抛出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开始)……

尝试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

注:本博客已经迁移到个人站点 http://www.raychase.net/ ,欢迎大家访问收藏,本ITEye博客在数日后将不再更新。

1
1
分享到:
评论
1 楼 zui4yi1 2012-12-11  
同感,呵呵

相关推荐

    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 包含...

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

    5. **日期和时间API**: Java 8引入了`java.time`包,提供`LocalDate`、`LocalTime`、`LocalDateTime`等类,替代了原有的`java.util.Date`和`Calendar`,使日期和时间的操作更加直观。 **模块系统(Project Jigsaw)...

    java8 API 中文版

    Java 8 API是Java开发的重要参考资料,它包含了Java 8版本的所有类库、接口和方法的详细说明。这个中文版的API文档对于中国开发者来说,无疑提供了极大的便利,因为中文语言的理解更为直观,有助于提高开发效率。...

    java8 API 文档

    Java 8 API 文档是Java开发人员的重要参考资料,它详细阐述了Java 8及更高版本中的各种类库、接口和方法。这个文档包含了Java SE(标准版)8的所有公共API,是理解和使用新特性的关键工具。让我们深入探讨Java 8 API...

    Java1.8API中文手册

    Java 8中引入了新的日期时间API,包括java.time包下的LocalDate、LocalTime、LocalDateTime和ZonedDateTime等类,替代了原有的Calendar和Date。这些新类提供了更强大、更直观的时间日期处理能力。 六、方法引用和...

    Java卡API_V2.2.1

    Java卡API_V2.2.1 Java卡API_V2.2.1是Java卡应用程序接口(API)的规范,提供了Java卡平台API的中文译本。下面是Java卡API_V2.2.1的详细知识点: 1. 概述 Java卡API_V2.2.1是Java卡平台的应用程序接口规范,提供...

    Java8API文档(官方离线版)

    Java 8还对日期和时间API进行了重写,引入了`java.time`包。旧的`java.util.Date`和`java.util.Calendar`被更直观、更易用的`LocalDate`、`LocalTime`、`LocalDateTime`等类取代。这些新类提供了更丰富的操作和格式...

    JavaAPI文档中文版

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

    JAVA常用API文档 中文完整版.zip

    8. **日期时间**:Java 8引入了新的日期和时间API(java.time包),包括LocalDate、LocalTime、LocalDateTime等类,提供了更直观和强大的日期时间处理功能。 9. **国际化与本地化**:java.util.Locale和...

    Java8 API 文档.CHM

    5. **日期和时间API**:Java 8用`java.time`包取代了过时的`java.util.Date`和`Calendar`,提供了更直观和易用的日期、时间和时区处理。`LocalDate`, `LocalTime`, `LocalDateTime`, `ZonedDateTime`等类提供了丰富...

    java8中文文档API

    Java 8对日期和时间API进行了彻底的改革,引入了`java.time`包,包含`LocalDate`, `LocalTime`, `LocalDateTime`等类,以及`ZonedDateTime`和`Duration`等,提供了更直观和强大的日期时间处理功能。 **8. Nashorn ...

    Java API文档 中文网页版

    Java API文档是Java开发者的重要参考资料,它包含了Java开发工具包(JDK)中的所有类、接口、方法和常量的详细说明。这份中文网页版的Java API文档为中国的开发者提供了便利,无需通过英文版本来学习和查找API信息,...

    Java-api-mac

    Java API for Mac,简称为Java-API-Mac,是专门为苹果Mac操作系统设计的一套Java开发接口。这个API使得Java开发者能够充分利用Mac平台特有的功能和特性,如Aqua界面、Carbon库集成以及Core Foundation框架等,从而...

    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中文文档

    java json api,json api

    Java JSON API是Java平台上的库,提供了处理JSON的能力,包括解析JSON字符串、生成JSON对象以及进行JSON与Java对象之间的转换。 在Java中,有多种实现JSON API的库,如Jackson、Gson、org.json和json-lib等。本篇...

    ElasticSearch Java API 中文文档

    标题《ElasticSearch Java API 中文文档》表明本篇文档的主要内容是关于ElasticSearch的Java API的中文使用说明和相关知识点介绍。ElasticSearch是一个基于Lucene构建的开源搜索引擎,它提供了一个分布式、多用户...

    使用java调用jenkins api

    Java调用Jenkins API是一个常见的自动化任务执行场景,特别是在持续集成和持续部署(CI/CD)流程中。Jenkins作为一个开源的持续集成工具,提供了丰富的API接口,允许开发者通过编程方式与Jenkins服务器进行交互。...

    java中文api文档api

    8. **日期时间**:Java 8引入了新的日期时间API(java.time包),替代了旧的Date和Calendar,提供了更方便、更符合语义的日期和时间操作。 9. **XML处理**:Java提供了DOM、SAX和StAX等多种方式解析和操作XML文档,...

Global site tag (gtag.js) - Google Analytics