1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.sql; 19 20 /** 21 * A class which can consume and produce dates in SQL {@code Date} format. 22 * <p> 23 * Dates are represented in SQL as {@code yyyy-MM-dd}. Note that this date 24 * format only deals with year, month and day values. There are no values for 25 * hours, minutes, seconds. 26 * <p> 27 * This is unlike the familiar {@code java.util.Date} object, which also includes 28 * values for hours, minutes, seconds, and milliseconds. 29 * <p> 30 * Time points are handled as millisecond values - milliseconds since the Epoch, 31 * January 1st 1970, 00:00:00.000 GMT. Time values passed to the {@code 32 * java.sql.Date} class are "normalized" to the time 00:00:00.000 GMT on the 33 * date implied by the time value. 34 */ 35 @FindBugsSuppressWarnings("NM_SAME_SIMPLE_NAME_AS_SUPERCLASS") 36 public class Date extends java.util.Date { 37 38 private static final long serialVersionUID = 1511598038487230103L; 39 40 /** 41 * Constructs a {@code Date} object corresponding to the supplied year, 42 * month and day. 43 * 44 * @deprecated Use the constructor {@link #Date(long)} instead. 45 * @param theYear 46 * the year, specified as the year minus 1900. Must be in the 47 * range {@code [0,8099]}. 48 * @param theMonth 49 * the month, specified as a number with 0 = January. Must be in 50 * the range {@code [0,11]}. 51 * @param theDay 52 * the day in the month. Must be in the range {@code [1,31]}. 53 */ 54 @Deprecated Date(int theYear, int theMonth, int theDay)55 public Date(int theYear, int theMonth, int theDay) { 56 super(theYear, theMonth, theDay); 57 } 58 59 /** 60 * Creates a date which corresponds to the day determined by the supplied 61 * milliseconds time value {@code theDate}. 62 * 63 * @param theDate 64 * a time value in milliseconds since the epoch - January 1 1970 65 * 00:00:00 GMT. The time value (hours, minutes, seconds, 66 * milliseconds) stored in the {@code Date} object is adjusted to 67 * correspond to 00:00:00 GMT on the day determined by the supplied 68 * time value. 69 */ Date(long theDate)70 public Date(long theDate) { 71 super(normalizeTime(theDate)); 72 } 73 74 /** 75 * @deprecated This method is deprecated and must not be used. SQL {@code 76 * Date} values do not have an hours component. 77 * @return does not return anything. 78 * @throws IllegalArgumentException 79 * if this method is called. 80 */ 81 @Deprecated 82 @Override getHours()83 public int getHours() { 84 throw new IllegalArgumentException("unimplemented"); 85 } 86 87 /** 88 * @deprecated This method is deprecated and must not be used. SQL {@code 89 * Date} values do not have a minutes component. 90 * @return does not return anything. 91 * @throws IllegalArgumentException 92 * if this method is called. 93 */ 94 @Deprecated 95 @Override getMinutes()96 public int getMinutes() { 97 throw new IllegalArgumentException("unimplemented"); 98 } 99 100 /** 101 * @deprecated This method is deprecated and must not be used. SQL {@code 102 * Date} values do not have a seconds component. 103 * @return does not return anything. 104 * @throws IllegalArgumentException 105 * if this method is called. 106 */ 107 @Deprecated 108 @Override getSeconds()109 public int getSeconds() { 110 throw new IllegalArgumentException("unimplemented"); 111 } 112 113 /** 114 * @deprecated This method is deprecated and must not be used. SQL {@code 115 * Date} values do not have an hours component. 116 * @param theHours 117 * the number of hours to set. 118 * @throws IllegalArgumentException 119 * if this method is called. 120 */ 121 @Deprecated 122 @Override setHours(int theHours)123 public void setHours(int theHours) { 124 throw new IllegalArgumentException("unimplemented"); 125 } 126 127 /** 128 * @deprecated This method is deprecated and must not be used. SQL {@code 129 * Date} values do not have a minutes component. 130 * @param theMinutes 131 * the number of minutes to set. 132 * @throws IllegalArgumentException 133 * if this method is called. 134 */ 135 @Deprecated 136 @Override setMinutes(int theMinutes)137 public void setMinutes(int theMinutes) { 138 throw new IllegalArgumentException("unimplemented"); 139 } 140 141 /** 142 * @deprecated This method is deprecated and must not be used. SQL {@code 143 * Date} values do not have a seconds component. 144 * @param theSeconds 145 * the number of seconds to set. 146 * @throws IllegalArgumentException 147 * if this method is called. 148 */ 149 @Deprecated 150 @Override setSeconds(int theSeconds)151 public void setSeconds(int theSeconds) { 152 throw new IllegalArgumentException("unimplemented"); 153 } 154 155 /** 156 * Sets this date to a date supplied as a milliseconds value. The date is 157 * set based on the supplied time value and rounded to zero GMT for that day. 158 * 159 * @param theTime 160 * the time in milliseconds since the Epoch. 161 */ 162 @Override setTime(long theTime)163 public void setTime(long theTime) { 164 /* 165 * Store the Date based on the supplied time after removing any time 166 * elements finer than the day based on zero GMT 167 */ 168 super.setTime(normalizeTime(theTime)); 169 } 170 171 /** 172 * Produces a string representation of the date in SQL format 173 * 174 * @return a string representation of the date in SQL format - {@code "yyyy-MM-dd"}. 175 */ 176 @Override toString()177 public String toString() { 178 StringBuilder sb = new StringBuilder(10); 179 180 format((getYear() + 1900), 4, sb); 181 sb.append('-'); 182 format((getMonth() + 1), 2, sb); 183 sb.append('-'); 184 format(getDate(), 2, sb); 185 186 return sb.toString(); 187 } 188 189 private static final String PADDING = "0000"; 190 191 /* 192 * Private method to format the time 193 */ format(int date, int digits, StringBuilder sb)194 private void format(int date, int digits, StringBuilder sb) { 195 String str = String.valueOf(date); 196 if (digits - str.length() > 0) { 197 sb.append(PADDING.substring(0, digits - str.length())); 198 } 199 sb.append(str); 200 } 201 202 /** 203 * Creates a {@code Date} from a string representation of a date in SQL 204 * format. 205 * 206 * @param dateString 207 * the string representation of a date in SQL format - " {@code yyyy-MM-dd}". 208 * @return the {@code Date} object. 209 * @throws IllegalArgumentException 210 * if the format of the supplied string does not match the SQL 211 * format. 212 */ valueOf(String dateString)213 public static Date valueOf(String dateString) { 214 if (dateString == null) { 215 throw new IllegalArgumentException("dateString == null"); 216 } 217 if (dateString.length() > 10) { 218 // early fail to avoid parsing huge invalid strings 219 throw new IllegalArgumentException(); 220 } 221 222 String[] parts = dateString.split("-"); 223 if (parts.length != 3) { 224 throw new IllegalArgumentException(); 225 } 226 227 int year = Integer.parsePositiveInt(parts[0]); 228 int month = Integer.parsePositiveInt(parts[1]); 229 int day = Integer.parsePositiveInt(parts[2]); 230 return new Date(year - 1900, month - 1, day); 231 } 232 233 /* 234 * Private method which normalizes a Time value, removing all low 235 * significance digits corresponding to milliseconds, seconds, minutes and 236 * hours, so that the returned Time value corresponds to 00:00:00 GMT on a 237 * particular day. 238 */ normalizeTime(long theTime)239 private static long normalizeTime(long theTime) { 240 return theTime; 241 } 242 } 243