1f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License.  You may obtain a copy of the License at
8f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.sql;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.text.ParsePosition;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.text.SimpleDateFormat;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Date;
23142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilsonimport java.util.regex.Pattern;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * A Java representation of the SQL {@code TIMESTAMP} type. It provides the
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * capability of representing the SQL {@code TIMESTAMP} nanosecond value, in
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * addition to the regular date/time value which has millisecond resolution.
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The {@code Timestamp} class consists of a regular date/time value, where only
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the integral seconds value is stored, plus a nanoseconds value where the
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * fractional seconds are stored.
33142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson * <p>
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The addition of the nanosecond value field to the {@code Timestamp} object
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * makes it significantly different from the {@code java.util.Date} object which
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * it extends. Users should be aware that {@code Timestamp} objects are not
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * interchangable with {@code java.util.Date} objects when used outside the
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * confines of the {@code java.sql} package.
39142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson *
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see Date
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see Time
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.util.Date
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class Timestamp extends Date {
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final long serialVersionUID = 2745179027874758501L;
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // The nanoseconds time value of the Timestamp
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int nanos;
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
51143e8c9cf91cfc01c3c91c8e93cad661ec7554eeElliott Hughes    // The regex pattern of yyyy-MM-dd HH:mm:ss
5203c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes    private static final String TIME_FORMAT_REGEX = "[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.*";
53142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a {@code Timestamp} corresponding to the time specified by the
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * supplied values for <i>Year</i>, <i>Month</i>, <i>Date</i>, <i>Hour</i>,
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <i>Minutes</i>, <i>Seconds</i> and <i>Nanoseconds</i>.
58142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson     *
59142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson     * @deprecated Use the constructor {@link #Timestamp(long)}.
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theYear
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            specified as the year minus 1900.
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theMonth
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            specified as an integer in the range [0,11].
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theDate
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            specified as an integer in the range [1,31].
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theHour
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            specified as an integer in the range [0,23].
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theMinute
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            specified as an integer in the range [0,59].
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theSecond
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            specified as an integer in the range [0,59].
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theNano
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            which defines the nanosecond value of the timestamp specified
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            as an integer in the range [0,999'999'999]
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if any of the parameters is out of range.
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @SuppressWarnings("deprecation")
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Deprecated
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Timestamp(int theYear, int theMonth, int theDate, int theHour,
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int theMinute, int theSecond, int theNano)
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IllegalArgumentException {
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(theYear, theMonth, theDate, theHour, theMinute, theSecond);
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (theNano < 0 || theNano > 999999999) {
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException();
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        nanos = theNano;
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a {@code Timestamp} object corresponding to the time represented
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * by a supplied time value.
93f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theTime
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            a time value in the format of milliseconds since the Epoch
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            (January 1 1970 00:00:00.000 GMT).
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Timestamp(long theTime) {
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(theTime);
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Now set the time for this Timestamp object - which deals with the
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * nanosecond value as well as the base time
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
104142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        setTimeImpl(theTime);
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns {@code true} if this timestamp object is later than the supplied
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * timestamp, otherwise returns {@code false}.
110f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theTimestamp
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the timestamp to compare with this timestamp object.
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if this {@code Timestamp} object is later than the
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         supplied timestamp, {@code false} otherwise.
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean after(Timestamp theTimestamp) {
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long thisTime = this.getTime();
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long compareTime = theTimestamp.getTime();
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // If the time value is later, the timestamp is later
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (thisTime > compareTime) {
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return true;
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // If the time value is earlier, the timestamp is not later
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        else if (thisTime < compareTime) {
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Otherwise the time values are equal in which case the nanoseconds
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * value determines whether this timestamp is later...
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        else if (this.getNanos() > theTimestamp.getNanos()) {
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return true;
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns {@code true} if this {@code Timestamp} object is earlier than the
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * supplied timestamp, otherwise returns {@code false}.
142f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theTimestamp
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the timestamp to compare with this {@code Timestamp} object.
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if this {@code Timestamp} object is earlier than the
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         supplied timestamp, {@code false} otherwise.
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean before(Timestamp theTimestamp) {
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long thisTime = this.getTime();
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long compareTime = theTimestamp.getTime();
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // If the time value is later, the timestamp is later
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (thisTime < compareTime) {
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return true;
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // If the time value is earlier, the timestamp is not later
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        else if (thisTime > compareTime) {
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Otherwise the time values are equal in which case the nanoseconds
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * value determines whether this timestamp is later...
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        else if (this.getNanos() < theTimestamp.getNanos()) {
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return true;
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Compares this {@code Timestamp} object with a supplied {@code Timestamp}
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * object.
174f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theObject
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the timestamp to compare with this {@code Timestamp} object,
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            passed as an {@code Object}.
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return <dd>
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <dl>
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         {@code 0} if the two {@code Timestamp} objects are equal in time
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         </dl>
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <dl>
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         a value {@code < 0} if this {@code Timestamp} object is before
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         the supplied {@code Timestamp} and a value
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         </dl>
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <dl>
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         {@code > 0} if this {@code Timestamp} object is after the
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         supplied {@code Timestamp}
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         </dl>
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         </dd>
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws ClassCastException
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the supplied object is not a {@code Timestamp} object.
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int compareTo(Date theObject) throws ClassCastException {
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this.compareTo((Timestamp) theObject);
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Compares this {@code Timestamp} object with a supplied {@code Timestamp}
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * object.
202f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theTimestamp
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the timestamp to compare with this {@code Timestamp} object,
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            passed in as a {@code Timestamp}.
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return one of the following:
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <ul>
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <li>{@code 0}, if the two {@code Timestamp} objects are
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         equal in time</li>
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <li>{@code < 0}, if this {@code Timestamp} object is before the
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         supplied {@code Timestamp}</li>
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         <li> {@code > 0}, if this {@code Timestamp} object is after the
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         supplied {@code Timestamp}</li>
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         </ul>
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int compareTo(Timestamp theTimestamp) {
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int result = super.compareTo(theTimestamp);
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (result == 0) {
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int thisNano = this.getNanos();
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int thatNano = theTimestamp.getNanos();
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (thisNano > thatNano) {
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return 1;
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (thisNano == thatNano) {
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return 0;
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return -1;
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Tests to see if this timestamp is equal to a supplied object.
234f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theObject
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the object to which this timestamp is compared.
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if this {@code Timestamp} object is equal to the
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         supplied {@code Timestamp} object<br>{@code false} if the object
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         is not a {@code Timestamp} object or if the object is a {@code
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         Timestamp} but represents a different instant in time.
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean equals(Object theObject) {
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (theObject instanceof Timestamp) {
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return equals((Timestamp) theObject);
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return false;
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Tests to see if this timestamp is equal to a supplied timestamp.
252f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theTimestamp
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the timestamp to compare with this {@code Timestamp} object,
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            passed as an {@code Object}.
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if this {@code Timestamp} object is equal to the
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         supplied {@code Timestamp} object, {@code false} otherwise.
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean equals(Timestamp theTimestamp) {
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (theTimestamp == null) {
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return (this.getTime() == theTimestamp.getTime())
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                && (this.getNanos() == theTimestamp.getNanos());
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets this {@code Timestamp}'s nanosecond value
269f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return The timestamp's nanosecond value, an integer between 0 and
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         999,999,999.
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int getNanos() {
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return nanos;
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the time represented by this {@code Timestamp} object, as a long
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * value containing the number of milliseconds since the Epoch (January 1
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * 1970, 00:00:00.000 GMT).
281142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson     *
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the number of milliseconds that have passed since January 1 1970,
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         00:00:00.000 GMT.
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public long getTime() {
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long theTime = super.getTime();
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        theTime = theTime + (nanos / 1000000);
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return theTime;
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the nanosecond value for this {@code Timestamp}.
294142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson     *
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param n
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            number of nanoseconds.
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if number of nanoseconds smaller than 0 or greater than
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             999,999,999.
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void setNanos(int n) throws IllegalArgumentException {
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if ((n < 0) || (n > 999999999)) {
30303c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw new IllegalArgumentException("Value out of range");
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        nanos = n;
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the time represented by this {@code Timestamp} object to the
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * supplied time, defined as the number of milliseconds since the Epoch
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * (January 1 1970, 00:00:00.000 GMT).
312142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson     *
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param theTime
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            number of milliseconds since the Epoch (January 1 1970,
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            00:00:00.000 GMT).
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void setTime(long theTime) {
319142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        setTimeImpl(theTime);
320142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson    }
321f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
322142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson    private void setTimeImpl(long theTime) {
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Deal with the nanoseconds value. The supplied time is in milliseconds -
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * so we must extract the milliseconds value and multiply by 1000000 to
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * get nanoseconds. Things are more complex if theTime value is
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * negative, since then the time value is the time before the Epoch but
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * the nanoseconds value of the Timestamp must be positive - so we must
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * take the "raw" milliseconds value and subtract it from 1000 to get to
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * the true nanoseconds value Simultaneously, recalculate the time value
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * to the exact nearest second and reset the Date time value
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int milliseconds = (int) (theTime % 1000);
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        theTime = theTime - milliseconds;
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (milliseconds < 0) {
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            theTime = theTime - 1000;
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            milliseconds = 1000 + milliseconds;
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super.setTime(theTime);
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        setNanos(milliseconds * 1000000);
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the timestamp formatted as a String in the JDBC Timestamp Escape
345143e8c9cf91cfc01c3c91c8e93cad661ec7554eeElliott Hughes     * format, which is {@code "yyyy-MM-dd HH:mm:ss.nnnnnnnnn"}.
346f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return A string representing the instant defined by the {@code
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         Timestamp}, in JDBC Timestamp escape format.
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @SuppressWarnings("deprecation")
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String toString() {
353142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        StringBuilder sb = new StringBuilder(29);
354142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson
355142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        format((getYear() + 1900), 4, sb);
356142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        sb.append('-');
357142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        format((getMonth() + 1), 2, sb);
358142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        sb.append('-');
359142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        format(getDate(), 2, sb);
360142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        sb.append(' ');
361142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        format(getHours(), 2, sb);
362142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        sb.append(':');
363142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        format(getMinutes(), 2, sb);
364142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        sb.append(':');
365142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        format(getSeconds(), 2, sb);
366142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        sb.append('.');
367142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        if (nanos == 0) {
368142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson            sb.append('0');
369142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        } else {
370142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson            format(nanos, 9, sb);
371142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson            while (sb.charAt(sb.length() - 1) == '0') {
372142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson                sb.setLength(sb.length() - 1);
373142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson            }
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
375142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson
376142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        return sb.toString();
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
37903c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes    private static final String PADDING = "000000000";
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
381f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    /*
382f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    * Private method to format the time
383f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    */
384f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    private void format(int date, int digits, StringBuilder sb) {
385142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        String str = String.valueOf(date);
386142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        if (digits - str.length() > 0) {
387142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson            sb.append(PADDING.substring(0, digits - str.length()));
388142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        }
389f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        sb.append(str);
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates a {@code Timestamp} object with a time value equal to the time
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specified by a supplied String holding the time in JDBC timestamp escape
395143e8c9cf91cfc01c3c91c8e93cad661ec7554eeElliott Hughes     * format, which is {@code "yyyy-MM-dd HH:mm:ss.nnnnnnnnn}"
396f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param s
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code String} containing a time in JDBC timestamp escape
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            format.
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return A {@code Timestamp} object with time value as defined by the
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         supplied {@code String}.
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the provided string is {@code null}.
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static Timestamp valueOf(String s) throws IllegalArgumentException {
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (s == null) {
40703c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw new IllegalArgumentException("Argument cannot be null");
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
41003c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        // omit trailing whitespace
411142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        s = s.trim();
412142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        if (!Pattern.matches(TIME_FORMAT_REGEX, s)) {
41303c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw badTimestampString(s);
414142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson        }
415142d526f8bf90fb9bb63c637beb5299f39791f55Jesse Wilson
41603c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ParsePosition pp = new ParsePosition(0);
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * First parse out the yyyy-MM-dd HH:mm:ss component of the String into
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * a Date object using the SimpleDateFormat. This should stop after the
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * seconds value, according to the definition of SimpleDateFormat.parse,
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * with the ParsePosition indicating the index of the "." which should
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * precede the nanoseconds value
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Date theDate;
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            theDate = df.parse(s, pp);
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
43003c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw badTimestampString(s);
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (theDate == null) {
43403c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw badTimestampString(s);
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * If we get here, the Date part of the string was OK - now for the
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * nanoseconds value. Strictly, this requires the remaining part of the
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * String to look like ".nnnnnnnnn". However, we accept anything with a
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * '.' followed by 1 to 9 digits - we also accept nothing (no fractions
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * of a second). Anything else is interpreted as incorrect format which
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * will generate an IllegalArgumentException
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int position = pp.getIndex();
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int remaining = s.length() - position;
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int theNanos;
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (remaining == 0) {
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // First, allow for the case where no fraction of a second is given:
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            theNanos = 0;
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /*
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * Case where fraction of a second is specified: Require 1 character
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * plus the "." in the remaining part of the string...
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
45703c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            if ((s.length() - position) < ".n".length()) {
45803c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes                throw badTimestampString(s);
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /*
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * If we're strict, we should not allow any EXTRA characters after
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * the 9 digits
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
46503c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            if ((s.length() - position) > ".nnnnnnnnn".length()) {
46603c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes                throw badTimestampString(s);
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Require the next character to be a "."
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (s.charAt(position) != '.') {
47103c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes                throw new NumberFormatException("Bad input string format: expected '.' not '" +
4721f07ea29bc2d334c55c16227582a7795b8c117c1Elliott Hughes                        s.charAt(position) + "' in \"" + s + "\"");
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Get the length of the number string - need to account for the '.'
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int nanoLength = s.length() - position - 1;
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Get the 9 characters following the "." as an integer
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String theNanoString = s.substring(position + 1, position + 1
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    + nanoLength);
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /*
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * We must adjust for the cases where the nanos String was not 9
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * characters long by padding out with zeros
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
48403c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            theNanoString = theNanoString + "000000000";
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            theNanoString = theNanoString.substring(0, 9);
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                theNanos = Integer.parseInt(theNanoString);
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (Exception e) {
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // If we get here, the string was not a number
49103c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes                throw badTimestampString(s);
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (theNanos < 0 || theNanos > 999999999) {
49603c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            throw badTimestampString(s);
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Timestamp theTimestamp = new Timestamp(theDate.getTime());
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        theTimestamp.setNanos(theNanos);
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return theTimestamp;
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
504f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
50503c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes    private static IllegalArgumentException badTimestampString(String s) {
50603c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        throw new IllegalArgumentException("Timestamp format must be " +
507143e8c9cf91cfc01c3c91c8e93cad661ec7554eeElliott Hughes                "yyyy-MM-dd HH:mm:ss.fffffffff; was '" + s + "'");
50803c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes    }
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
510