Skip to content

Commit 7cd84bf

Browse files
Antonio Alonso Domingueznicolasstucki
authored andcommitted
Add implementation for java.time.Year
1 parent fba96bb commit 7cd84bf

File tree

4 files changed

+653
-12
lines changed

4 files changed

+653
-12
lines changed

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

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
1212
import ChronoUnit._
1313
import LocalDate._
1414

15-
requireDateTime(year >= minYear && year <= maxYear,
15+
requireDateTime(year >= Year.MIN_VALUE && year <= Year.MAX_VALUE,
1616
s"Invalid value for year: $year")
1717

1818
private val _isLeapYear = iso.isLeapYear(year)
@@ -143,12 +143,12 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
143143
LocalDate.of(year, month, day)
144144

145145
case YEAR_OF_ERA =>
146-
requireDateTime(value > 0 && value <= maxYear + 1, msg)
146+
requireDateTime(value > 0 && value <= Year.MAX_VALUE + 1, msg)
147147
if (getEra == IsoEra.CE) withYear(value.toInt)
148148
else withYear(1 - value.toInt)
149149

150150
case YEAR =>
151-
requireDateTime(value >= minYear && value <= maxYear, msg)
151+
requireDateTime(value >= Year.MIN_VALUE && value <= Year.MAX_VALUE, msg)
152152
withYear(value.toInt)
153153

154154
case ERA =>
@@ -215,7 +215,7 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
215215

216216
def plusYears(years: Long): LocalDate = {
217217
val year1 = year + years
218-
requireDateTime(year1 >= minYear && year1 <= maxYear,
218+
requireDateTime(year1 >= Year.MIN_VALUE && year1 <= Year.MAX_VALUE,
219219
s"Invalid value for year: $year1")
220220
val leap = iso.isLeapYear(year1)
221221
val day1 =
@@ -228,7 +228,7 @@ final class LocalDate private (year: Int, month: Month, dayOfMonth: Int)
228228
val month1 = getMonthValue + Math.floorMod(months, 12).toInt
229229
val year1 = year + Math.floorDiv(months, 12) +
230230
(if (month1 > 12) 1 else 0)
231-
requireDateTime(year1 >= minYear && year1 <= maxYear,
231+
requireDateTime(year1 >= Year.MIN_VALUE && year1 <= Year.MAX_VALUE,
232232
s"Invalid value for year: $year1")
233233
val month2 = Month.of(if (month1 > 12) month1 - 12 else month1)
234234
val day = dayOfMonth min month2.length(iso.isLeapYear(year1))
@@ -382,12 +382,9 @@ object LocalDate {
382382
}.take(400).toVector
383383

384384
private final val daysInFourHundredYears = 146097
385-
private final val minYear = -999999999
386-
private final val maxYear = 999999999
387385

388-
final val MIN = new LocalDate(minYear, Month.JANUARY, 1)
389-
390-
final val MAX = new LocalDate(maxYear, Month.DECEMBER, 31)
386+
final val MIN = new LocalDate(Year.MIN_VALUE, Month.JANUARY, 1)
387+
final val MAX = new LocalDate(Year.MAX_VALUE, Month.DECEMBER, 31)
391388

392389
def now(): LocalDate = {
393390
val d = new js.Date()
@@ -420,7 +417,7 @@ object LocalDate {
420417
val rem = Math.floorMod(epochDay, daysInFourHundredYears).toInt
421418
val (year1, start) = daysBeforeYears.takeWhile(_._2 <= rem).last
422419
val year2 = year1 + quot * 400
423-
requireDateTime(year2 >= minYear && year2 <= maxYear,
420+
requireDateTime(year2 >= Year.MIN_VALUE && year2 <= Year.MAX_VALUE,
424421
s"Invalid value for year: $year2")
425422
val dayOfYear = rem - start + 1
426423
LocalDate.ofYearDay(year2.toInt, dayOfYear.toInt)

src/main/scala/java/time/Year.scala

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
package java.time
2+
3+
import java.time.chrono.{Chronology, IsoChronology}
4+
import java.time.temporal._
5+
6+
/** Created by alonsodomin on 24/12/2015. */
7+
final class Year private (year: Int)
8+
extends TemporalAccessor with Temporal with TemporalAdjuster with Comparable[Year]
9+
with java.io.Serializable {
10+
11+
import Preconditions._
12+
import Year._
13+
import ChronoField._
14+
import ChronoUnit._
15+
16+
requireDateTime(year >= MIN_VALUE && year <= MAX_VALUE, s"Invalid year value: $year")
17+
18+
def getValue(): Int = year
19+
20+
def isSupported(field: TemporalField): Boolean = field match {
21+
case _: ChronoField => field == YEAR_OF_ERA || field == YEAR || field == ERA
22+
case null => false
23+
case _ => field.isSupportedBy(this)
24+
}
25+
26+
def isSupported(unit: TemporalUnit): Boolean = unit match {
27+
case _: ChronoUnit =>
28+
unit == YEARS || unit == DECADES || unit == CENTURIES ||
29+
unit == MILLENNIA || unit == ERAS
30+
31+
case null => false
32+
case _ => unit.isSupportedBy(this)
33+
}
34+
35+
override def range(field: TemporalField): ValueRange = field match {
36+
case YEAR_OF_ERA =>
37+
if (year <= 0) ValueRange.of(1, MAX_VALUE + 1)
38+
else ValueRange.of(1, MAX_VALUE)
39+
40+
case _ => super.range(field)
41+
}
42+
43+
override def get(field: TemporalField): Int = field match {
44+
case YEAR_OF_ERA => if (year < 1) 1 - year else year
45+
case YEAR => year
46+
case ERA => if (year < 1) 0 else 1
47+
48+
case _: ChronoField =>
49+
throw new UnsupportedTemporalTypeException(s"Unsupported field: $field")
50+
}
51+
52+
def getLong(field: TemporalField): Long = field match {
53+
case field: ChronoField => get(field)
54+
case _ => field.getFrom(this)
55+
}
56+
57+
def isLeap(): Boolean = Year.isLeap(year)
58+
59+
def isValidMonthDay(monthDay: MonthDay): Boolean =
60+
monthDay.isValidYear(year)
61+
62+
def length(): Int = if (isLeap) 366 else 365
63+
64+
def `with`(field: TemporalField, value: Long): Year = {
65+
def withYear(newYear: Int): Year = {
66+
if (year != newYear) Year.of(newYear)
67+
else this
68+
}
69+
70+
field match {
71+
case YEAR_OF_ERA =>
72+
val yearOfEra = YEAR_OF_ERA.checkValidIntValue(value)
73+
val newYear = if (year < 1) 1 - yearOfEra else yearOfEra
74+
withYear(newYear)
75+
76+
case YEAR =>
77+
withYear(YEAR.checkValidIntValue(value))
78+
79+
case ERA =>
80+
requireDateTime(value == 0 || value == 1,
81+
s"Invalid value for field $field: $value")
82+
val era = get(ERA)
83+
if (era != value) Year.of(1 - year)
84+
else this
85+
86+
case _: ChronoField =>
87+
throw new UnsupportedTemporalTypeException(s"Unsupported field: $field")
88+
89+
case _ =>
90+
field.adjustInto(this, value)
91+
}
92+
}
93+
94+
def plus(amount: Long, unit: TemporalUnit): Year = unit match {
95+
case YEARS => plusYears(amount)
96+
case DECADES => plusYears(Math.multiplyExact(amount, 10))
97+
case CENTURIES => plusYears(Math.multiplyExact(amount, 100))
98+
case MILLENNIA => plusYears(Math.multiplyExact(amount, 1000))
99+
100+
case ERAS =>
101+
val era = get(ERA)
102+
`with`(ERA, Math.addExact(era, amount))
103+
104+
case _: ChronoUnit =>
105+
throw new UnsupportedTemporalTypeException(s"Unsupported unit: $unit")
106+
107+
case _ =>
108+
unit.addTo(this, amount)
109+
}
110+
111+
def plusYears(amount: Long): Year = {
112+
if (amount == 0) {
113+
this
114+
} else {
115+
val newYear = year + amount
116+
Year.of(YEAR.checkValidIntValue(newYear))
117+
}
118+
}
119+
120+
override def minus(amount: Long, unit: TemporalUnit): Year = {
121+
if (amount != Long.MinValue) plus(-amount, unit)
122+
else plus(Long.MaxValue, unit).plus(1, unit)
123+
}
124+
125+
def minusYears(amount: Long): Year = minus(amount, YEARS)
126+
127+
// Not implemented
128+
// def query[R](query: TemporalQuery[R]): R
129+
130+
def adjustInto(temporal: Temporal): Temporal =
131+
temporal.`with`(YEAR, year)
132+
133+
def until(end: Temporal, unit: TemporalUnit): Long = {
134+
val other = Year.from(end)
135+
val yearsDiff: Int = other.getValue - year
136+
137+
unit match {
138+
case YEARS => yearsDiff
139+
case DECADES => yearsDiff / 10
140+
case CENTURIES => yearsDiff / 100
141+
case MILLENNIA => yearsDiff / 1000
142+
case ERAS => other.get(ERA) - get(ERA)
143+
144+
case _: ChronoUnit =>
145+
throw new UnsupportedTemporalTypeException(s"Unsupported unit: $unit")
146+
147+
case _ => unit.between(this, other)
148+
}
149+
}
150+
151+
// Not implemented
152+
// def format(formatter: DateTimeFormatter): String
153+
154+
def atDay(dayOfYear: Int): LocalDate =
155+
LocalDate.ofYearDay(year, dayOfYear)
156+
157+
// TODO
158+
// def atMonth(month: Month): YearMonth = YearMonth.of(year, month)
159+
160+
// TODO
161+
// def atMonth(month: Int): YearMonth = YearMonth.of(year, month)
162+
163+
def atMonthDay(monthDay: MonthDay): LocalDate = monthDay.atYear(year)
164+
165+
def compareTo(other: Year): Int = year - other.getValue
166+
167+
def isAfter(other: Year): Boolean = compareTo(other) > 0
168+
169+
def isBefore(other: Year): Boolean = compareTo(other) < 0
170+
171+
override def equals(other: Any): Boolean = other match {
172+
case that: Year => year == that.getValue
173+
case _ => false
174+
}
175+
176+
override def hashCode(): Int = year.hashCode()
177+
178+
override def toString: String = year.toString
179+
180+
}
181+
182+
object Year {
183+
import ChronoField._
184+
185+
final val MIN_VALUE: Int = -999999999
186+
final val MAX_VALUE: Int = 999999999
187+
188+
private final val iso = IsoChronology.INSTANCE
189+
190+
def now(): Year = from(LocalDate.now())
191+
192+
// Not implemented
193+
// def now(zone: ZoneId): Year
194+
// def now(clock: Clock): Year
195+
196+
def of(year: Int): Year = {
197+
YEAR.checkValidIntValue(year)
198+
new Year(year)
199+
}
200+
201+
def from(temporal: TemporalAccessor): Year = temporal match {
202+
case temporal: Year => temporal
203+
case _ => of(temporal.get(YEAR))
204+
}
205+
206+
// Not implemented
207+
// def parse(text: CharSequence): Year
208+
// def parse(text: CharSequence, formatter: DateTimeFormatter): Year
209+
210+
def isLeap(year: Long): Boolean = iso.isLeapYear(year)
211+
212+
}

src/main/scala/java/time/temporal/ChronoField.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package java.time.temporal
22

3+
import java.time.Year
4+
35
final class ChronoField private (name: String, ordinal: Int,
46
_range: ValueRange, baseUnit: ChronoUnit, rangeUnit: ChronoUnit, flags: Int)
57
extends Enum[ChronoField](name, ordinal) with TemporalField {
@@ -123,7 +125,7 @@ object ChronoField {
123125
ValueRange.of(1, 999999999, 1000000000), YEARS, ERAS, isDateBasedFlag)
124126

125127
final val YEAR = new ChronoField("Year", 26,
126-
ValueRange.of(-999999999, 999999999), YEARS, FOREVER, isDateBasedFlag)
128+
ValueRange.of(Year.MIN_VALUE, Year.MAX_VALUE), YEARS, FOREVER, isDateBasedFlag)
127129

128130
final val ERA = new ChronoField("Era", 27, ValueRange.of(0, 1), ERAS, FOREVER,
129131
isDateBasedFlag)

0 commit comments

Comments
 (0)