@@ -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