36
36
public class Interval implements Serializable {
37
37
private final int months ;
38
38
private final int days ;
39
- private final long microseconds ;
40
- private final short nanoFractions ;
39
+ private final BigInteger nanoseconds ;
41
40
42
41
public static final long MONTHS_PER_YEAR = 12 ;
43
- public static final long DAYS_PER_MONTH = 30 ;
44
- public static final long HOURS_PER_DAY = 24 ;
45
42
public static final long MINUTES_PER_HOUR = 60 ;
46
43
public static final long SECONDS_PER_MINUTE = 60 ;
47
44
public static final long SECONDS_PER_HOUR = MINUTES_PER_HOUR * SECONDS_PER_MINUTE ;
@@ -51,8 +48,10 @@ public class Interval implements Serializable {
51
48
public static final long MICROS_PER_SECOND = MICROS_PER_MILLI * MILLIS_PER_SECOND ;
52
49
public static final long MICROS_PER_MINUTE = SECONDS_PER_MINUTE * MICROS_PER_SECOND ;
53
50
public static final long MICROS_PER_HOUR = SECONDS_PER_HOUR * MICROS_PER_SECOND ;
54
- public static final long MICROS_PER_DAY = HOURS_PER_DAY * MICROS_PER_HOUR ;
55
- public static final long MICROS_PER_MONTH = DAYS_PER_MONTH * MICROS_PER_DAY ;
51
+ public static final BigInteger NANOS_PER_MICROSECOND =
52
+ BigInteger .valueOf (MICROS_PER_SECOND * NANOS_PER_MICRO );
53
+ public static final BigInteger NANOS_PER_MILLISECOND =
54
+ BigInteger .valueOf (MILLIS_PER_SECOND * NANOS_PER_MICRO );
56
55
public static final BigInteger NANOS_PER_SECOND =
57
56
BigInteger .valueOf (MICROS_PER_SECOND * NANOS_PER_MICRO );
58
57
public static final BigInteger NANOS_PER_MINUTE =
@@ -61,23 +60,15 @@ public class Interval implements Serializable {
61
60
BigInteger .valueOf (MICROS_PER_HOUR * NANOS_PER_MICRO );
62
61
public static final Interval ZERO = Interval .builder ().build ();
63
62
64
- /** Regex to ISO8601 formatted interval. `P[n]Y[n]M[n]DT[n]H[n]M[n(. [fraction])]S` */
63
+ /** Regex to parse ISO8601 interval format- `P[n]Y[n]M[n]DT[n]H[n]M[n([.,] [fraction])]S` */
65
64
private static final Pattern INTERVAL_PATTERN =
66
65
Pattern .compile (
67
- "^P(?!$)(-?\\ d+Y)?(-?\\ d+M)?(-?\\ d+D)?(T(?=-?. ?\\ d)(-?\\ d+H)?(-?\\ d+M)?(-?((\\ d+(\\ . \\ d{1,9})?)|(\\ . \\ d{1,9}))S)?)?$" );
66
+ "^P(?!$)(-?\\ d+Y)?(-?\\ d+M)?(-?\\ d+D)?(T(?=-?[.,] ?\\ d)(-?\\ d+H)?(-?\\ d+M)?(-?((\\ d+([.,] \\ d{1,9})?)|([.,] \\ d{1,9}))S)?)?$" );
68
67
69
- private Interval (int months , int days , long microseconds , short nanoFractions ) {
68
+ private Interval (int months , int days , BigInteger nanoseconds ) {
70
69
this .months = months ;
71
70
this .days = days ;
72
-
73
- // Keep nanoFractions between [0, 1000).
74
- if (nanoFractions < 0 ) {
75
- nanoFractions += (short ) NANOS_PER_MICRO ;
76
- microseconds -= 1 ;
77
- }
78
-
79
- this .microseconds = microseconds ;
80
- this .nanoFractions = nanoFractions ;
71
+ this .nanoseconds = nanoseconds ;
81
72
}
82
73
83
74
/** Returns the months component of the interval. */
@@ -90,49 +81,15 @@ public int getDays() {
90
81
return days ;
91
82
}
92
83
93
- /** Returns the microseconds component of the interval. */
94
- public long getMicroseconds () {
95
- return microseconds ;
96
- }
97
-
98
- /** Returns the nanoFractions component of the interval. */
99
- public short getNanoFractions () {
100
- return nanoFractions ;
101
- }
102
-
103
- /** Returns the microseconds and nanoFraction of the Interval combined as nanoseconds. */
84
+ /** Returns the nanoseconds component of the interval. */
104
85
public BigInteger getNanoseconds () {
105
- return BigInteger .valueOf (getMicroseconds ())
106
- .multiply (BigInteger .valueOf (NANOS_PER_MICRO ))
107
- .add (BigInteger .valueOf (getNanoFractions ()));
86
+ return nanoseconds ;
108
87
}
109
88
110
89
public static Builder builder () {
111
90
return new Builder ();
112
91
}
113
92
114
- /**
115
- * Returns the total microseconds represented by the interval. It combines months, days and
116
- * microseconds fields of the interval into microseconds.
117
- */
118
- public long getAsMicroseconds () {
119
- return Math .addExact (
120
- Math .addExact (
121
- Math .multiplyExact (getMonths (), MICROS_PER_MONTH ),
122
- Math .multiplyExact (getDays (), MICROS_PER_DAY )),
123
- getMicroseconds ());
124
- }
125
-
126
- /**
127
- * Returns the total nanoseconds represented by the interval. It combines months, days,
128
- * microseconds and nanoFractions fields of the interval into nanoseconds.
129
- */
130
- public BigInteger getAsNanoseconds () {
131
- return BigInteger .valueOf (getAsMicroseconds ())
132
- .multiply (BigInteger .valueOf (NANOS_PER_MICRO ))
133
- .add (BigInteger .valueOf (getNanoFractions ()));
134
- }
135
-
136
93
/** Creates an interval with specified number of months. */
137
94
public static Interval ofMonths (int months ) {
138
95
return builder ().setMonths (months ).build ();
@@ -145,46 +102,31 @@ public static Interval ofDays(int days) {
145
102
146
103
/** Creates an interval with specified number of seconds. */
147
104
public static Interval ofSeconds (long seconds ) {
148
- return builder ().setMicroseconds ( seconds * MICROS_PER_SECOND ).build ();
105
+ return builder ().setNanoseconds ( BigInteger . valueOf ( seconds ). multiply ( NANOS_PER_SECOND ) ).build ();
149
106
}
150
107
151
108
/** Creates an interval with specified number of milliseconds. */
152
109
public static Interval ofMilliseconds (long milliseconds ) {
153
- return builder ().setMicroseconds (milliseconds * MICROS_PER_MILLI ).build ();
110
+ return builder ()
111
+ .setNanoseconds (BigInteger .valueOf (milliseconds ).multiply (NANOS_PER_MILLISECOND ))
112
+ .build ();
154
113
}
155
114
156
115
/** Creates an interval with specified number of microseconds. */
157
116
public static Interval ofMicroseconds (long micros ) {
158
- return builder ().setMicroseconds (micros ).build ();
117
+ return builder ()
118
+ .setNanoseconds (BigInteger .valueOf (micros ).multiply (NANOS_PER_MICROSECOND ))
119
+ .build ();
159
120
}
160
121
161
122
/** Creates an interval with specified number of nanoseconds. */
162
123
public static Interval ofNanoseconds (@ NotNull BigInteger nanos ) {
163
- BigInteger micros = nanos .divide (BigInteger .valueOf (NANOS_PER_MICRO ));
164
- BigInteger nanoFractions = nanos .subtract (micros .multiply (BigInteger .valueOf (NANOS_PER_MICRO )));
165
- long microsValue = micros .longValueExact ();
166
- short nanoFractionsValue = nanoFractions .shortValueExact ();
167
- return builder ().setMicroseconds (microsValue ).setNanoFractions (nanoFractionsValue ).build ();
168
- }
169
-
170
- /** Creates an interval with specified number of months, days and microseconds. */
171
- public static Interval fromMonthsDaysMicros (int months , int days , long micros ) {
172
- return builder ().setMonths (months ).setDays (days ).setMicroseconds (micros ).build ();
124
+ return builder ().setNanoseconds (nanos ).build ();
173
125
}
174
126
175
127
/** Creates an interval with specified number of months, days and nanoseconds. */
176
- public static Interval fromMonthsDaysNanos (int months , int days , BigInteger nanos ) {
177
- long micros = (nanos .divide (BigInteger .valueOf (NANOS_PER_MICRO ))).longValueExact ();
178
- short nanoFractions =
179
- (nanos .subtract (BigInteger .valueOf (micros ).multiply (BigInteger .valueOf (NANOS_PER_MICRO ))))
180
- .shortValue ();
181
-
182
- return builder ()
183
- .setMonths (months )
184
- .setDays (days )
185
- .setMicroseconds (micros )
186
- .setNanoFractions (nanoFractions )
187
- .build ();
128
+ public static Interval fromMonthsDaysNanos (int months , int days , BigInteger nanoseconds ) {
129
+ return builder ().setMonths (months ).setDays (days ).setNanoseconds (nanoseconds ).build ();
188
130
}
189
131
190
132
private static String getNullOrDefault (Matcher matcher , int groupIdx ) {
@@ -204,7 +146,8 @@ public static Interval parseFromString(String interval) {
204
146
long days = Long .parseLong (getNullOrDefault (matcher , 3 ).replace ("D" , "" ));
205
147
long hours = Long .parseLong (getNullOrDefault (matcher , 5 ).replace ("H" , "" ));
206
148
long minutes = Long .parseLong (getNullOrDefault (matcher , 6 ).replace ("M" , "" ));
207
- BigDecimal seconds = new BigDecimal (getNullOrDefault (matcher , 7 ).replace ("S" , "" ));
149
+ BigDecimal seconds =
150
+ new BigDecimal (getNullOrDefault (matcher , 7 ).replace ("S" , "" ).replace ("," , "." ));
208
151
209
152
long totalMonths = Math .addExact (Math .multiplyExact (years , MONTHS_PER_YEAR ), months );
210
153
BigInteger totalNanos = seconds .movePointRight (9 ).toBigInteger ();
@@ -213,15 +156,10 @@ public static Interval parseFromString(String interval) {
213
156
totalNanos =
214
157
totalNanos .add (BigInteger .valueOf (hours * SECONDS_PER_HOUR ).multiply (NANOS_PER_SECOND ));
215
158
216
- BigInteger totalMicros = totalNanos .divide (BigInteger .valueOf (NANOS_PER_MICRO ));
217
- BigInteger nanoFractions =
218
- totalNanos .subtract (totalMicros .multiply (BigInteger .valueOf (NANOS_PER_MICRO )));
219
-
220
159
return Interval .builder ()
221
160
.setMonths (Math .toIntExact (totalMonths ))
222
161
.setDays (Math .toIntExact (days ))
223
- .setMicroseconds (totalMicros .longValueExact ())
224
- .setNanoFractions (nanoFractions .shortValueExact ())
162
+ .setNanoseconds (totalNanos )
225
163
.build ();
226
164
}
227
165
@@ -278,7 +216,7 @@ public String toISO8601() {
278
216
result .append (String .format ("%s%s" , seconds_sign , seconds_part ));
279
217
280
218
if (!nanos .equals (zero )) {
281
- result .append (String .format (".%09d" , nanos ).replaceAll ("0 +$" , "" ));
219
+ result .append (String .format (".%09d" , nanos ).replaceAll ("(0{3}) +$" , "" ));
282
220
}
283
221
result .append ("S" );
284
222
}
@@ -307,17 +245,16 @@ && getDays() == anotherInterval.getDays()
307
245
@ Override
308
246
public int hashCode () {
309
247
int result = 17 ;
310
- result = 31 * result + Long .valueOf (getMonths ()).hashCode ();
311
- result = 31 * result + Long .valueOf (getDays ()).hashCode ();
248
+ result = 31 * result + Integer .valueOf (getMonths ()).hashCode ();
249
+ result = 31 * result + Integer .valueOf (getDays ()).hashCode ();
312
250
result = 31 * result + getNanoseconds ().hashCode ();
313
251
return result ;
314
252
}
315
253
316
254
public static class Builder {
317
255
private int months = 0 ;
318
256
private int days = 0 ;
319
- private long microseconds = 0 ;
320
- private short nanoFractions = 0 ;
257
+ private BigInteger nanoseconds = BigInteger .ZERO ;
321
258
322
259
Builder setMonths (int months ) {
323
260
this .months = months ;
@@ -329,26 +266,13 @@ Builder setDays(int days) {
329
266
return this ;
330
267
}
331
268
332
- Builder setMicroseconds (long microseconds ) {
333
- this .microseconds = microseconds ;
334
- return this ;
335
- }
336
-
337
- Builder setNanoFractions (short nanoFractions ) {
338
- if (nanoFractions <= -NANOS_PER_MICRO || nanoFractions >= NANOS_PER_MICRO ) {
339
- throw SpannerExceptionFactory .newSpannerException (
340
- ErrorCode .INVALID_ARGUMENT ,
341
- String .format (
342
- "NanoFractions must be between:[-%d, %d]" ,
343
- NANOS_PER_MICRO - 1 , NANOS_PER_MICRO - 1 ));
344
- }
345
-
346
- this .nanoFractions = nanoFractions ;
269
+ Builder setNanoseconds (BigInteger nanoseconds ) {
270
+ this .nanoseconds = nanoseconds ;
347
271
return this ;
348
272
}
349
273
350
274
public Interval build () {
351
- return new Interval (months , days , microseconds , nanoFractions );
275
+ return new Interval (months , days , nanoseconds );
352
276
}
353
277
}
354
278
}
0 commit comments