@@ -9,32 +9,49 @@ import kotlinx.datetime.format.*
9
9
import kotlinx.datetime.internal.*
10
10
import kotlinx.datetime.serializers.YearMonthIso8601Serializer
11
11
import 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
12
17
13
18
@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
25
24
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( )
30
29
31
30
// val days: LocalDateRange get() = firstDay..lastDay // no ranges yet
32
31
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
+ })
34
42
35
43
public actual companion object {
36
44
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
+ }
38
55
39
56
@Suppress(" FunctionName" )
40
57
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
45
62
public actual val ISO : DateTimeFormat <YearMonth > get() = ISO_YEAR_MONTH
46
63
}
47
64
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)
50
66
51
- actual override fun toString (): String = Formats . ISO . format(this )
67
+ actual override fun toString (): String = isoFormat. format(value )
52
68
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
54
70
55
- override fun hashCode (): Int = year * 31 + month .hashCode()
71
+ override fun hashCode (): Int = value .hashCode()
56
72
57
73
private fun writeReplace (): Any = Ser (Ser .YEAR_MONTH_TAG , this )
58
74
}
@@ -64,3 +80,11 @@ internal fun YearMonth.Companion.fromEpochMonths(months: Long): YearMonth {
64
80
val month = months.mod(12 ) + 1
65
81
return YearMonth (year.toInt(), month)
66
82
}
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