当前位置:编程学习 > JAVA >>

Java的日期API真烂

蛋疼的java.sql.Date
 
只有Date和Calendar搞定一切吗?那还好啊。当然不是!光Date就有java.util.Date和java.sql.Date,而且关系是java.sql.Date extends java.util.Date。为了把前者转成后者,我写了这样的代码:
 
Date date = new Date();
java.sql.Date d = new java.sql.Date(date.getTime());
居然不支持Date参数的构造器,我只好传入long类型的时间。接下去,我尝试把当前小时数取出来:
 
System.out.println(d.getHours());
悲剧出现了:
 
Exception in thread "main" java.lang.IllegalArgumentException
at java.sql.Date.getHours(Date.java:177)
一看源码,坑爹啊:
 
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类的构造器:
 
public Date(int year, int month, int day)
长得并不奇葩嘛。
 
好,现在我要输出2012年的1月1号了:
 
Date date = new Date(2012,1,1);
System.out.println(date);
结果,我傻眼了:
 
Thu Feb 01 00:00:00 CST 3912
等等,这是啥?3192年?
 
原来实际年份是要在你的年份参数上加上个起始年份1900。
 
更坑爹的是,月份参数我不是给了1吗?怎么输出二月(Feb)了?
 
Date里面的月份居然是用0~11表示的,换句话说,一月用0来表示,二月用1来表示。如果不用常量或者枚举,很容易踩到坑里去,对不对?
 
后来发现Go语言的time.Date方法,对于月份做了个恶心但是不容易坑人的处理(看奇葩的月份参数啊):
 
func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location)
我甚至怀疑Google这样处理是在用极端的方法鄙视Java(另,据我所知,JavaScript好像也是这样的,月份从0开始)……
 
尝试Joda吧
 
最开始的时候,Date既要承载日期信息,又要做日期之间的转换,还要做不同日期格式的显示,职责较繁杂,从JDK 1.1 开始,这三项职责分开了:
 
使用Calendar类实现日期和时间字段之间转换;
使用DateFormat类来格式化和分析日期字符串;
而Date只用来承载日期和时间信息。
原有Date中的相应方法已废弃。不过,无论是Date,还是Calendar,都用着太不方便了,这是API没有设计好的地方。
 
比如Calendar的getInstance方法,并未提供一个指定年月日和时分秒的重载方法,每次要指定特定的日期时间,必须先获取一个表示当前时间的Calendar实例,再去设值,比如:
 
Calendar c = Calendar.getInstance();
c.set(2012, 0, 1, 11, 11, 11);
System.out.println(c.getTime());
注意上面代码中对于年份的传值——是的,和Date不一样的是,Calendar年份的传值不需要减去1900(当然月份的定义和Date还是一样),这种不一致真是让人抓狂!
 
打印:
 
Sun Jan 01 11:11:11 CST 2012
有很多开源库都在努力弥补Java的这一问题,比如Joda-Time,获取Calendar对象和设置时间完全可以合成一步完成:
 
DateTime dateTime = new DateTime(2012, 1, 1, 11, 11, 11, 0);
而且,一月份总是可以传1来表示了。
 
再如,如果要给上述时间增加3天再按格式输出的话,使用Joda更加便捷:
 
System.out.println(dateTime.plusDays(3).toString("E MM/dd/yyyy HH:mm:ss");
补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,