@@ -69,6 +69,13 @@ public class Interval implements Serializable {
6969 private Interval (int months , int days , long microseconds , short nanoFractions ) {
7070 this .months = months ;
7171 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+
7279 this .microseconds = microseconds ;
7380 this .nanoFractions = nanoFractions ;
7481 }
@@ -199,7 +206,7 @@ public static Interval parseFromString(String interval) {
199206 long minutes = Long .parseLong (getNullOrDefault (matcher , 6 ).replace ("M" , "" ));
200207 BigDecimal seconds = new BigDecimal (getNullOrDefault (matcher , 7 ).replace ("S" , "" ));
201208
202- long totalMonths = years * MONTHS_PER_YEAR + months ;
209+ long totalMonths = Math . addExact ( Math . multiplyExact ( years , MONTHS_PER_YEAR ), months ) ;
203210 BigInteger totalNanos = seconds .movePointRight (9 ).toBigInteger ();
204211 totalNanos =
205212 totalNanos .add (BigInteger .valueOf (minutes * SECONDS_PER_MINUTE ).multiply (NANOS_PER_SECOND ));
@@ -227,16 +234,16 @@ public String toISO8601() {
227234 StringBuilder result = new StringBuilder ();
228235 result .append ("P" );
229236
230- long months = this .getMonths ();
231- long years = months / MONTHS_PER_YEAR ;
232- months = months - years * MONTHS_PER_YEAR ;
237+ long months_part = this .getMonths ();
238+ long years_part = months_part / MONTHS_PER_YEAR ;
239+ months_part = months_part - years_part * MONTHS_PER_YEAR ;
233240
234- if (years != 0 ) {
235- result .append (String .format ("%dY" , years ));
241+ if (years_part != 0 ) {
242+ result .append (String .format ("%dY" , years_part ));
236243 }
237244
238- if (months != 0 ) {
239- result .append (String .format ("%dM" , months ));
245+ if (months_part != 0 ) {
246+ result .append (String .format ("%dM" , months_part ));
240247 }
241248
242249 if (this .getDays () != 0 ) {
@@ -247,23 +254,33 @@ public String toISO8601() {
247254 BigInteger zero = BigInteger .valueOf (0 );
248255 if (nanos .compareTo (zero ) != 0 ) {
249256 result .append ("T" );
250- BigInteger hours = nanos .divide (NANOS_PER_HOUR );
251-
252- if (hours .compareTo (zero ) != 0 ) {
253- result .append (String .format ("%sH" , hours ));
257+ BigInteger hours_part = nanos .divide (NANOS_PER_HOUR );
258+ nanos = nanos . subtract ( hours_part . multiply ( NANOS_PER_HOUR ));
259+ if (hours_part .compareTo (zero ) != 0 ) {
260+ result .append (String .format ("%sH" , hours_part ));
254261 }
255262
256- nanos = nanos .subtract ( hours . multiply ( NANOS_PER_HOUR ) );
257- BigInteger minutes = nanos .divide ( NANOS_PER_MINUTE );
258- if (minutes .compareTo (zero ) != 0 ) {
259- result .append (String .format ("%sM" , minutes ));
263+ BigInteger minutes_part = nanos .divide ( NANOS_PER_MINUTE );
264+ nanos = nanos .subtract ( minutes_part . multiply ( NANOS_PER_MINUTE ) );
265+ if (minutes_part .compareTo (zero ) != 0 ) {
266+ result .append (String .format ("%sM" , minutes_part ));
260267 }
261268
262- nanos = nanos .subtract (minutes .multiply (NANOS_PER_MINUTE ));
263- BigDecimal seconds = new BigDecimal (nanos ).movePointLeft (9 );
264-
265- if (seconds .compareTo (new BigDecimal (zero )) != 0 ) {
266- result .append (String .format ("%sS" , seconds .stripTrailingZeros ()));
269+ if (!nanos .equals (zero )) {
270+ String seconds_sign = "" ;
271+ if (nanos .signum () == -1 ) {
272+ seconds_sign = "-" ;
273+ nanos = nanos .negate ();
274+ }
275+
276+ BigInteger seconds_part = nanos .divide (NANOS_PER_SECOND );
277+ nanos = nanos .subtract (seconds_part .multiply (NANOS_PER_SECOND ));
278+ result .append (String .format ("%s%s" , seconds_sign , seconds_part ));
279+
280+ if (!nanos .equals (zero )) {
281+ result .append (String .format (".%09d" , nanos ).replaceAll ("0+$" , "" ));
282+ }
283+ result .append ("S" );
267284 }
268285 }
269286
0 commit comments