Skip to content
This repository was archived by the owner on Oct 18, 2023. It is now read-only.

Commit db522be

Browse files
ummelsnicolasstucki
authored andcommitted
Fix #2109: LocalDate.until sometimes returns wrong result
1 parent 750615a commit db522be

File tree

1 file changed

+21
-13
lines changed

1 file changed

+21
-13
lines changed

src/main/scala/java/time/LocalDate.scala

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,20 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
2424

2525
private lazy val dayOfYear =
2626
month.firstDayOfYear(_isLeapYear) + dayOfMonth - 1
27+
2728
private lazy val epochDay = {
2829
val year1 = year - 1970
2930
val daysBeforeYear = daysBeforeYears(Math.floorMod(year1, 400))._2
3031
val offset =
3132
Math.floorDiv(year1, 400).toLong * daysInFourHundredYears
3233
offset + daysBeforeYear + dayOfYear - 1
3334
}
35+
3436
private lazy val dayOfWeek =
3537
Math.floorMod(epochDay + 3, 7).toInt + 1
3638

39+
private def prolepticMonth = year.toLong * 12 + getMonthValue - 1
40+
3741
// Implemented by ChronoLocalDate
3842
// def isSupported(field: TemporalField): Boolean
3943
// def isSupported(unit: TemporalUnit): Boolean
@@ -64,7 +68,7 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
6468
case ALIGNED_WEEK_OF_MONTH => (dayOfMonth - 1) / 7 + 1
6569
case ALIGNED_WEEK_OF_YEAR => (dayOfYear - 1) / 7 + 1
6670
case MONTH_OF_YEAR => getMonthValue
67-
case PROLEPTIC_MONTH => year.toLong * 12 + getMonthValue - 1
71+
case PROLEPTIC_MONTH => prolepticMonth
6872
case YEAR_OF_ERA => if (year > 0) year else 1 - year
6973
case YEAR => year
7074
case ERA => if (year > 0) 1 else 0
@@ -271,8 +275,7 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
271275
case WEEKS => (other.toEpochDay - epochDay) / 7
272276

273277
case MONTHS =>
274-
val dmonths =
275-
(other.getYear - year).toLong * 12 + other.getMonthValue - getMonthValue
278+
val dmonths = other.prolepticMonth - prolepticMonth
276279
if (other.getDayOfMonth < dayOfMonth && dmonths > 0) dmonths - 1
277280
else if (other.getDayOfMonth > dayOfMonth && dmonths < 0) dmonths + 1
278281
else dmonths
@@ -307,17 +310,22 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
307310

308311
def until(end: ChronoLocalDate): Period = {
309312
val other = LocalDate.from(end)
310-
if (equals(other)) Period.ZERO
311-
else if (isBefore(other)) {
312-
val months = until(other, MONTHS)
313-
val date1 = plus(months, MONTHS)
314-
val days = date1.until(other, DAYS).toInt
315-
val years = (months / 12).toInt
316-
val months1 = (months % 12).toInt
317-
Period.of(years, months1, days)
318-
} else {
319-
other.until(this).negated
313+
val dmonths = other.prolepticMonth - prolepticMonth
314+
val ddays = other.getDayOfMonth - dayOfMonth
315+
val corr = {
316+
if (dmonths > 0 && ddays < 0) -1
317+
else if (dmonths < 0 && ddays > 0) 1
318+
else 0
319+
}
320+
val months = dmonths + corr
321+
val days = {
322+
if (corr < 0) plus(months, MONTHS).until(other, DAYS).toInt
323+
else if (corr > 0) ddays - other.lengthOfMonth
324+
else ddays
320325
}
326+
val years = (months / 12).toInt
327+
val months1 = (months % 12).toInt
328+
Period.of(years, months1, days)
321329
}
322330

323331
// Not implemented

0 commit comments

Comments
 (0)