1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.value; |
7 | |
8 | import java.sql.PreparedStatement; |
9 | import java.sql.SQLException; |
10 | import java.sql.Time; |
11 | import org.h2.api.ErrorCode; |
12 | import org.h2.message.DbException; |
13 | import org.h2.util.DateTimeUtils; |
14 | import org.h2.util.MathUtils; |
15 | import org.h2.util.StringUtils; |
16 | |
17 | /** |
18 | * Implementation of the TIME data type. |
19 | */ |
20 | public class ValueTime extends Value { |
21 | |
22 | /** |
23 | * The precision in digits. |
24 | */ |
25 | public static final int PRECISION = 6; |
26 | |
27 | /** |
28 | * The display size of the textual representation of a time. |
29 | * Example: 10:00:00 |
30 | */ |
31 | static final int DISPLAY_SIZE = 8; |
32 | |
33 | private final long nanos; |
34 | |
35 | private ValueTime(long nanos) { |
36 | this.nanos = nanos; |
37 | } |
38 | |
39 | /** |
40 | * Get or create a time value. |
41 | * |
42 | * @param nanos the nanoseconds |
43 | * @return the value |
44 | */ |
45 | public static ValueTime fromNanos(long nanos) { |
46 | return (ValueTime) Value.cache(new ValueTime(nanos)); |
47 | } |
48 | |
49 | /** |
50 | * Get or create a time value for the given time. |
51 | * |
52 | * @param time the time |
53 | * @return the value |
54 | */ |
55 | public static ValueTime get(Time time) { |
56 | return fromNanos(DateTimeUtils.nanosFromDate(time.getTime())); |
57 | } |
58 | |
59 | /** |
60 | * Calculate the time value from a given time in |
61 | * milliseconds in UTC. |
62 | * |
63 | * @param ms the milliseconds |
64 | * @return the value |
65 | */ |
66 | public static ValueTime fromMillis(long ms) { |
67 | return fromNanos(DateTimeUtils.nanosFromDate(ms)); |
68 | } |
69 | |
70 | /** |
71 | * Parse a string to a ValueTime. |
72 | * |
73 | * @param s the string to parse |
74 | * @return the time |
75 | */ |
76 | |
77 | public static ValueTime parse(String s) { |
78 | try { |
79 | return fromNanos(DateTimeUtils.parseTimeNanos(s, 0, s.length(), false)); |
80 | } catch (Exception e) { |
81 | throw DbException.get(ErrorCode.INVALID_DATETIME_CONSTANT_2, |
82 | e, "TIME", s); |
83 | } |
84 | } |
85 | |
86 | public long getNanos() { |
87 | return nanos; |
88 | } |
89 | |
90 | @Override |
91 | public Time getTime() { |
92 | return DateTimeUtils.convertNanoToTime(nanos); |
93 | } |
94 | |
95 | @Override |
96 | public int getType() { |
97 | return Value.TIME; |
98 | } |
99 | |
100 | @Override |
101 | public String getString() { |
102 | StringBuilder buff = new StringBuilder(DISPLAY_SIZE); |
103 | appendTime(buff, nanos, false); |
104 | return buff.toString(); |
105 | } |
106 | |
107 | @Override |
108 | public String getSQL() { |
109 | return "TIME '" + getString() + "'"; |
110 | } |
111 | |
112 | @Override |
113 | public long getPrecision() { |
114 | return PRECISION; |
115 | } |
116 | |
117 | @Override |
118 | public int getDisplaySize() { |
119 | return DISPLAY_SIZE; |
120 | } |
121 | |
122 | @Override |
123 | protected int compareSecure(Value o, CompareMode mode) { |
124 | return MathUtils.compareLong(nanos, ((ValueTime) o).nanos); |
125 | } |
126 | |
127 | @Override |
128 | public boolean equals(Object other) { |
129 | if (this == other) { |
130 | return true; |
131 | } |
132 | return other instanceof ValueTime && nanos == (((ValueTime) other).nanos); |
133 | } |
134 | |
135 | @Override |
136 | public int hashCode() { |
137 | return (int) (nanos ^ (nanos >>> 32)); |
138 | } |
139 | |
140 | @Override |
141 | public Object getObject() { |
142 | return getTime(); |
143 | } |
144 | |
145 | @Override |
146 | public void set(PreparedStatement prep, int parameterIndex) |
147 | throws SQLException { |
148 | prep.setTime(parameterIndex, getTime()); |
149 | } |
150 | |
151 | @Override |
152 | public Value add(Value v) { |
153 | ValueTime t = (ValueTime) v.convertTo(Value.TIME); |
154 | return ValueTime.fromNanos(nanos + t.getNanos()); |
155 | } |
156 | |
157 | @Override |
158 | public Value subtract(Value v) { |
159 | ValueTime t = (ValueTime) v.convertTo(Value.TIME); |
160 | return ValueTime.fromNanos(nanos - t.getNanos()); |
161 | } |
162 | |
163 | @Override |
164 | public Value multiply(Value v) { |
165 | return ValueTime.fromNanos((long) (nanos * v.getDouble())); |
166 | } |
167 | |
168 | @Override |
169 | public Value divide(Value v) { |
170 | return ValueTime.fromNanos((long) (nanos / v.getDouble())); |
171 | } |
172 | |
173 | @Override |
174 | public int getSignum() { |
175 | return Long.signum(nanos); |
176 | } |
177 | |
178 | @Override |
179 | public Value negate() { |
180 | return ValueTime.fromNanos(-nanos); |
181 | } |
182 | |
183 | /** |
184 | * Append a time to the string builder. |
185 | * |
186 | * @param buff the target string builder |
187 | * @param nanos the time in nanoseconds |
188 | * @param alwaysAddMillis whether to always add at least ".0" |
189 | */ |
190 | static void appendTime(StringBuilder buff, long nanos, |
191 | boolean alwaysAddMillis) { |
192 | if (nanos < 0) { |
193 | buff.append('-'); |
194 | nanos = -nanos; |
195 | } |
196 | long ms = nanos / 1000000; |
197 | nanos -= ms * 1000000; |
198 | long s = ms / 1000; |
199 | ms -= s * 1000; |
200 | long m = s / 60; |
201 | s -= m * 60; |
202 | long h = m / 60; |
203 | m -= h * 60; |
204 | StringUtils.appendZeroPadded(buff, 2, h); |
205 | buff.append(':'); |
206 | StringUtils.appendZeroPadded(buff, 2, m); |
207 | buff.append(':'); |
208 | StringUtils.appendZeroPadded(buff, 2, s); |
209 | if (alwaysAddMillis || ms > 0 || nanos > 0) { |
210 | buff.append('.'); |
211 | int start = buff.length(); |
212 | StringUtils.appendZeroPadded(buff, 3, ms); |
213 | if (nanos > 0) { |
214 | StringUtils.appendZeroPadded(buff, 6, nanos); |
215 | } |
216 | for (int i = buff.length() - 1; i > start; i--) { |
217 | if (buff.charAt(i) != '0') { |
218 | break; |
219 | } |
220 | buff.deleteCharAt(i); |
221 | } |
222 | } |
223 | } |
224 | |
225 | } |