zz Java TimeZone ++: mapping Calendar to Oracle Date or TimeStamp
(original article : http://blog.sarathonline.com/2009/01/java-timezone-mapping-calendar-to.html )
In Oracle Database date and timestamp columns can be read in java using s[g]etTimeStamp() methods for storing date and time information. However, they do not save the TimeZone information! The read and write operations are done on java.sql.TimeStamp which is a subclass of java.util.Date. When reading and writing to database, they just write out the *face value* in Java VM's default TimeZone the code is running on. And read the value too 'TO' the java VM's Default TimeZone. So assuming you WriteDate program on a VM in EST and ReadDate program on another VM in PST (or just change system timezone) - You are getting a different *value* in the date Object.
So, How do you tackle this issue. The best way is to set your application to run on a specified (constant) default timezone. As mentioned in the earlier post this can be achieved by TimeZone.setDefault()
. If you are unable to do it, JDBC specification allows sql dates to be read and written using a specified calendar. The resultSet.s[g]etTimeStamp method has an overloaded cousin, that takes a Calendar parameter. These methods save the date *face value* into the db after converting it to the timezone of the calendar passed as argument. So if there is a central place, You would want to have code some thing like this.
staticfinalCalendar networkCal =Calendar.getInstance(TimeZone.getTimeZone("EST"));//Writing somewherePreparedStatement ps = conn.prepareStatement("Update datex set dt = ?, tms = ?, faceval =? where id=1"); ps.setDate(1,new java.sql.Date(userDate.getTime())); ps.setTimestamp(2,newTimestamp(userDate.getTime()),networkCal);//Reading ElsewhereResultSet rs = st.executeQuery("select * from datex where id = 1"); sqlTS = rs.getTimestamp("tms",networkCal);
In iBatis (we use iBatis), You can have a TypeHandlerCallback for Calender-TimeStamp mapping
classCalendarTypeHandlerCallbackimplementsTypeHandlerCallback{privatestaticfinalCalendar netWorkCal =Calendar.getInstance(TimeZone.getTimeZone("EST"));publicObject getResult(ResultGetter getter)throwsSQLException{Date date = getter.getDate(netWorkCal);Calendar calendar =null;if(date !=null){ calendar =Calendar.getInstance(); calendar.setTime(date);}return calendar;}publicvoid setParameter(ParameterSetter setter,Object parameter)throwsSQLException{GregorianCalendar calendar =(GregorianCalendar) parameter; java.sql.Date date =new java.sql.Date(calendar.getTimeInMillis()); setter.setDate(date, netWorkCal);}publicObject valueOf(String s){return s;}}
A Sample jdbc test case is:
/** * Table used: CREATE TABLE "DATEX" ( "ID" NUMBER(3,0) NOT NULL ENABLE, "DT" DATE, "TMS" DATE NOT NULL ENABLE, "FACEVAL" VARCHAR2(50) NOT NULL ENABLE, CONSTRAINT "DATEX_PK" PRIMARY KEY ("ID") ENABLE ) * * @author spandurangi * */ public class DBTimeStampReadWriteTest extends TestCase { TimeZone userTz = TimeZone.getTimeZone("IST"); //Used for writing TO and reading FROM RDBMS static final Calendar networkCal = Calendar.getInstance(TimeZone.getTimeZone("EST")); String userEntered = "2009-01-31 01:00:01"; /** * @throws Exception */ public void testDirectWriteConvToSTDTz() throws Exception { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); sdf.setTimeZone(userTz); Date userDate = sdf.parse(userEntered); System.out.println("========== DATABASE testDirectWriteConvToSTDTz TEST ================="); Connection conn = null; try { conn = getConnection(); PreparedStatement ps = conn.prepareStatement("Update datex set dt = ?, tms = ?, faceval =? where id=1"); ps.setDate(1, new java.sql.Date(userDate.getTime())); ps.setTimestamp(2, new Timestamp(userDate.getTime()), networkCal); ps.setString(3, userEntered + " p/w " + sdf.getTimeZone().getID()); ps.execute(); Statement st = conn.createStatement(); String SELECT_LATEST = "select * from datex where id = 1"; Calendar ret = printRow(st.executeQuery(SELECT_LATEST)); assertEquals(userDate,ret.getTime()); } catch (Exception e) { e.printStackTrace(); } finally { if (conn != null) { conn.close(); } } } /** * Run this test seperately with Vm's TZ same after doing the first one * @throws Exception */ public void testDirectReadConvToSTDTz() throws Exception { TimeZone.setDefault(TimeZone.getTimeZone("PST")); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); // to compare the same value!! sdf.setTimeZone(userTz); Date userDate = sdf.parse(userEntered); System.out.println("========== DATABASE testDirectReadConvToSTDTz TEST ================="); Connection conn = null; try { conn = getConnection(); Statement st = conn.createStatement(); String SELECT_LATEST = "select * from datex where id = 1"; Calendar ret = printRow(st.executeQuery(SELECT_LATEST)); assertEquals(userDate,ret.getTime()); //Comparision may run on any vm! Calendar org = Calendar.getInstance(); org.setTime(userDate); ret.setTimeZone(org.getTimeZone()); System.out.println(decorate(org) + " == " + decorate(ret)); assertEquals(decorate(org), decorate(ret)); } catch (Exception e) { e.printStackTrace(); } finally { if (conn != null) { conn.close(); } } } private String decorate(Calendar cal) { FastDateFormat f = FastDateFormat.getInstance("EEE MMM dd HH:mm:ss z yyyy"); return f.format(cal); } private Connection getConnection() throws Exception { Class.forName("oracle.jdbc.OracleDriver"); String url = "jdbc:oracle:thin:@localhost:1521:xe"; return DriverManager.getConnection(url, "sarath", "pass"); } private Calendar printRow(ResultSet rs) throws Exception { rs.next(); // JDBC driver reads by face value, loses date info java.sql.Date sqlDate = rs.getDate("dt"); Calendar cal = Calendar.getInstance(); cal.setTime(sqlDate); System.out.println("Date Information"); System.out.println(sqlDate + "::" + sqlDate.getTime() + " :: " + cal.getTime() + " :: " + cal.getTimeInMillis() + " :: " + decorate(cal)); // JDBC driver reads by face value, applies system tz, (mutates mill // secs) (WRONG WAY! binding to VM) Timestamp sqlTS = rs.getTimestamp("tms"); cal = Calendar.getInstance(); cal.setTime(sqlTS); System.out.println("Timestamp Information from db as it is"); System.out.println(sqlTS + "::" + sqlDate.getTime() + " :: " + cal.getTime() + " :: " + cal.getTimeInMillis() + " :: " + decorate(cal)); // JDBC driver reads by face value, applies the supplied tz that is // supplied (mutates mill secs) (CORRECT! reads in same Tz) sqlTS = rs.getTimestamp("tms", networkCal); cal.setTime(sqlTS); System.out.println("Timestamp Information read with a different Cal (allTimesInTz)"); System.out.println(sqlTS + "::" + sqlDate.getTime() + " :: " + cal.getTime() + " :: " + cal.getTimeInMillis() + " :: " + decorate(cal)); return cal; } }
If you are using Hibernate, You could use a user type to get similar effect.
Adventurously, I used the TimeZone.setDefault method on non-production systems of an application involving Tomcat, WebLogic a couple of wars and one ear. So far, I have not observed any issues, Google doesnot have any pages that give any known situations either. If I come to know, I will update.
相关推荐
<javaClientGenerator targetPackage="com.example.mapper" targetProject="src/main/java" type="XMLMAPPER"/> ``` 在上述配置完成后,只需运行Maven的`mybatis-generator:generate`目标,MBG就会根据配置...
Java SpringMVC Mapping的逆向生成是一个自动化工具的使用过程,主要是为了减少手动编写XML映射文件的工作量,提高开发效率。在这个场景中,我们提到的是使用Mybatis-Generator来生成DAO(数据访问对象)、Model...
MyBatis将SQL与Java代码分离,支持动态SQL,同时提供了强大的映射机制,使得ORM(Object-Relational Mapping)变得更加简单。在Spring框架中,MyBatis可以与Spring的事务管理无缝集成,通过Spring的...
组件出版于 2012 年末横空出世,由于不会炒作,...我才发现原来在 2013 年时上传的 0.04 版本是不带 OR/RO Mapping 机制的。。。 想了想,还是补上 v6 这个带 OR/RO Mapping 机制的版本吧,虽然是同一时期的产物。
【Hibernate】是Java中的一款对象关系映射(Object-Relational Mapping,ORM)框架,它将数据库操作与业务逻辑解耦,允许开发者通过面向对象的方式进行数据库交互。Hibernate通过XML或注解配置,可以自动映射Java类...
Java EE(Java Platform, Enterprise Edition)6是Java平台在企业级应用开发中的一个关键版本,它为构建分布式、多层的Web应用程序提供了丰富的框架和API。这个API文档集是Java开发者的重要参考资料,它包含了Java ...
【SSH+Oracle 整合详解】 SSH(Struts2、Spring、Hibernate)是Java开发中常用的三大开源框架,它们各自负责Web应用的不同层面:Struts2处理MVC模式中的Controller部分,Spring作为整体的IoC(Inversion of Control...
【标题】"blog项目 java+jsp+eclipse+jdk"是一个基于Java技术栈的博客系统开发实例,它结合了Java后端、JSP前端、Eclipse集成开发环境以及JDK运行环境,展示了如何构建一个完整的Web应用。在这个项目中,开发者可以...
它允许开发者直接编写原生的SQL查询,同时还能享受到ORM(Object-Relational Mapping)带来的便利。在本项目中,MyBatis作为数据访问层,负责与数据库进行交互。 **ShardingJDBC**: ShardingSphere(原名Sharding-...
Java爬虫技术结合Elasticsearch和Kibana的综合应用是一种高效的数据抓取、存储和可视化解决方案。在本文中,我们将深入探讨这三个组件的核心概念、它们如何协同工作以及如何利用它们构建一个完整的数据处理系统。 ...
3. **iBatis2**:iBatis 是一个 SQL mapping 框架,它将 SQL 语句与 Java 代码分离,提供了更灵活的数据库操作方式。在 Spring3 和 iBatis2 的结合中,iBatis 负责处理数据库查询和更新,Spring 则通过 DAO(数据...
7. **JPA(Java Persistence API)**或Hibernate:提供ORM(Object-Relational Mapping)功能,简化数据库操作。 【WebLogic知识点】 1. **应用部署**:WebLogic支持部署各种类型的J2EE应用,如WAR、EAR文件。 2. *...
- TIME: 对应 Java 的 Time 类型,但 Oracle9i 中没有单独的时间类型,通常用 DATE 类型表示。 - BLOB: 对应 Java 的 Object 类型,用于存储二进制大数据。 2. Java 数据类型: - Java 的基本数据类型如 byte, ...
不喜欢NHibernate传统的*.hbm.xml来对数据库进行映射的朋友有福了,可以使用NHibernate.Mapping.Attribute.dll来实现自动映射。 减少不小的工作量。
【Hibernate】作为ORM(Object-Relational Mapping)工具,解决了Java应用程序与关系数据库之间的交互问题。它允许开发者用面向对象的方式来操作数据库,通过映射机制将Java对象与数据库表进行对应,减少了对SQL的...
【基于Java的企业级应用开发:拦截器】 在Java企业级应用开发中,Spring MVC框架提供了一种名为拦截器(Interceptor)的功能,它与Servlet中的过滤器(Filter)类似,但有其独特的用法和功能。拦截器主要用于在用户...
3.4 数据访问层:JDBC(Java Database Connectivity)或者ORM(Object-Relational Mapping)框架如Hibernate,用于与MySQL数据库进行交互。 四、功能详解 4.1 客户管理:包括客户信息录入、查询、修改和删除,支持...