Skip to content

Commit c87d8d5

Browse files
committed
Merge pull request scala-js#2128 from alonsodomin/add-month-year
Added initial implementation for MonthDay
2 parents 48de7c7 + a41ffa2 commit c87d8d5

File tree

9 files changed

+402
-42
lines changed

9 files changed

+402
-42
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package java.time
2+
3+
import java.time.chrono.IsoChronology
4+
5+
import scala.scalajs.js
6+
7+
import java.time.temporal._
8+
9+
/** Created by alonsodomin on 22/12/2015. */
10+
final class MonthDay private (month: Int, day: Int)
11+
extends TemporalAccessor with TemporalAdjuster with Comparable[MonthDay]
12+
with java.io.Serializable {
13+
14+
import Preconditions._
15+
import ChronoField._
16+
17+
requireDateTime(month >= 1 && month <= 12, s"Invalid month value: $month")
18+
requireDateTime(day >= 1 && day <= 31, s"Invalid day value: $day")
19+
20+
def isSupported(field: TemporalField): Boolean = field match {
21+
case _: ChronoField => field == DAY_OF_MONTH || field == MONTH_OF_YEAR
22+
case null => false
23+
case _ => field.isSupportedBy(this)
24+
}
25+
26+
override def range(field: TemporalField): ValueRange = field match {
27+
case DAY_OF_MONTH => ValueRange.of(1, getMonth().minLength(), getMonth().maxLength())
28+
case _ => super.range(field)
29+
}
30+
31+
// Implemented by TemporalAccessor
32+
// def get(field: TemporalField): Int
33+
34+
def getLong(field: TemporalField): Long = field match {
35+
case DAY_OF_MONTH => day
36+
case MONTH_OF_YEAR => month
37+
38+
case _: ChronoField =>
39+
throw new UnsupportedTemporalTypeException(s"Field not supported: $field")
40+
41+
case _ => field.getFrom(this)
42+
}
43+
44+
def getMonthValue(): Int = month
45+
46+
def getMonth(): Month = Month.of(month)
47+
48+
def getDayOfMonth(): Int = day
49+
50+
override def equals(other: Any): Boolean = other match {
51+
case that: MonthDay =>
52+
that.getMonthValue == getMonthValue() && that.getDayOfMonth == getDayOfMonth()
53+
54+
case _ => false
55+
}
56+
57+
override def hashCode(): Int = {
58+
val state = Seq(month, day)
59+
state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b)
60+
}
61+
62+
def isValidYear(year: Int): Boolean = {
63+
if (month == 2 && day == 29)
64+
IsoChronology.INSTANCE.isLeapYear(year)
65+
else
66+
true
67+
}
68+
69+
def `with`(month: Month): MonthDay = {
70+
require(month != null, s"'month' can not be null")
71+
if (month == getMonth()) {
72+
this
73+
} else {
74+
val dayOfMonth = js.Math.min(day, month.maxLength())
75+
MonthDay.of(month, dayOfMonth)
76+
}
77+
}
78+
79+
def withMonth(month: Int): MonthDay = `with`(Month.of(month))
80+
81+
def withDayOfMonth(dayOfMonth: Int): MonthDay = {
82+
requireDateTime(dayOfMonth <= getMonth().maxLength(),
83+
s"The day $dayOfMonth is invalid for mont $month")
84+
if (dayOfMonth == day) this
85+
else MonthDay.of(month, dayOfMonth)
86+
}
87+
88+
// Not implemented
89+
// def query[R](query: TemporalQuery[R]): R
90+
91+
def adjustInto(temporal: Temporal): Temporal = {
92+
val temporalWithMonth = temporal.`with`(MONTH_OF_YEAR, month)
93+
val dayOfMonth: Int = js.Math.min(day,
94+
temporalWithMonth.range(DAY_OF_MONTH).getMaximum.toInt)
95+
temporalWithMonth.`with`(DAY_OF_MONTH, dayOfMonth)
96+
}
97+
98+
def atYear(year: Int): LocalDate =
99+
LocalDate.of(year, month, if (isValidYear(year)) day else 28)
100+
101+
def compareTo(that: MonthDay): Int = {
102+
if (month == that.getMonthValue) day - that.getDayOfMonth
103+
else month - that.getMonthValue
104+
}
105+
106+
def isAfter(that: MonthDay): Boolean = compareTo(that) > 0
107+
108+
def isBefore(that: MonthDay): Boolean = compareTo(that) < 0
109+
110+
override def toString(): String = f"--$month%02d-$day%02d"
111+
112+
// Not implemented
113+
// def format(formatter: DateTimeFormatter): String
114+
115+
}
116+
117+
object MonthDay {
118+
119+
import Preconditions._
120+
import ChronoField._
121+
122+
def now(): MonthDay = {
123+
val date = LocalDate.now()
124+
of(date.getMonthValue, date.getDayOfMonth)
125+
}
126+
127+
// Not implemented
128+
// def now(zoneId: ZoneId): MonthDay
129+
130+
// Not implemented
131+
// def now(clock: Clock): MonthDay
132+
133+
def of(month: Month, dayOfMonth: Int): MonthDay = {
134+
if (month == null)
135+
throw new NullPointerException("month")
136+
DAY_OF_MONTH.checkValidValue(dayOfMonth)
137+
requireDateTime(dayOfMonth <= month.maxLength(),
138+
s"The day $dayOfMonth is invalid for month $month")
139+
new MonthDay(month.getValue, dayOfMonth)
140+
}
141+
142+
def of(month: Int, dayOfMonth: Int): MonthDay = {
143+
MONTH_OF_YEAR.checkValidIntValue(month)
144+
of(Month.of(month), dayOfMonth)
145+
}
146+
147+
def from(accessor: TemporalAccessor): MonthDay = accessor match {
148+
case md: MonthDay => md
149+
case _ => of(accessor.get(MONTH_OF_YEAR), accessor.get(DAY_OF_MONTH))
150+
}
151+
152+
// Not implemented
153+
// def parse(text: CharSequence): MonthDay
154+
155+
// Not implemented
156+
// def parse(text: CharSequence, formatter: DateTimeFormatter): MonthDay
157+
158+
}

