001/* 002 * ModeShape (http://www.modeshape.org) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.modeshape.jdbc.util; 017 018import java.sql.Date; 019import java.sql.Time; 020import java.sql.Timestamp; 021import java.text.DateFormat; 022import java.text.SimpleDateFormat; 023import java.util.Calendar; 024import java.util.GregorianCalendar; 025import java.util.TimeZone; 026 027/** 028 * Utility methods for SQL Timestamps, Time, and Dates with time zones as UTC This is intended to take incoming Strings or Dates 029 * that have accurate Calendar fields and give the UTC time by interpretting those fields in the target time zone. Use of the 030 * Calendar object passed in will not be thread safe, but it will not alter the contents of the Calendar. Note that normalization 031 * occurs only for the transition from one type to another. 032 */ 033public class TimestampWithTimezone { 034 035 public static DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$ 036 public static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$ 037 public static DateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss a"); //$NON-NLS-1$ 038 039 private static ThreadLocal<Calendar> CALENDAR = new ThreadLocal<Calendar>() { 040 @Override 041 protected Calendar initialValue() { 042 return Calendar.getInstance(); 043 } 044 }; 045 046 public static Calendar getCalendar() { 047 return CALENDAR.get(); 048 } 049 050 public static void resetCalendar( TimeZone tz ) { 051 TimeZone.setDefault(tz); 052 Calendar cal = Calendar.getInstance(); 053 cal.setTimeZone(tz); 054 CALENDAR.set(cal); 055 } 056 057 public static Timestamp createTimestamp( Calendar initial, 058 Calendar target ) { 059 if (target == null) { 060 target = getCalendar(); 061 } 062 063 long time = target.getTimeInMillis(); 064 065 Calendar new_target = adjustCalendarForTimeStamp(initial, target); 066 067 Timestamp tsInTz = createTimestamp(new_target); 068 069 target.setTimeInMillis(time); 070 return tsInTz; 071 } 072 073 public static Time createTime( Calendar initial, 074 Calendar target ) { 075 if (target == null) { 076 // if target is null, then obtain current calendar 077 target = getCalendar(); 078 } 079 080 long time = target.getTimeInMillis(); 081 082 adjustCalendarForTime(initial, target); 083 084 target.set(Calendar.MILLISECOND, 0); 085 086 Time result = createTime(target); 087 088 target.setTimeInMillis(time); 089 090 return result; 091 } 092 093 public static Date createDate( Calendar initial, 094 Calendar target ) { 095 if (target == null) { 096 return createDate(initial); 097 } 098 099 long time = target.getTimeInMillis(); 100 101 target = adjustCalendarForDate(initial, target); 102 103 Date result = normalizeDate(target, true); 104 105 target.setTimeInMillis(time); 106 107 return result; 108 } 109 110 /** 111 * Creates normalized SQL Time Object based on the target Calendar. 112 * 113 * @param target Calendar 114 * @return Time 115 */ 116 public static Time createTime( Calendar target ) { 117 return new Time(target.getTimeInMillis()); 118 } 119 120 /** 121 * Creates normalized SQL Date Object based on the target Calendar 122 * 123 * @param target Calendar 124 * @return Date 125 */ 126 public static Date createDate( Calendar target ) { 127 return new java.sql.Date(target.getTime().getTime()); 128 } 129 130 /** 131 * Creates normalized SQL Timestamp Object based on the target Calendar 132 * 133 * @param target Calendar 134 * @return Timestamp 135 */ 136 public static Timestamp createTimestamp( Calendar target ) { 137 return new Timestamp(target.getTime().getTime()); 138 } 139 140 private static Date normalizeDate( Calendar target, 141 boolean isDate ) { 142 if (isDate) { 143 target.set(Calendar.HOUR_OF_DAY, 0); 144 target.set(Calendar.MINUTE, 0); 145 target.set(Calendar.SECOND, 0); 146 target.set(Calendar.MILLISECOND, 0); 147 } 148 return createDate(target); 149 } 150 151 private static void adjustCalendarForTime( Calendar initial, 152 Calendar target ) { 153 assert initial != null; 154 155 if (initial.getTimeZone().hasSameRules(target.getTimeZone())) { 156 target.setTime(initial.getTime()); 157 return; 158 } 159 160 target.clear(); 161 for (int i = 0; i <= Calendar.MILLISECOND; i++) { 162 target.set(i, initial.get(i)); 163 } 164 } 165 166 private static Calendar adjustCalendarForDate( Calendar initial, 167 Calendar target ) { 168 assert initial != null; 169 170 if (initial.getTimeZone().hasSameRules(target.getTimeZone())) { 171 target.setTime(initial.getTime()); 172 return target; 173 } 174 175 Calendar ntarget = new GregorianCalendar(target.getTimeZone()); 176 ntarget.setTimeInMillis(initial.getTimeInMillis()); 177 178 return ntarget; 179 } 180 181 private static Calendar adjustCalendarForTimeStamp( Calendar initial, 182 Calendar target ) { 183 assert initial != null; 184 185 if (initial.getTimeZone().hasSameRules(target.getTimeZone())) { 186 target.setTime(initial.getTime()); 187 return target; 188 } 189 190 TimeZone targetTimeZone = target.getTimeZone(); 191 Calendar ret = new GregorianCalendar(targetTimeZone); 192 ret.setTimeInMillis(initial.getTimeInMillis() + targetTimeZone.getOffset(initial.getTimeInMillis()) 193 - initial.getTimeZone().getOffset(initial.getTimeInMillis())); 194 ret.getTime(); 195 return ret; 196 } 197}