3636public class Interval implements Serializable {
3737 private final int months ;
3838 private final int days ;
39- private final long microseconds ;
40- private final short nanoFractions ;
39+ private final BigInteger nanoseconds ;
4140
4241 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 ;
4542 public static final long MINUTES_PER_HOUR = 60 ;
4643 public static final long SECONDS_PER_MINUTE = 60 ;
4744 public static final long SECONDS_PER_HOUR = MINUTES_PER_HOUR * SECONDS_PER_MINUTE ;
@@ -51,8 +48,10 @@ public class Interval implements Serializable {
5148 public static final long MICROS_PER_SECOND = MICROS_PER_MILLI * MILLIS_PER_SECOND ;
5249 public static final long MICROS_PER_MINUTE = SECONDS_PER_MINUTE * MICROS_PER_SECOND ;
5350 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 );
5655 public static final BigInteger NANOS_PER_SECOND =
5756 BigInteger .valueOf (MICROS_PER_SECOND * NANOS_PER_MICRO );
5857 public static final BigInteger NANOS_PER_MINUTE =
@@ -61,23 +60,15 @@ public class Interval implements Serializable {
6160 BigInteger .valueOf (MICROS_PER_HOUR * NANOS_PER_MICRO );
6261 public static final Interval ZERO = Interval .builder ().build ();
6362
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` */
6564 private static final Pattern INTERVAL_PATTERN =
6665 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)?)?$" );
6867
69- private Interval (int months , int days , long microseconds , short nanoFractions ) {
68+ private Interval (int months , int days , BigInteger nanoseconds ) {
7069 this .months = months ;
7170 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 ;
8172 }
8273
8374 /** Returns the months component of the interval. */
@@ -90,49 +81,15 @@ public int getDays() {
9081 return days ;
9182 }
9283
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. */
10485 public BigInteger getNanoseconds () {
105- return BigInteger .valueOf (getMicroseconds ())
106- .multiply (BigInteger .valueOf (NANOS_PER_MICRO ))
107- .add (BigInteger .valueOf (getNanoFractions ()));
86+ return nanoseconds ;
10887 }
10988
11089 public static Builder builder () {
11190 return new Builder ();
11291 }
11392
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-
13693 /** Creates an interval with specified number of months. */
13794 public static Interval ofMonths (int months ) {
13895 return builder ().setMonths (months ).build ();
@@ -145,46 +102,31 @@ public static Interval ofDays(int days) {
145102
146103 /** Creates an interval with specified number of seconds. */
147104 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 ();
149106 }
150107
151108 /** Creates an interval with specified number of milliseconds. */
152109 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 ();
154113 }
155114
156115 /** Creates an interval with specified number of microseconds. */
157116 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 ();
159120 }
160121
161122 /** Creates an interval with specified number of nanoseconds. */
162123 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 ();
173125 }
174126
175127 /** 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 ();
188130 }
189131
190132 private static String getNullOrDefault (Matcher matcher , int groupIdx ) {
@@ -204,7 +146,8 @@ public static Interval parseFromString(String interval) {
204146 long days = Long .parseLong (getNullOrDefault (matcher , 3 ).replace ("D" , "" ));
205147 long hours = Long .parseLong (getNullOrDefault (matcher , 5 ).replace ("H" , "" ));
206148 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 ("," , "." ));
208151
209152 long totalMonths = Math .addExact (Math .multiplyExact (years , MONTHS_PER_YEAR ), months );
210153 BigInteger totalNanos = seconds .movePointRight (9 ).toBigInteger ();
@@ -213,15 +156,10 @@ public static Interval parseFromString(String interval) {
213156 totalNanos =
214157 totalNanos .add (BigInteger .valueOf (hours * SECONDS_PER_HOUR ).multiply (NANOS_PER_SECOND ));
215158
216- BigInteger totalMicros = totalNanos .divide (BigInteger .valueOf (NANOS_PER_MICRO ));
217- BigInteger nanoFractions =
218- totalNanos .subtract (totalMicros .multiply (BigInteger .valueOf (NANOS_PER_MICRO )));
219-
220159 return Interval .builder ()
221160 .setMonths (Math .toIntExact (totalMonths ))
222161 .setDays (Math .toIntExact (days ))
223- .setMicroseconds (totalMicros .longValueExact ())
224- .setNanoFractions (nanoFractions .shortValueExact ())
162+ .setNanoseconds (totalNanos )
225163 .build ();
226164 }
227165
@@ -278,7 +216,7 @@ public String toISO8601() {
278216 result .append (String .format ("%s%s" , seconds_sign , seconds_part ));
279217
280218 if (!nanos .equals (zero )) {
281- result .append (String .format (".%09d" , nanos ).replaceAll ("0 +$" , "" ));
219+ result .append (String .format (".%09d" , nanos ).replaceAll ("(0{3}) +$" , "" ));
282220 }
283221 result .append ("S" );
284222 }
@@ -307,17 +245,16 @@ && getDays() == anotherInterval.getDays()
307245 @ Override
308246 public int hashCode () {
309247 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 ();
312250 result = 31 * result + getNanoseconds ().hashCode ();
313251 return result ;
314252 }
315253
316254 public static class Builder {
317255 private int months = 0 ;
318256 private int days = 0 ;
319- private long microseconds = 0 ;
320- private short nanoFractions = 0 ;
257+ private BigInteger nanoseconds = BigInteger .ZERO ;
321258
322259 Builder setMonths (int months ) {
323260 this .months = months ;
@@ -329,26 +266,13 @@ Builder setDays(int days) {
329266 return this ;
330267 }
331268
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 ;
347271 return this ;
348272 }
349273
350274 public Interval build () {
351- return new Interval (months , days , microseconds , nanoFractions );
275+ return new Interval (months , days , nanoseconds );
352276 }
353277 }
354278}
0 commit comments