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);
}
}
结果:
java.sql.Date
为了与 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进行转化