Java的败笔-Date类
 
日期对任何高级程序语言来说,都是非常重要的一种数据类型,由于日期数据类型的特殊性,日期数据的格式众多,有时候还需要不同格式之间的日期进行各种比较运算操作,这使得日期的处理比较复杂。
 
在Java中,日期的处理相关的类如下:
java.util.Date
  java.sql.Date
  java.sql.Time
  java.sql.Timestamp
java.util.Calendar
java.util.TimeZone
 
和扯淡的设计,首先Date类有两个,其实完全可以用一个来代替,也许是刚开始时候没设计好的的问题吧。
 
从上面类的层次结构看,将java.util.Date转为java.sql.Date时候,日期的时分秒会被去掉,数据的精度发生变化了。这是两个上下级类之间很不合理的问题。
 
而JDBC中定义接口时候,用的是java.sql.Date,而我们常常用到的Date都是java.util.Date,这往往导致一些转换过程中发生误差。
 
于是java.sql.Timestamp类诞生了,它保持了日期数据原有的精度。可以实现和java.util.Date的无损转换。但是Timestamp这个类在一些预定义SQL中常常会出问题,报错!不知道是数据驱动的问题还是数据库问题,或者Java语言的问题。
这个问题可以看看下面给出的测试代码:
 
环境:
Java5
mysql-noinstall-5.1.40-win32.zip
mysql-connector-java-5.1.10.zip
 
建表SQL
create database    

use testdb;

drop table if exists testdate;

create table testdate (
    id bigint(20) not null auto_increment,
    code varchar(20) default null,
    crdate timestamp not null default current_timestamp,
    primary key (id)
) engine=myisam auto_increment=122 default charset=latin1;
 
测试类:
import java.sql.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;

/**
* 日期增改查测试
*
* @author leizhimin 2009-11-9 11:15:46
*/


public class Test {
        private static final String data_format = "yyyy-MM-dd kk:mm:ss";
        private static final SimpleDateFormat sf = new SimpleDateFormat(data_format);

        public static void main(String[] args) throws SQLException, ParseException {
                Timestamp ts = new Timestamp(sf.parse("2009-12-10 13:33:15").getTime());
                System.out.println(ts);
//                test_insert1();
//                test_insert2();
//                test_insert3();
//                test_update1();
//                test_update2();
//                test_query2();
        }

        public static void test_insert1() throws SQLException {
                Connection conn = ConnTools.makeConnection();
                Statement stmt = conn.createStatement();
                String sql_1 = "insert into testdate(code,crdate) values ('x',CURRENT_TIMESTAMP)";
                String sql_2 = "insert    into testdate(code,crdate) values ('y','2009-11-09 13:00:23')";
                stmt.executeUpdate(sql_1);
                stmt.executeUpdate(sql_2);
        }

        public static void test_insert2() throws SQLException {
                Connection conn = ConnTools.makeConnection();
                String sql = "insert into testdate(code,crdate) values ('z',?)";
                PreparedStatement pstmt = conn.prepareStatement(sql);
                pstmt.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
                pstmt.executeUpdate();
        }

        public static void test_insert3() throws SQLException {
                Connection conn = ConnTools.makeConnection();
                String sql = "insert into testdate(code,crdate) values ('w',?)";
                PreparedStatement pstmt = conn.prepareStatement(sql);
                pstmt.setString(1, "2009-11-09 13:00:23");
                pstmt.executeUpdate();
        }

        public static void test_update1() throws SQLException {
                Connection conn = ConnTools.makeConnection();
                Statement stmt = conn.createStatement();
                String sql = "update testdate set crdate = '2009-12-12 13:33:15' where code = 'z'";
                stmt.executeUpdate(sql);
        }

        public static void test_update2() throws SQLException {
                Connection conn = ConnTools.makeConnection();
                String sql = "update testdate set crdate = ? where code = 'z'";
                PreparedStatement pstmt = conn.prepareStatement(sql);
                pstmt.setString(1, "2009-12-12 13:33:15");
                pstmt.executeUpdate(sql);
        }

//        public static void test_update3() throws SQLException, ParseException {
//                Connection conn = ConnTools.makeConnection();
//                String sql = "update testdate set crdate = ? where code = 'z'";
//                PreparedStatement pstmt = conn.prepareStatement(sql);
//                pstmt.setTimestamp(1, new Timestamp(sf.parse("2009-11-09 13:00:23").getTime()));
//                pstmt.executeUpdate(sql);
//        }

        public static void test_query1() throws SQLException {
                Connection conn = ConnTools.makeConnection();
                String sql = "select * from testdate where crdate > '2009-11-09 13:00:23' and crdate < '2009-11-10 13:00:23'";
                Statement stmt = conn.createStatement();
                ResultSet rs = stmt.executeQuery(sql);
                while (rs.next()) {
                        System.out.println(">>> id=" + rs.getLong("id") + "; code=" + rs.getString("code") + "; crdate=" + rs.getTimestamp("crdate"));
                }
                conn.close();
        }

//        public static void test_query2() throws SQLException, ParseException {
//                Connection conn = ConnTools.makeConnection();
//                String sql = "select * from testdate where crdate > ? and crdate < ?";
//                PreparedStatement pstmt = conn.prepareStatement(sql);
////                pstmt.setString(1,"2009-11-09 13:00:23");
////                pstmt.setString(2,"2009-11-10 13:00:23");
//                pstmt.setTimestamp(1,new Timestamp(sf.parse("2009-11-09 13:00:23").getTime()));
//                pstmt.setTimestamp(2,new Timestamp(sf.parse("2009-11-10 13:00:23").getTime()));
//                ResultSet rs = pstmt.executeQuery(sql);
//                while (rs.next()) {
//                        System.out.println(">>> id=" + rs.getLong("id") + "; code=" + rs.getString("code") + "; crdate=" + rs.getTimestamp("crdate"));
//                }
//                conn.close();
//        }
}
 
以上的各个测试方法,被注释掉的是出错的,没注释掉的是支持的。
对于出错的,一直也没找到原因何在。实在令人郁闷。
 
------------
 
再说Date、Time根本就没有存在的价值,看看API,里面的方法都过期了,就剩下toString和valueOf方法,这两个类也成了API的垃圾,尤其是java.sql.Date,在JDBC接口中使用了,因此,如果这几个垃圾干掉了,JDBC接口规范也要改,那么将引发各个数据库厂商对数据库驱动也要改,这是不可接受的。
 
但是这些越多越多的垃圾导致了Java的混乱,也阻碍语言的间接性。其实Java中还有大量的垃圾API,仅仅为了一个向后兼容而保留着。
 
新的Java7目前还没听说要给API瘦身,不知道啥时候Java的日期处理能像C#那样方便就好了。