Before, it would create an invalid date:
IN: scratchpad 2021 1 30 <date> 1 months time+ .
T{ timestamp
{ year 2021 }
{ month 2 }
{ day 30 }
{ gmt-offset T{ duration { hour -6 } } }
}
After, it sets it to the last day of the month:
IN: scratchpad 2021 1 30 <date> 1 months time+ .
T{ timestamp
{ year 2021 }
{ month 2 }
{ day 28 }
{ gmt-offset T{ duration { hour -8 } } }
}
{ t } [
2009 1 29 <date> 1 months time+
- 2009 3 1 <date> =
+ 2009 2 28 <date> =
] unit-test
{ t } [
: microseconds ( x -- duration ) 1000000 / seconds ;
: nanoseconds ( x -- duration ) 1000000000 / seconds ;
+DEFER: days-in-month
+
<PRIVATE
GENERIC: +year ( timestamp x -- timestamp )
12 /rem [ 1 - 12 ] when-zero swap ; inline
M: integer +month
- [ over month>> + months/years [ >>month ] dip +year ] unless-zero ;
+ [
+ over month>> + months/years
+ [ >>month dup days-in-month '[ _ min ] change-day ] dip +year
+ ] unless-zero ;
M: real +month
float>whole-part swapd average-month * +day swap +month ;