1 /* 2 * Copyright (c) 1996, 2016, 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 jdk.internal.misc.SharedSecrets; 31 import jdk.internal.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 * @since 1.1 46 */ 47 public class Date extends java.util.Date { 48 49 private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); 50 51 /** 52 * Constructs a <code>Date</code> object initialized with the given 53 * year, month, and day. 54 * <P> 55 * The result is undefined if a given argument is out of bounds. 56 * 57 * @param year the year minus 1900; must be 0 to 8099. (Note that 58 * 8099 is 9999 minus 1900.) 59 * @param month 0 to 11 60 * @param day 1 to 31 61 * @deprecated instead use the constructor <code>Date(long date)</code> 62 */ 63 @Deprecated(since="1.2") 64 public Date(int year, int month, int day) { 65 super(year, month, day); 66 } 67 68 /** 69 * Constructs a <code>Date</code> object using the given milliseconds 70 * time value. If the given milliseconds value contains time 71 * information, the driver will set the time components to the 72 * time in the default time zone (the time zone of the Java virtual 73 * machine running the application) that corresponds to zero GMT. 74 * 75 * @param date milliseconds since January 1, 1970, 00:00:00 GMT not 76 * to exceed the milliseconds representation for the year 8099. 77 * A negative number indicates the number of milliseconds 78 * before January 1, 1970, 00:00:00 GMT. 79 */ 80 public Date(long date) { 81 // If the millisecond date value contains time info, mask it out. 82 super(date); 83 84 } 85 86 /** 87 * Sets an existing <code>Date</code> object 88 * using the given milliseconds time value. 89 * If the given milliseconds value contains time information, 90 * the driver will set the time components to the 91 * time in the default time zone (the time zone of the Java virtual 92 * machine running the application) that corresponds to zero GMT. 93 * 94 * @param date milliseconds since January 1, 1970, 00:00:00 GMT not 95 * to exceed the milliseconds representation for the year 8099. 96 * A negative number indicates the number of milliseconds 97 * before January 1, 1970, 00:00:00 GMT. 98 */ 99 public void setTime(long date) { 100 // If the millisecond date value contains time info, mask it out. 101 super.setTime(date); 102 } 103 104 /** 105 * Converts a string in JDBC date escape format to 106 * a <code>Date</code> value. 107 * 108 * @param s a <code>String</code> object representing a date in 109 * in the format "yyyy-[m]m-[d]d". The leading zero for <code>mm</code> 110 * and <code>dd</code> may also be omitted. 111 * @return a <code>java.sql.Date</code> object representing the 112 * given date 113 * @throws IllegalArgumentException if the date given is not in the 114 * JDBC date escape format (yyyy-[m]m-[d]d) 115 */ 116 public static Date valueOf(String s) { 117 if (s == null) { 118 throw new java.lang.IllegalArgumentException(); 119 } 120 final int YEAR_LENGTH = 4; 121 final int MONTH_LENGTH = 2; 122 final int DAY_LENGTH = 2; 123 final int MAX_MONTH = 12; 124 final int MAX_DAY = 31; 125 Date d = null; 126 127 int firstDash = s.indexOf('-'); 128 int secondDash = s.indexOf('-', firstDash + 1); 129 int len = s.length(); 130 131 if ((firstDash > 0) && (secondDash > 0) && (secondDash < len - 1)) { 132 if (firstDash == YEAR_LENGTH && 133 (secondDash - firstDash > 1 && secondDash - firstDash <= MONTH_LENGTH + 1) && 134 (len - secondDash > 1 && len - secondDash <= DAY_LENGTH + 1)) { 135 int year = Integer.parseInt(s, 0, firstDash, 10); 136 int month = Integer.parseInt(s, firstDash + 1, secondDash, 10); 137 int day = Integer.parseInt(s, secondDash + 1, len, 10); 138 139 if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) { 140 d = new Date(year - 1900, month - 1, day); 141 } 142 } 143 } 144 if (d == null) { 145 throw new java.lang.IllegalArgumentException(); 146 } 147 148 return d; 149 150 } 151 152 153 /** 154 * Formats a date in the date escape format yyyy-mm-dd. 155 * 156 * @return a String in yyyy-mm-dd format 157 */ 158 @SuppressWarnings("deprecation") 159 public String toString () { 160 int year = super.getYear() + 1900; 161 int month = super.getMonth() + 1; 162 int day = super.getDate(); 163 164 char buf[] = new char[10]; 165 formatDecimalInt(year, buf, 0, 4); 166 buf[4] = '-'; 167 Date.formatDecimalInt(month, buf, 5, 2); 168 buf[7] = '-'; 169 Date.formatDecimalInt(day, buf, 8, 2); 170 171 return jla.newStringUnsafe(buf); 172 } 173 174 /** 175 * Formats an unsigned integer into a char array in decimal output format. 176 * Numbers will be zero-padded or truncated if the string representation 177 * of the integer is smaller than or exceeds len, respectively. 178 * 179 * Should consider moving this to Integer and expose it through 180 * JavaLangAccess similar to Integer::formatUnsignedInt 181 * @param val Value to convert 182 * @param buf Array containing converted value 183 * @param offset Starting pos in buf 184 * @param len length of output value 185 */ 186 static void formatDecimalInt(int val, char[] buf, int offset, int len) { 187 int charPos = offset + len; 188 do { 189 buf[--charPos] = (char)('0' + (val % 10)); 190 val /= 10; 191 } while (charPos > offset); 192 } 193 194 // Override all the time operations inherited from java.util.Date; 195 196 /** 197 * This method is deprecated and should not be used because SQL Date 198 * values do not have a time component. 199 * 200 * @deprecated 201 * @exception java.lang.IllegalArgumentException if this method is invoked 202 * @see #setHours 203 */ 204 @Deprecated(since="1.2") 205 public int getHours() { 206 throw new java.lang.IllegalArgumentException(); 207 } 208 209 /** 210 * This method is deprecated and should not be used because SQL Date 211 * values do not have a time component. 212 * 213 * @deprecated 214 * @exception java.lang.IllegalArgumentException if this method is invoked 215 * @see #setMinutes 216 */ 217 @Deprecated(since="1.2") 218 public int getMinutes() { 219 throw new java.lang.IllegalArgumentException(); 220 } 221 222 /** 223 * This method is deprecated and should not be used because SQL Date 224 * values do not have a time component. 225 * 226 * @deprecated 227 * @exception java.lang.IllegalArgumentException if this method is invoked 228 * @see #setSeconds 229 */ 230 @Deprecated(since="1.2") 231 public int getSeconds() { 232 throw new java.lang.IllegalArgumentException(); 233 } 234 235 /** 236 * This method is deprecated and should not be used because SQL Date 237 * values do not have a time component. 238 * 239 * @deprecated 240 * @exception java.lang.IllegalArgumentException if this method is invoked 241 * @see #getHours 242 */ 243 @Deprecated(since="1.2") 244 public void setHours(int i) { 245 throw new java.lang.IllegalArgumentException(); 246 } 247 248 /** 249 * This method is deprecated and should not be used because SQL Date 250 * values do not have a time component. 251 * 252 * @deprecated 253 * @exception java.lang.IllegalArgumentException if this method is invoked 254 * @see #getMinutes 255 */ 256 @Deprecated(since="1.2") 257 public void setMinutes(int i) { 258 throw new java.lang.IllegalArgumentException(); 259 } 260 261 /** 262 * This method is deprecated and should not be used because SQL Date 263 * values do not have a time component. 264 * 265 * @deprecated 266 * @exception java.lang.IllegalArgumentException if this method is invoked 267 * @see #getSeconds 268 */ 269 @Deprecated(since="1.2") 270 public void setSeconds(int i) { 271 throw new java.lang.IllegalArgumentException(); 272 } 273 274 /** 275 * Private serial version unique ID to ensure serialization 276 * compatibility. 277 */ 278 static final long serialVersionUID = 1511598038487230103L; 279 280 /** 281 * Obtains an instance of {@code Date} from a {@link LocalDate} object 282 * with the same year, month and day of month value as the given 283 * {@code LocalDate}. 284 * <p> 285 * The provided {@code LocalDate} is interpreted as the local date 286 * in the local time zone. 287 * 288 * @param date a {@code LocalDate} to convert 289 * @return a {@code Date} object 290 * @exception NullPointerException if {@code date} is null 291 * @since 1.8 292 */ 293 @SuppressWarnings("deprecation") 294 public static Date valueOf(LocalDate date) { 295 return new Date(date.getYear() - 1900, date.getMonthValue() -1, 296 date.getDayOfMonth()); 297 } 298 299 /** 300 * Creates a {@code LocalDate} instance using the year, month and day 301 * from this {@code Date} object. 302 * @return a {@code LocalDate} object representing the same date value 303 * 304 * @since 1.8 305 */ 306 @SuppressWarnings("deprecation") 307 public LocalDate toLocalDate() { 308 return LocalDate.of(getYear() + 1900, getMonth() + 1, getDate()); 309 } 310 311 /** 312 * This method always throws an UnsupportedOperationException and should 313 * not be used because SQL {@code Date} values do not have a time 314 * component. 315 * 316 * @exception java.lang.UnsupportedOperationException if this method is invoked 317 */ 318 @Override 319 public Instant toInstant() { 320 throw new java.lang.UnsupportedOperationException(); 321 } 322 }