|
| 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 | +} |
0 commit comments