1.Date.getTime() 和 Calendar.getTimeInMillis() 返回自 1970 年 1 月 1 日 00:00:00 GMT+0 以来此 Date 对象表示的毫秒数。
证明
package com.siyuan.test.jdk; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; public class TimeTest { public static void main(String[] args) throws ParseException { SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Calendar calendar = Calendar.getInstance(); String timeStr = "1970-01-01 00:00:00"; Date time = dateFmt.parse(timeStr); System.out.println(time.getTime()); calendar.setTime(time); System.out.println(calendar.getTimeInMillis()); System.out.println(TimeZone.getDefault()); } }
输出结果
-28800000 -28800000 sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null]
-28800000 = 8 * 3600 * 1000
Asia/Shanghai 位于 GMT+0800
2.TimeZone对DateFormat的影响
package com.siyuan.test.jdk; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.TimeZone; public class DateFormatTest { public static void main(String[] args) { SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Calendar calendar = Calendar.getInstance(); System.out.println(dateFmt.format(calendar.getTime())); System.out.println(dateFmt.getTimeZone()); System.out.println(TimeZone.getDefault()); System.out.println("======================================================"); dateFmt.setTimeZone(TimeZone.getTimeZone("GMT+00")); System.out.println(dateFmt.format(calendar.getTime())); } }
输出结果
2014-10-20 22:34:44 sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null] sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null] ====================================================== 2014-10-20 14:34:44
3.MySQL中的DateTime数据类型
1)建表
CREATE TABLE `t_date_i18n` ( `FID` int(11) NOT NULL AUTO_INCREMENT, `FDate` datetime DEFAULT NULL, `FTimeStamp` timestamp NULL DEFAULT NULL, PRIMARY KEY (`FID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2)JDBC操作
--存储
package com.siyuan.test.jdk; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Timestamp; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; public class DBDateTest { public static String DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver"; public static String USER_NAME = "root"; public static String PASSWORD = "123456"; public static String URL = "jdbc:mysql://localhost:3306/study"; public static Connection getConnection() throws ClassNotFoundException, SQLException { Class.forName(DRIVER_CLASS_NAME); return DriverManager.getConnection(URL, USER_NAME, PASSWORD); } public static final String SQL_SAVE = "INSERT INTO t_date_i18n(FDate, FTimeStamp) values(?, ?)"; /** * 使用setDate方法存储 */ public void save(Date date) { Connection conn = null; PreparedStatement pstat = null; try { conn = DBDateTest.getConnection(); conn.setAutoCommit(false); pstat = conn.prepareStatement(SQL_SAVE); java.sql.Date dateSaved = new java.sql.Date(date.getTime()); pstat.setDate(1, dateSaved); pstat.setDate(2, dateSaved); pstat.executeUpdate(); conn.commit(); } catch (Exception e) { e.printStackTrace(); } finally { try { pstat.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } /** * 使用setTimestamp方法存储 */ public void save_2(Date date) { Connection conn = null; PreparedStatement pstat = null; try { conn = DBDateTest.getConnection(); conn.setAutoCommit(false); pstat = conn.prepareStatement(SQL_SAVE); Timestamp timestampSaved = new Timestamp(date.getTime()); pstat.setTimestamp(1, timestampSaved); pstat.setTimestamp(2, timestampSaved); pstat.executeUpdate(); conn.commit(); } catch (Exception e) { e.printStackTrace(); } finally { try { pstat.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } public static void main(String[] args) throws ParseException { DBDateTest test = new DBDateTest(); DateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateStr = "2014-10-25 00:00:00"; Date date1 = dateFmt.parse(dateStr); test.save(date1); dateFmt.setTimeZone(TimeZone.getTimeZone("GMT+00")); Date date2 = dateFmt.parse(dateStr); test.save_2(date2); TimeZone.setDefault(TimeZone.getTimeZone("GMT+02")); DateFormat dateFmt2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); date1 = dateFmt2.parse(dateStr); test.save(date1); dateFmt2.setTimeZone(TimeZone.getTimeZone("GMT+00")); date2 = dateFmt2.parse(dateStr); test.save_2(date2); } }
结果:
为了与 SQL DATE
的定义一致,由 java.sql.Date
实例包装的毫秒值必须通过将小时、分钟、秒和毫秒设置为与该实例相关的特定时区中的零来“规范化”。
java.sql.Timestamp
将时间转化为JDK默认TimeZone对应的时间进行存储。
存储时均和数据库的时区无关。
--读取
package com.siyuan.test.jdk; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; public class DBDateTest { public static String DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver"; public static String USER_NAME = "root"; public static String PASSWORD = "123456"; public static String URL = "jdbc:mysql://localhost:3306/study"; public static Connection getConnection() throws ClassNotFoundException, SQLException { Class.forName(DRIVER_CLASS_NAME); return DriverManager.getConnection(URL, USER_NAME, PASSWORD); } public static final String SQL_GET = "SELECT FDate, FTimeStamp FROM t_date_i18n WHERE FID = ?"; /** * 使用setDate方法存储 */ public void get(int id) { Connection conn = null; PreparedStatement pstat = null; try { conn = DBDateTest.getConnection(); conn.setAutoCommit(false); pstat = conn.prepareStatement(SQL_GET); pstat.setInt(1, id); ResultSet rs = pstat.executeQuery(); if (rs.next()) { System.out.println(format(rs.getDate(1))); System.out.println(format(rs.getTimestamp(2))); } conn.commit(); } catch (Exception e) { e.printStackTrace(); } finally { try { pstat.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } public static String format(Date date) { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); } public static void main(String[] args) throws ParseException { DBDateTest test = new DBDateTest(); test.get(1); TimeZone.setDefault(TimeZone.getTimeZone("GMT+02")); test.get(1); } }
结果
2014-10-25 00:00:00 2014-10-25 00:00:00 2014-10-25 00:00:00 2014-10-25 00:00:00
结论:
读取时保持时间一致,不管当前JDK的默认TimeZone是多少
3)MyBatis操作
--存储
package com.siyuan.test.mybatis.dao; import java.io.IOException; import java.io.InputStream; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import com.siyuan.test.mybatis.entity.DateI18N; public class DateI18NTest { public static void main(String[] args) throws IOException, ParseException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session2 = sqlSessionFactory.openSession(); try { DateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateStr = "2014-10-25 00:00:00"; DateI18N dateI18N = new DateI18N(); DateI18NDAO dateI18NDAO = session2.getMapper(DateI18NDAO.class); Date date1 = dateFmt.parse(dateStr); dateI18N.setDate(date1); dateI18NDAO.insert(dateI18N); dateFmt.setTimeZone(TimeZone.getTimeZone("GMT+00")); Date date2 = dateFmt.parse(dateStr); dateI18N.setDate(date2); dateI18NDAO.insert(dateI18N); TimeZone.setDefault(TimeZone.getTimeZone("GMT+02")); dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); date1 = dateFmt.parse(dateStr); dateI18N.setDate(date1); dateI18NDAO.insert(dateI18N); dateFmt.setTimeZone(TimeZone.getTimeZone("GMT+00")); date2 = dateFmt.parse(dateStr); dateI18N.setDate(date2); dateI18NDAO.insert(dateI18N); session2.commit(); } finally { session2.close(); } } }
DateI18N.java
package com.siyuan.test.mybatis.entity; import java.util.Date; public class DateI18N { private Date date; public DateI18N() { } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
DateI18NDAO.java
package com.siyuan.test.mybatis.dao; import com.siyuan.test.mybatis.entity.DateI18N; public interface DateI18NDAO { void insert(DateI18N dateI18N); }
DateI18NDAO.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.siyuan.test.mybatis.dao.DateI18NDAO"> <insert id="insert" parameterType="DateI18N"> INSERT INTO t_date_i18n (FDate) VALUES (#{date}) </insert> </mapper>
结果:
MyBatis的DateTypeHandler是采用Timestamp来处理Date对象的
4.国际化Date的方案
1)在对应的表里面新增一个字段,保存TimeZone
2)保存时统一为某一固定的TimeZone,读取时根据所需TimeZone进行转化