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
18package java.sql;
19
20import java.util.Date;
21
22/**
23 * Java representation of an SQL {@code TIME} value. Provides utilities to
24 * format and parse the time's representation as a String in JDBC escape format.
25 */
26public class Time extends Date {
27
28    private static final long serialVersionUID = 8397324403548013681L;
29
30    /**
31     * Constructs a {@code Time} object using the supplied values for <i>Hour</i>,
32     * <i>Minute</i> and <i>Second</i>. The <i>Year</i>, <i>Month</i> and
33     * <i>Day</i> elements of the {@code Time} object are set to the date
34     * of the Epoch (January 1, 1970).
35     * <p>
36     * Any attempt to access the <i>Year</i>, <i>Month</i> or <i>Day</i>
37     * elements of a {@code Time} object will result in an {@code
38     * IllegalArgumentException}.
39     * <p>
40     * The result is undefined if any argument is out of bounds.
41     *
42     * @deprecated Use the constructor {@link #Time(long)} instead.
43     * @param theHour
44     *            a value in the range {@code [0,23]}.
45     * @param theMinute
46     *            a value in the range {@code [0,59]}.
47     * @param theSecond
48     *            a value in the range {@code [0,59]}.
49     */
50    @SuppressWarnings("deprecation")
51    @Deprecated
52    public Time(int theHour, int theMinute, int theSecond) {
53        super(70, 0, 1, theHour, theMinute, theSecond);
54    }
55
56    /**
57     * Constructs a {@code Time} object using a supplied time specified in
58     * milliseconds.
59     *
60     * @param theTime
61     *            a {@code Time} specified in milliseconds since the
62     *            <i>Epoch</i> (January 1st 1970, 00:00:00.000).
63     */
64    public Time(long theTime) {
65        super(theTime);
66    }
67
68    /**
69     * @deprecated This method is deprecated and must not be used. An SQL
70     *             {@code Time} object does not have a date component.
71     * @return does not return anything.
72     * @throws IllegalArgumentException
73     *             if this method is called.
74     */
75    @SuppressWarnings("deprecation")
76    @Deprecated
77    @Override
78    public int getDate() {
79        throw new IllegalArgumentException("unimplemented");
80    }
81
82    /**
83     * @deprecated This method is deprecated and must not be used. An SQL
84     *             {@code Time} object does not have a day component.
85     * @return does not return anything.
86     * @throws IllegalArgumentException
87     *             if this method is called.
88     */
89    @SuppressWarnings("deprecation")
90    @Deprecated
91    @Override
92    public int getDay() {
93        throw new IllegalArgumentException("unimplemented");
94    }
95
96    /**
97     * @deprecated This method is deprecated and must not be used. An SQL
98     *             {@code Time} object does not have a month component.
99     * @return does not return anything.
100     * @throws IllegalArgumentException
101     *             if this method is called.
102     */
103    @SuppressWarnings("deprecation")
104    @Deprecated
105    @Override
106    public int getMonth() {
107        throw new IllegalArgumentException("unimplemented");
108    }
109
110    /**
111     * @deprecated This method is deprecated and must not be used. An SQL
112     *             {@code Time} object does not have a year component.
113     * @return does not return anything.
114     * @throws IllegalArgumentException
115     *             if this method is called.
116     */
117    @SuppressWarnings("deprecation")
118    @Deprecated
119    @Override
120    public int getYear() {
121        throw new IllegalArgumentException("unimplemented");
122    }
123
124    /**
125     * @deprecated This method is deprecated and must not be used. An SQL
126     *             {@code Time} object does not have a date component.
127     * @throws IllegalArgumentException
128     *             if this method is called.
129     */
130    @SuppressWarnings("deprecation")
131    @Deprecated
132    @Override
133    public void setDate(int i) {
134        throw new IllegalArgumentException("unimplemented");
135    }
136
137    /**
138     * @deprecated This method is deprecated and must not be used. An SQL
139     *             {@code Time} object does not have a month component.
140     * @throws IllegalArgumentException
141     *             if this method is called.
142     */
143    @SuppressWarnings("deprecation")
144    @Deprecated
145    @Override
146    public void setMonth(int i) {
147        throw new IllegalArgumentException("unimplemented");
148    }
149
150    /**
151     * @deprecated This method is deprecated and must not be used. An SQL
152     *             {@code Time} object does not have a year component.
153     * @throws IllegalArgumentException
154     *             if this method is called.
155     */
156    @SuppressWarnings("deprecation")
157    @Deprecated
158    @Override
159    public void setYear(int i) {
160        throw new IllegalArgumentException("unimplemented");
161    }
162
163    /**
164     * Sets the time for this {@code Time} object to the supplied milliseconds
165     * value.
166     *
167     * @param time
168     *            A time value expressed as milliseconds since the <i>Epoch</i>.
169     *            Negative values are milliseconds before the Epoch. The Epoch
170     *            is January 1 1970, 00:00:00.000.
171     */
172    @Override
173    public void setTime(long time) {
174        super.setTime(time);
175    }
176
177    /**
178     * Formats the {@code Time} as a String in JDBC escape format: {@code
179     * hh:mm:ss}.
180     *
181     * @return A String representing the {@code Time} value in JDBC escape
182     *         format: {@code HH:mm:ss}
183     */
184    @Override
185    public String toString() {
186        StringBuilder sb = new StringBuilder(8);
187
188        format(getHours(), 2, sb);
189        sb.append(':');
190        format(getMinutes(), 2, sb);
191        sb.append(':');
192        format(getSeconds(), 2, sb);
193
194        return sb.toString();
195    }
196
197    private static final String PADDING = "00";
198
199    /*
200    * Private method to format the time
201    */
202    private void format(int date, int digits, StringBuilder sb) {
203        String str = String.valueOf(date);
204        if (digits - str.length() > 0) {
205            sb.append(PADDING.substring(0, digits - str.length()));
206        }
207        sb.append(str);
208    }
209
210    /**
211     * Creates a {@code Time} object from a string holding a time represented in
212     * JDBC escape format: {@code hh:mm:ss}.
213     * <p>
214     * An exception occurs if the input string does not comply with this format.
215     *
216     * @param timeString
217     *            A String representing the time value in JDBC escape format:
218     *            {@code hh:mm:ss}.
219     * @return The {@code Time} object set to a time corresponding to the given
220     *         time.
221     * @throws IllegalArgumentException
222     *             if the supplied time string is not in JDBC escape format.
223     */
224    public static Time valueOf(String timeString) {
225        if (timeString == null) {
226            throw new IllegalArgumentException("timeString == null");
227        }
228        int firstIndex = timeString.indexOf(':');
229        int secondIndex = timeString.indexOf(':', firstIndex + 1);
230        // secondIndex == -1 means none or only one separator '-' has been
231        // found.
232        // The string is separated into three parts by two separator characters,
233        // if the first or the third part is null string, we should throw
234        // IllegalArgumentException to follow RI
235        if (secondIndex == -1 || firstIndex == 0
236                || secondIndex + 1 == timeString.length()) {
237            throw new IllegalArgumentException();
238        }
239        // parse each part of the string
240        int hour = Integer.parseInt(timeString.substring(0, firstIndex));
241        int minute = Integer.parseInt(timeString.substring(firstIndex + 1,
242                secondIndex));
243        int second = Integer.parseInt(timeString.substring(secondIndex + 1,
244                timeString.length()));
245        return new Time(hour, minute, second);
246    }
247}
248