Skip to content

Commit 95c0b1b

Browse files
author
Sagar Agarwal
committed
API changes for Interval Class
1 parent 9873e90 commit 95c0b1b

File tree

8 files changed

+223
-299
lines changed

8 files changed

+223
-299
lines changed

google-cloud-spanner/src/main/java/com/google/cloud/spanner/Interval.java

Lines changed: 31 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,9 @@
3636
public 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
}

google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,7 @@ public void serialization() {
557557
Interval.builder()
558558
.setMonths(100)
559559
.setDays(10)
560-
.setMicroseconds(1000)
561-
.setNanoFractions((short) 10)
560+
.setNanoseconds(BigInteger.valueOf(1000010))
562561
.build()),
563562
Value.interval(null),
564563
Value.stringArray(ImmutableList.of("one", "two")),
@@ -584,7 +583,8 @@ public void serialization() {
584583
Date.fromYearMonthDay(2017, 4, 17), Date.fromYearMonthDay(2017, 5, 18))),
585584
Value.dateArray(null),
586585
Value.intervalArray(
587-
ImmutableList.of(Interval.ZERO, Interval.fromMonthsDaysMicros(10, 20, 30))),
586+
ImmutableList.of(
587+
Interval.ZERO, Interval.fromMonthsDaysNanos(10, 20, BigInteger.valueOf(30000L)))),
588588
Value.intervalArray(null),
589589
Value.struct(s(null, 30)),
590590
Value.struct(structType, null),
@@ -1023,7 +1023,7 @@ public void getDateList() {
10231023
@Test
10241024
public void getIntervalList() {
10251025
List<Interval> intervalList = new ArrayList<>();
1026-
intervalList.add(Interval.fromMonthsDaysMicros(10, 20, 100));
1026+
intervalList.add(Interval.fromMonthsDaysNanos(10, 20, BigInteger.valueOf(100)));
10271027
intervalList.add(Interval.fromMonthsDaysNanos(-10, -20, BigInteger.valueOf(134520)));
10281028

10291029
consumer.onPartialResultSet(

0 commit comments

Comments
 (0)