View Javadoc

1   /*
2    * JBoss, Home of Professional Open Source.
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * 
7    * This library is free software; you can redistribute it and/or
8    * modify it under the terms of the GNU Lesser General Public
9    * License as published by the Free Software Foundation; either
10   * version 2.1 of the License, or (at your option) any later version.
11   * 
12   * This library is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   * Lesser General Public License for more details.
16   * 
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this library; if not, write to the Free Software
19   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20   * 02110-1301 USA.
21   */
22  
23  package org.modeshape.jdbc.util;
24  
25  import java.sql.Date;
26  import java.sql.Time;
27  import java.sql.Timestamp;
28  import java.text.DateFormat;
29  import java.text.SimpleDateFormat;
30  import java.util.Calendar;
31  import java.util.GregorianCalendar;
32  import java.util.TimeZone;
33  
34  
35  /**
36   * Utility methods for SQL Timestamps, Time, and Dates with time zones as UTC 
37   * 
38   * This is intended to take incoming Strings or Dates that have accurate 
39   * Calendar fields and give the UTC time by interpretting those fields
40   * in the target time zone. 
41   * 
42   * Use of the Calendar object passed in will not be thread safe, but
43   * it will not alter the contents of the Calendar.
44   * 
45   * Note that normalization occurs only for the transition from one type to another. 
46   *  
47   */
48  public class TimestampWithTimezone {
49  	
50      public static DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$
51      public static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
52      public static DateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss a"); //$NON-NLS-1$
53  
54  	
55  	private static ThreadLocal<Calendar> CALENDAR = new ThreadLocal<Calendar>() {
56  		@Override
57  		protected Calendar initialValue() {
58  			return Calendar.getInstance();
59  		}
60  	};
61  	
62  	public static Calendar getCalendar() {
63  		return CALENDAR.get();
64  	}
65  	
66  	public static void resetCalendar(TimeZone tz) {
67  		TimeZone.setDefault(tz);
68  		Calendar cal = Calendar.getInstance();
69  		cal.setTimeZone(tz);
70  		CALENDAR.set(cal);
71  	}
72  	
73  	
74      public static Timestamp createTimestamp(Calendar initial, Calendar target) {
75          if (target == null) {
76              target = getCalendar();
77          }
78  
79          long time = target.getTimeInMillis(); 
80          
81          Calendar new_target = adjustCalendarForTimeStamp(initial, target);
82                  
83          Timestamp tsInTz = createTimestamp(new_target); 
84                  
85          target.setTimeInMillis(time);
86          return tsInTz;      
87      }	
88      
89      public static Time createTime(Calendar initial, Calendar target) {
90          if (target == null) {
91          	// if target is null, then obtain current calendar
92          	target = getCalendar();
93          }
94         
95          long time = target.getTimeInMillis(); 
96  
97          adjustCalendarForTime(initial, target); 
98          
99          target.set(Calendar.MILLISECOND, 0);
100         
101         Time result = createTime(target);
102         
103         target.setTimeInMillis(time);
104 
105         return result;
106     }
107     
108     public static Date createDate(Calendar initial, Calendar target) {
109         if (target == null) {
110             return createDate(initial);
111         }
112 
113         long time = target.getTimeInMillis(); 
114         
115         target = adjustCalendarForDate(initial, target);
116                  
117         Date result = normalizeDate(target, true);
118                
119         target.setTimeInMillis(time);
120 
121         return result;
122     }
123     
124     /**
125      * Creates normalized SQL Time Object based on
126      * the target Calendar.
127      * @param target Calendar 
128      * 
129      * @return Time
130      */
131     public static Time createTime(Calendar target) {  
132     	return new Time(target.getTimeInMillis());
133     }
134     
135   /**
136   * Creates normalized SQL Date Object based on
137   * the target Calendar
138   * @param target Calendar 
139   *  
140   * @return Date
141   */ 
142     public static Date createDate(Calendar target) {		        
143         return new java.sql.Date(target.getTime().getTime());
144     }
145     
146     
147     /**
148      * Creates normalized SQL Timestamp Object based on
149      * the target Calendar
150      * @param target Calendar 
151      *  
152      * @return Timestamp
153      */ 
154     public static Timestamp createTimestamp(Calendar target) {
155         return new Timestamp(target.getTime().getTime());
156     }
157     
158     private static Date normalizeDate(Calendar target, boolean isDate) {
159          if (isDate) {
160             target.set(Calendar.HOUR_OF_DAY, 0);
161             target.set(Calendar.MINUTE, 0);
162             target.set(Calendar.SECOND, 0);
163             target.set(Calendar.MILLISECOND, 0);
164         }
165         return createDate(target);
166     } 
167     
168 	private static void adjustCalendarForTime(Calendar initial,
169 			Calendar target) {
170 		assert initial != null;
171 
172         if (initial.getTimeZone().hasSameRules(target.getTimeZone())) {
173 			 target.setTime(initial.getTime());
174 			 return;
175         }
176          
177         target.clear();
178         for (int i = 0; i <= Calendar.MILLISECOND; i++) {
179             target.set(i, initial.get(i));
180         }     		
181 	}
182    
183 	private static Calendar adjustCalendarForDate(Calendar initial,
184 			Calendar target) {
185 		assert initial != null;
186 
187 		if (initial.getTimeZone().hasSameRules(target.getTimeZone())) {	
188 			target.setTime(initial.getTime());
189 			return target;
190 		}
191 		
192 		Calendar ntarget = new GregorianCalendar(target.getTimeZone());
193 		ntarget.setTimeInMillis(initial.getTimeInMillis()); 	
194 
195         return ntarget;
196 	}
197 	
198 	private static Calendar adjustCalendarForTimeStamp(Calendar initial,
199 			Calendar target) {
200 		assert initial != null;
201 
202 		if (initial.getTimeZone().hasSameRules(target.getTimeZone())) {	
203 			target.setTime(initial.getTime());
204 			return target;
205 		}
206 		
207 		TimeZone targetTimeZone = target.getTimeZone();
208 		    Calendar ret = new GregorianCalendar(targetTimeZone);
209 		    ret.setTimeInMillis(initial.getTimeInMillis() +
210 		    		targetTimeZone.getOffset(initial.getTimeInMillis()) -
211 		            initial.getTimeZone().getOffset(initial.getTimeInMillis()));
212 		    ret.getTime();
213 		    return ret;
214 		    
215 //		    Calendar ret = new GregorianCalendar(targetTimeZone);
216 //		    ret.setTimeInMillis(initial.getTimeInMillis() +
217 //		    		targetTimeZone.getOffset(initial.getTimeInMillis()) -
218 //		            TimeZone.getDefault().getOffset(initial.getTimeInMillis()));
219 		
220 	}	
221 }