test-suite/shared/src/test/require-jdk8/org/scalajs/testsuite/javalib/time/DayOfWeekTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import org.junit.Test
77
import org.junit.Assert._
88
import org.scalajs.testsuite.utils.AssertThrows._
99

10-
class DayOfWeekTest extends TemporalAccessorTest {
10+
class DayOfWeekTest extends TemporalAccessorTest[DayOfWeek] {
1111
import DayOfWeek._
1212

1313
val samples = values.toSeq

test-suite/shared/src/test/require-jdk8/org/scalajs/testsuite/javalib/time/LocalDateTest.scala

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import org.junit.Test
88
import org.junit.Assert._
99
import org.scalajs.testsuite.utils.AssertThrows._
1010

11-
class LocalDateTest extends TemporalTest {
11+
class LocalDateTest extends TemporalTest[LocalDate] {
1212

1313
import DateTimeTestUtil._
1414
import LocalDate._
@@ -25,28 +25,20 @@ class LocalDateTest extends TemporalTest {
2525

2626
def isSupported(field: ChronoField): Boolean = field.isDateBased
2727

28-
@Test override def test_range(): Unit = {
29-
for {
30-
d <- samples
31-
field <- ChronoField.values
32-
} {
33-
lazy val expected = field match {
34-
case DAY_OF_MONTH => ValueRange.of(1, d.lengthOfMonth)
35-
case DAY_OF_YEAR => ValueRange.of(1, d.lengthOfYear)
28+
override def expectedRangeFor(accessor: LocalDate, field: TemporalField): ValueRange = {
29+
field match {
30+
case DAY_OF_MONTH => ValueRange.of(1, accessor.lengthOfMonth)
31+
case DAY_OF_YEAR => ValueRange.of(1, accessor.lengthOfYear)
3632

37-
case ALIGNED_WEEK_OF_MONTH =>
38-
ValueRange.of(1, if (d.lengthOfMonth > 28) 5 else 4)
33+
case ALIGNED_WEEK_OF_MONTH =>
34+
ValueRange.of(1, if (accessor.lengthOfMonth > 28) 5 else 4)
3935

40-
case YEAR_OF_ERA =>
41-
val maxYear = if (d.getEra == IsoEra.CE) 999999999 else 1000000000
42-
ValueRange.of(1, maxYear)
36+
case YEAR_OF_ERA =>
37+
val maxYear = if (accessor.getEra == IsoEra.CE) 999999999 else 1000000000
38+
ValueRange.of(1, maxYear)
4339

44-
case _ => field.range
45-
}
46-
if (isSupported(field))
47-
assertEquals(expected, d.range(field))
48-
else
49-
expectThrows(classOf[UnsupportedTemporalTypeException], d.range(field))
40+
case _ =>
41+
super.expectedRangeFor(accessor, field)
5042
}
5143
}
5244

test-suite/shared/src/test/require-jdk8/org/scalajs/testsuite/javalib/time/LocalTimeTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import org.junit.Test
77
import org.junit.Assert._
88
import org.scalajs.testsuite.utils.AssertThrows._
99

10-
class LocalTimeTest extends TemporalTest {
10+
class LocalTimeTest extends TemporalTest[LocalTime] {
1111

1212
import DateTimeTestUtil._
1313
import LocalTime._

0 commit comments

Comments
 (0)