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