1 /* 2 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.sql; 27 28 import java.time.Instant; 29 import java.time.LocalDate; 30 import sun.misc.SharedSecrets; 31 import sun.misc.JavaLangAccess; 32 33 /** 34 * <P>A thin wrapper around a millisecond value that allows 35 * JDBC to identify this as an SQL <code>DATE</code> value. A 36 * milliseconds value represents the number of milliseconds that 37 * have passed since January 1, 1970 00:00:00.000 GMT. 38 * <p> 39 * To conform with the definition of SQL <code>DATE</code>, the 40 * millisecond values wrapped by a <code>java.sql.Date</code> instance 41 * must be 'normalized' by setting the 42 * hours, minutes, seconds, and milliseconds to zero in the particular 43 * time zone with which the instance is associated. 44 */ 45 public class Date extends java.util.Date { 46 47 private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); 48 49 /** 50 * Constructs a <code>Date</code> object initialized with the given 51 * year, month, and day. 52 * <P> 53 * The result is undefined if a given argument is out of bounds. 54 * 55 * @param year the year minus 1900; must be 0 to 8099. (Note that 56 * 8099 is 9999 minus 1900.) 57 * @param month 0 to 11 58 * @param day 1 to 31 59 * @deprecated instead use the constructor <code>Date(long date)</code> 60 */ 61 @Deprecated 62 public Date(int year, int month, int day) { 63 super(year, month, day); 64 } 65 66 /** 67 * Constructs a <code>Date</code> object using the given milliseconds 68 * time value. If the given milliseconds value contains time 69 * information, the driver will set the time components to the 70 * time in the default time zone (the time zone of the Java virtual 71 * machine running the application) that corresponds to zero GMT. 72 * 73 * @param date milliseconds since January 1, 1970, 00:00:00 GMT not 74 * to exceed the milliseconds representation for the year 8099. 75 * A negative number indicates the number of milliseconds 76 * before January 1, 1970, 00:00:00 GMT. 77 */ 78 public Date(long date) { 79 // If the millisecond date value contains time info, mask it out. 80 super(date); 81 82 } 83 84 /** 85 * Sets an existing <code>Date</code> object 86 * using the given milliseconds time value. 87 * If the given milliseconds value contains time information, 88 * the driver will set the time components to the 89 * time in the default time zone (the time zone of the Java virtual 90 * machine running the application) that corresponds to zero GMT. 91 * 92 * @param date milliseconds since January 1, 1970, 00:00:00 GMT not 93 * to exceed the milliseconds representation for the year 8099. 94 * A negative number indicates the number of milliseconds 95 * before January 1, 1970, 00:00:00 GMT. 96 */ 97 public void setTime(long date) { 98 // If the millisecond date value contains time info, mask it out. 99 super.setTime(date); 100 } 101 102 /** 103 * Converts a string in JDBC date escape format to 104 * a <code>Date</code> value. 105 * 106 * @param s a <code>String</code> object representing a date in 107 * in the format "yyyy-[m]m-[d]d". The leading zero for <code>mm</code> 108 * and <code>dd</code> may also be omitted. 109 * @return a <code>java.sql.Date</code> object representing the 110 * given date 111 * @throws IllegalArgumentException if the date given is not in the 112 * JDBC date escape format (yyyy-[m]m-[d]d) 113 */ 114 public static Date valueOf(String s) { 115 if (s == null) { 116 throw new java.lang.IllegalArgumentException(); 117 } 118 final int YEAR_LENGTH = 4; 119 final int MONTH_LENGTH = 2; 120 final int DAY_LENGTH = 2; 121 final int MAX_MONTH = 12; 122 final int MAX_DAY = 31; 123 Date d = null; 124 125 int firstDash = s.indexOf('-'); 126 int secondDash = s.indexOf('-', firstDash + 1); 127 int len = s.length(); 128 129 if ((firstDash > 0) && (secondDash > 0) && (secondDash < len - 1)) { 130 if (firstDash == YEAR_LENGTH && 131 (secondDash - firstDash > 1 && secondDash - firstDash <= MONTH_LENGTH + 1) && 132 (len - secondDash > 1 && len - secondDash <= DAY_LENGTH + 1)) { 133 int year = Integer.parseInt(s, 0, firstDash, 10); 134 int month = Integer.parseInt(s, firstDash + 1, secondDash, 10); 135 int day = Integer.parseInt(s, secondDash + 1, len, 10); 136 137 if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) { 138 d = new Date(year - 1900, month - 1, day); 139 } 140 } 141 } 142 if (d == null) { 143 throw new java.lang.IllegalArgumentException(); 144 } 145 146 return d; 147 148 } 149 150 151 /** 152 * Formats a date in the date escape format yyyy-mm-dd. 153 * 154 * @return a String in yyyy-mm-dd format 155 */ 156 @SuppressWarnings("deprecation") 157 public String toString () { 158 int year = super.getYear() + 1900; 159 int month = super.getMonth() + 1; 160 int day = super.getDate(); 161 162 char buf[] = new char[10]; 163 formatDecimalInt(year, buf, 0, 4); 164 buf[4] = '-'; 165 Date.formatDecimalInt(month, buf, 5, 2); 166 buf[7] = '-'; 167 Date.formatDecimalInt(day, buf, 8, 2); 168 169 return jla.newStringUnsafe(buf); 170 } 171 172 /** 173 * Formats an unsigned integer into a char array in decimal output format. 174 * Numbers will be zero-padded or truncated if the string representation 175 * of the integer is smaller than or exceeds len, respectively. 176 * 177 * Should consider moving this to Integer and expose it through 178 * JavaLangAccess similar to Integer::formatUnsignedInt 179 * @param val Value to convert 180 * @param buf Array containing converted value 181 * @param offset Starting pos in buf 182 * @param len length of output value 183 */ 184 static void formatDecimalInt(int val, char[] buf, int offset, int len) { 185 int charPos = offset + len; 186 do { 187 buf[--charPos] = (char)('0' + (val % 10)); 188 val /= 10; 189 } while (charPos > offset); 190 } 191 192 // Override all the time operations inherited from java.util.Date; 193 194 /** 195 * This method is deprecated and should not be used because SQL Date 196 * values do not have a time component. 197 * 198 * @deprecated 199 * @exception java.lang.IllegalArgumentException if this method is invoked 200 * @see #setHours 201 */ 202 @Deprecated 203 public int getHours() { 204 throw new java.lang.IllegalArgumentException(); 205 } 206 207 /** 208 * This method is deprecated and should not be used because SQL Date 209 * values do not have a time component. 210 * 211 * @deprecated 212 * @exception java.lang.IllegalArgumentException if this method is invoked 213 * @see #setMinutes 214 */ 215 @Deprecated 216 public int getMinutes() { 217 throw new java.lang.IllegalArgumentException(); 218 } 219 220 /** 221 * This method is deprecated and should not be used because SQL Date 222 * values do not have a time component. 223 * 224 * @deprecated 225 * @exception java.lang.IllegalArgumentException if this method is invoked 226 * @see #setSeconds 227 */ 228 @Deprecated 229 public int getSeconds() { 230 throw new java.lang.IllegalArgumentException(); 231 } 232 233 /** 234 * This method is deprecated and should not be used because SQL Date 235 * values do not have a time component. 236 * 237 * @deprecated 238 * @exception java.lang.IllegalArgumentException if this method is invoked 239 * @see #getHours 240 */ 241 @Deprecated 242 public void setHours(int i) { 243 throw new java.lang.IllegalArgumentException(); 244 } 245 246 /** 247 * This method is deprecated and should not be used because SQL Date 248 * values do not have a time component. 249 * 250 * @deprecated 251 * @exception java.lang.IllegalArgumentException if this method is invoked 252 * @see #getMinutes 253 */ 254 @Deprecated 255 public void setMinutes(int i) { 256 throw new java.lang.IllegalArgumentException(); 257 } 258 259 /** 260 * This method is deprecated and should not be used because SQL Date 261 * values do not have a time component. 262 * 263 * @deprecated 264 * @exception java.lang.IllegalArgumentException if this method is invoked 265 * @see #getSeconds 266 */ 267 @Deprecated 268 public void setSeconds(int i) { 269 throw new java.lang.IllegalArgumentException(); 270 } 271 272 /** 273 * Private serial version unique ID to ensure serialization 274 * compatibility. 275 */ 276 static final long serialVersionUID = 1511598038487230103L; 277 278 /** 279 * Obtains an instance of {@code Date} from a {@link LocalDate} object 280 * with the same year, month and day of month value as the given 281 * {@code LocalDate}. 282 * <p> 283 * The provided {@code LocalDate} is interpreted as the local date 284 * in the local time zone. 285 * 286 * @param date a {@code LocalDate} to convert 287 * @return a {@code Date} object 288 * @exception NullPointerException if {@code date} is null 289 * @since 1.8 290 */ 291 @SuppressWarnings("deprecation") 292 public static Date valueOf(LocalDate date) { 293 return new Date(date.getYear() - 1900, date.getMonthValue() -1, 294 date.getDayOfMonth()); 295 } 296 297 /** 298 * Creates a {@code LocalDate} instance using the year, month and day 299 * from this {@code Date} object. 300 * @return a {@code LocalDate} object representing the same date value 301 * 302 * @since 1.8 303 */ 304 @SuppressWarnings("deprecation") 305 public LocalDate toLocalDate() { 306 return LocalDate.of(getYear() + 1900, getMonth() + 1, getDate()); 307 } 308 309 /** 310 * This method always throws an UnsupportedOperationException and should 311 * not be used because SQL {@code Date} values do not have a time 312 * component. 313 * 314 * @exception java.lang.UnsupportedOperationException if this method is invoked 315 */ 316 @Override 317 public Instant toInstant() { 318 throw new java.lang.UnsupportedOperationException(); 319 } 320 }