@@ -9,32 +9,49 @@ import kotlinx.datetime.format.*
99import kotlinx.datetime.internal.*
1010import kotlinx.datetime.serializers.YearMonthIso8601Serializer
1111import kotlinx.serialization.Serializable
12+ import java.time.DateTimeException
13+ import java.time.format.DateTimeFormatterBuilder
14+ import java.time.format.DateTimeParseException
15+ import java.time.format.SignStyle
16+ import java.time.YearMonth as jtYearMonth
1217
1318@Serializable(with = YearMonthIso8601Serializer ::class )
14- public actual class YearMonth
15- public actual constructor (year: Int , month: Int ) : Comparable <YearMonth >, java.io.Serializable {
16- public actual val year: Int = year
17- internal actual val monthNumber: Int = month
18-
19- init {
20- require(month in 1 .. 12 ) { " Month must be in 1..12, but was $month " }
21- require(year in LocalDate .MIN .year.. LocalDate .MAX .year) {
22- " Year $year is out of range: ${LocalDate .MIN .year} ..${LocalDate .MAX .year} "
23- }
24- }
19+ public actual class YearMonth internal constructor(
20+ internal val value : jtYearMonth
21+ ) : Comparable<YearMonth>, java.io.Serializable {
22+ public actual val year: Int get() = value.year
23+ internal actual val monthNumber: Int get() = value.monthValue
2524
26- public actual val month: Month get() = Month (monthNumber )
27- public actual val firstDay: LocalDate get() = onDay( 1 )
28- public actual val lastDay: LocalDate get() = onDay(numberOfDays )
29- public actual val numberOfDays: Int get() = monthNumber.monthLength(isLeapYear(year) )
25+ public actual val month: Month get() = value.month.toKotlinMonth( )
26+ public actual val firstDay: LocalDate get() = LocalDate (value.atDay( 1 ) )
27+ public actual val lastDay: LocalDate get() = LocalDate (value.atEndOfMonth() )
28+ public actual val numberOfDays: Int get() = value.lengthOfMonth( )
3029
3130 // val days: LocalDateRange get() = firstDay..lastDay // no ranges yet
3231
33- public actual constructor (year: Int , month: Month ): this (year, month.number)
32+ public actual constructor (year: Int , month: Int ): this (try {
33+ jtYearMonth.of(year, month)
34+ } catch (e: DateTimeException ) {
35+ throw IllegalArgumentException (e)
36+ })
37+ public actual constructor (year: Int , month: Month ): this (try {
38+ jtYearMonth.of(year, month.toJavaMonth())
39+ } catch (e: DateTimeException ) {
40+ throw IllegalArgumentException (e)
41+ })
3442
3543 public actual companion object {
3644 public actual fun parse (input : CharSequence , format : DateTimeFormat <YearMonth >): YearMonth =
37- format.parse(input)
45+ if (format == = Formats .ISO ) {
46+ try {
47+ val sanitizedInput = removeLeadingZerosFromLongYearFormYearMonth(input.toString())
48+ jtYearMonth.parse(sanitizedInput).let (::YearMonth )
49+ } catch (e: DateTimeParseException ) {
50+ throw DateTimeFormatException (e)
51+ }
52+ } else {
53+ format.parse(input)
54+ }
3855
3956 @Suppress(" FunctionName" )
4057 public actual fun Format (block : DateTimeFormatBuilder .WithYearMonth .() -> Unit ): DateTimeFormat <YearMonth > =
@@ -45,14 +62,13 @@ public actual constructor(year: Int, month: Int) : Comparable<YearMonth>, java.i
4562 public actual val ISO : DateTimeFormat <YearMonth > get() = ISO_YEAR_MONTH
4663 }
4764
48- actual override fun compareTo (other : YearMonth ): Int =
49- compareValuesBy(this , other, YearMonth ::year, YearMonth ::month)
65+ actual override fun compareTo (other : YearMonth ): Int = value.compareTo(other.value)
5066
51- actual override fun toString (): String = Formats . ISO . format(this )
67+ actual override fun toString (): String = isoFormat. format(value )
5268
53- override fun equals (other : Any? ): Boolean = other is YearMonth && year == other.year && month == other.month
69+ override fun equals (other : Any? ): Boolean = this == = other || other is YearMonth && value == other.value
5470
55- override fun hashCode (): Int = year * 31 + month .hashCode()
71+ override fun hashCode (): Int = value .hashCode()
5672
5773 private fun writeReplace (): Any = Ser (Ser .YEAR_MONTH_TAG , this )
5874}
@@ -64,3 +80,11 @@ internal fun YearMonth.Companion.fromEpochMonths(months: Long): YearMonth {
6480 val month = months.mod(12 ) + 1
6581 return YearMonth (year.toInt(), month)
6682}
83+
84+ private val isoFormat by lazy {
85+ DateTimeFormatterBuilder ().parseCaseInsensitive()
86+ .appendValue(java.time.temporal.ChronoField .YEAR , 4 , 10 , SignStyle .EXCEEDS_PAD )
87+ .appendLiteral(' -' )
88+ .appendValue(java.time.temporal.ChronoField .MONTH_OF_YEAR , 2 )
89+ .toFormatter()
90+ }
0 commit comments