-
Notifications
You must be signed in to change notification settings - Fork 7
Use more specific calendar-dependent operations in Until, Add, and ToISO #69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
ca08cb5
to
d423175
Compare
a72de40
to
12195b9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial review up til NonISODateSurpasses
<emu-clause id="sec-temporal-parsemonthcode" type="implementation-defined abstract operation"> | ||
<h1> | ||
ParseMonthCode ( | ||
_monthCode_: a String, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think you can say something like a String which is a valid month code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was considering introducing a type for it. I say "valid month code" in the description. Happy for editorial advice from @ptomato or others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree we should narrow down the possible set of month codes (which we already have) and define that (essentially mark the existing definition) as the term "month code" or "month code type" akin to "calendar type" that we utilize from upstream Temporal. I don't think it's a bad idea to place this definition in the Temporal spec since it can be utilized in the upstream AO https://tc39.es/proposal-temporal/#sec-temporal-tomonthcode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you like me to add the definitions in this PR or can I do it in another PR? I'd also like to define terms like "arithmetical month"
spec.emu
Outdated
1. Let _monthsBefore_ be 0. | ||
1. Let _number_ be 1. | ||
1. Let _isLeap_ be *false*. | ||
1. Repeat, while _number_ ≤ 12, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
observation/praise: this will work for calendars that have multiple leap months in a year, like a hindu lunisolar calendar (especially a purnimanta calendar, where you are required to model fortnights as months since otherwise your leap months get "split" in half)
Implementors will likely optimize this to not need a for loop and instead query something like "does this year have a leap month and if so which month is it" which is potentially a useful other way of writing this spec text to avoid the loop. It falls within the type of thing that is possible to leave to implementors without confusion, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make it support Hindu (although Hindu is not yet in the spec), should I start _number_
at 0 in order to catch M00L?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered "does this year have a leap month and if so which month is it" but that is a more confusing calendar-dependent behavior, whereas "does year contain this particular month code" is more clear. I expect implementations to implement it as they see fit so long as the behaviors match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not spend too much time thinking about the nitty gritty specifics of Hindu until we have a concrete proposal on the table since there are multiple ways to model ir. I don't think it needs an M00L, but it might. The fact that Hindu days can be "merged" is probably going to be the biggest problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make it support Hindu (although Hindu is not yet in the spec), should I start
_number_
at 0 in order to catch M00L?
Yes, I think the algorithm should be able to handle M00L. Ignoring that possibility just creates future liability. And likewise for hard-coding 12 rather than something more clear like HighestMonthNumberForCalendarYear(calendar, year).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I resolved the month 0 / month 13 issue by adding an assertion in 6abbe6e
Was there anything else actionable from this thread?
spec.emu
Outdated
1. Set _monthCode_ to *"M06"*. | ||
1. Else if _isLeap1_ is *false* and _isLeap2_ is *true*, then | ||
1. If _monthCode_ is *"M06"*, then | ||
1. Set _monthCode_ to *"M05L"*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interesting choice; any particular reason behind it?
Not that I dislike it, but I would have thought keeping M06 as M06 would be clearer since Adar II is supposed to be the "regular" Adar
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please explain the intent of these steps with a "NOTE: The following steps…".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deleted this AO in 6abbe6e and replaced it with a table reference
|
||
<emu-clause id="sec-temporal-balancenonisodate" type="implementation-defined abstract operation"> | ||
<h1> | ||
BalanceNonISODate ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
praise: well written.
suggestion: I suppose this could be refactored into BalanceNonISOYearMonth and BalanceNonISODate to avoid the duplication of the resolvedMonth
balancing. But I don't know if that's better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I want to highlight that this logic is novel to Intl Era Month Code; the equivalent ISO operation in Temporal does month balancing with divrem and then goes to Epoch Days for weeks and days.
I think I prefer keeping it in one AO because it is easier to see how month and day balancing interact.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed around the AOs in 6abbe6e
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
spec.emu
Outdated
|
||
<emu-clause id="sec-temporal-regulatenonisoyearmonth" type="implementation-defined abstract operation"> | ||
<h1> | ||
RegulateNonISOYearMonth ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: I find this naming a bit confusing. In the original spec, "Regulate" is about applying overflow options, but here it's really doing a type of addition operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah; my mental model was "regulate" means "if overflow, constrain the least significant unit" and "balance" means "if overflow, roll over the smallest unit into higher units". This AO does the regulating behavior, so that's how I named it. I'm happy to explore other naming options, or refactor exactly what role the AO serves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ConstrainNonISOYearMonth
sounds good as well but yeah don't mind Regulate either since it's consistent with upstream
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I replaced RegulateNonISOYearMonth
with ConstrainMonthCodeToArithmeticalMonth
in 6abbe6e
spec.emu
Outdated
<p>It performs the following steps when called:</p> | ||
<emu-alg> | ||
1. Let _parts_ be CalendarISOToDate(_calendar_, _baseDate_). | ||
1. Let _yearMonth_ be RegulateNonISOYearMonth(_calendar_, _parts_.[[Year]], _parts_.[[MonthCode]], _years_). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought related to previous: My immediate response to this was "shouldn't the result of CalendarISOToDate
already be regulated" before I remembered that RegulateNonISOYearMonth
also does some year addition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I acknowledge that this was confusing, and it should be fixed in 6abbe6e
1. Else, | ||
1. Let _y1_ be _endOfMonth_.[[Year]]. | ||
1. Let _m1_ be _endOfMonth_.[[Month]]. | ||
1. Let _d1_ be _baseDay_. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: this doesn't clamp, but the previous one does. Is that a discrepancy we are okay with?
This means Surpasses(calendar, sign = 1, baseDate, isoDate2, years, months, weeks = 0, days = 0)
could be true whilst Surpasses(calendar, sign = 1, baseDate, isoDate2, years, months, weels = 0, days = 1)
could be false if, say, the other numbers were something like "add 1 month to to January 31st" since with days = 1 it will get normalized to Feb 28 + 1 (assume non leap year) but with days = 0 it'll get normalized to Feb 32.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This matches the behavior in tc39/proposal-temporal#3138.
The AO has one call site, Until
, which wants a true
return value for things like "march 31 + 1 month ?< april 30", since the Temporal Addition Algorithm only regulates to the end of the month immediately before adding weeks and days.
I could have written this AO with an extra argument, regulationBehavior
or something, or even as a completely different AO, but I realized that checking weeks == 0 and days == 0
was equivalent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, okay. I don't fully understand the Until argument but I see there is a reason. Perhaps worth including a note.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this thread resolved?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very minor points overall. Looks good!
Implementing this efficiently may be tricky but that's fine; at least now we have more concrete guidance for behavior
spec.emu
Outdated
1. Add _duration_.[[Months]] to _calendarDate_, balancing _calendarDate_ if it goes over a year boundary. | ||
1. If the date described by _calendarDate_ does not exist, then | ||
1. Let _parts_ be CalendarISOToDate(_calendar_, _isoDate_). | ||
1. Let _yearMonth_ be RegulateNonISOYearMonth(_calendar_, _parts_.[[Year]], _parts_.[[MonthCode]], _duration_.[[Years]]). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
observation: so we don't end up doing anything about the overflow
with months, only with day
question: is there a reason we should try to be more consistent? is there a reason we should not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to weigh in on #56. I took the position that overflow
should be applied consistently for overflowed days only, and not have an extra error case in lunisolar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, that makes sense, because day is a final thing whereas months is still incomplete.
Might be worth having a note here to that effect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, hold on, but the day here is partial as well; we have not yet finished adding.
But I guess that's somewhat the behavior you ask for with REJECT.
1. Update _calendarDate_.[[Month]] accordingly. | ||
1. Add _duration_.[[Months]] to _calendarDate_, balancing _calendarDate_ if it goes over a year boundary. | ||
1. If the date described by _calendarDate_ does not exist, then | ||
1. Let _parts_ be CalendarISOToDate(_calendar_, _isoDate_). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
praise: I appreciate the simplicity of this AO
A bit more commentary on my choices of AOs:
|
To put Add and Until's algorithm in words:
The key difference with non-ISO is step 2. ISO doesn't need to constrain to a valid year/month because all months are valid in all years. This also feeds into #56. Is it more consistent or less consistent for non-ISO to reject when constraining year/month? I took the position that non-ISO is better off rejecting on step 4 only. I think it's a valid position that it should reject on both steps 2 and 4. However, maybe there should be a third option in the enum to allow for either behavior. |
spec.emu
Outdated
_calendar_: a calendar type that is not *"iso8601"*, | ||
_year_: an integer, | ||
_monthCode_: a String, | ||
): an integer or ~invalid~ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An integer result is always positive, right?
): an integer or ~invalid~ | |
): a positive integer or ~invalid~ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 3dacca7
spec.emu
Outdated
1. If _calendar_ is not *"chinese"*, *"dangi"*, or *"hebrew"*, then | ||
1. Return _monthCodeParts_.[[Number]]. | ||
1. Let _monthsBefore_ be 0. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This kind of implicit assumption that all possible exceptions have been enumerated makes me uncomfortable. I'd like an assertion about what calendar must be if it is not "chinese", "dangi", or "hebrew", or better yet, representation of the underlying concept:
1. If _calendar_ is not *"chinese"*, *"dangi"*, or *"hebrew"*, then | |
1. Return _monthCodeParts_.[[Number]]. | |
1. Let _monthsBefore_ be 0. | |
1. If CalendarHasLeapMonths(_calendar_) is *false*, then | |
1. Return _monthCodeParts_.[[Number]]. | |
1. Let _monthsBefore_ be 0. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In 6abbe6e, I am checking for leap months by the presence of a new column in #table-additional-month-codes
.
spec.emu
Outdated
1. Let _number_ be 1. | ||
1. Let _isLeap_ be *false*. | ||
1. Repeat, while _number_ ≤ 12, | ||
1. If _calendar_ contains CreateMonthCode(_number_, _isLeap_) in _year_, according to a calendar-dependent algorithm, then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this have a named operation?
1. If _calendar_ contains CreateMonthCode(_number_, _isLeap_) in _year_, according to a calendar-dependent algorithm, then | |
1. If IsValidYearMonthCodeForCalendar(_calendar_, _year_, CreateMonthCode(_number_, _isLeap_)) is *true*, then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, except the AO that we're currently inside is also how I would implement IsValidYearMonthCodeForCalendar
... in fact this AO was called that in an earlier draft before I made it start returning an integer. I only need the sub-AO in order to determine if it is a valid leap month.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm more comfortable with the sub-AO than this kind of handwavy algorithm step. Or alternatively, with just making the entirety of MonthCodeToArithmeticalMonth calendar-dependent rather than trivially wrapping a calendar-dependent core.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a standalone AO YearContainsMonthCode
in 6abbe6e.
spec.emu
Outdated
1. Let _monthsBefore_ be 0. | ||
1. Let _number_ be 1. | ||
1. Let _isLeap_ be *false*. | ||
1. Repeat, while _number_ ≤ 12, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make it support Hindu (although Hindu is not yet in the spec), should I start
_number_
at 0 in order to catch M00L?
Yes, I think the algorithm should be able to handle M00L. Ignoring that possibility just creates future liability. And likewise for hard-coding 12 rather than something more clear like HighestMonthNumberForCalendarYear(calendar, year).
spec.emu
Outdated
1. Repeat, while _number_ ≤ 12, | ||
1. If _calendar_ contains CreateMonthCode(_number_, _isLeap_) in _year_, according to a calendar-dependent algorithm, then | ||
1. Set _monthsBefore_ to _monthsBefore_ + 1. | ||
1. If _monthCodeParts_.[[Number]] is _number_ and _monthCodeParts.[[IsLeap]] is _isLeap_, then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. If _monthCodeParts_.[[Number]] is _number_ and _monthCodeParts.[[IsLeap]] is _isLeap_, then | |
1. If _monthCodeParts_.[[Number]] is _number_ and _monthCodeParts_.[[IsLeap]] is _isLeap_, then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it to check for month code string equality instead, in 6abbe6e.
spec.emu
Outdated
1. Set _monthCode_ to *"M06"*. | ||
1. Else if _isLeap1_ is *false* and _isLeap2_ is *true*, then | ||
1. If _monthCode_ is *"M06"*, then | ||
1. Set _monthCode_ to *"M05L"*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please explain the intent of these steps with a "NOTE: The following steps…".
spec.emu
Outdated
1. Let _month_ be MonthCodeToArithmeticalMonth(_calendar_, _monthCode_, _y2_). | ||
1. Assert: _month_ is not ~invalid~. | ||
1. Else, | ||
1. Let _month_ be ParseMonthCode(_monthCode_).[[Number]]. | ||
1. Return the Record { [[Year]]: _y2_, [[Month]]: _month_ }. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. Let _month_ be MonthCodeToArithmeticalMonth(_calendar_, _monthCode_, _y2_). | |
1. Assert: _month_ is not ~invalid~. | |
1. Else, | |
1. Let _month_ be ParseMonthCode(_monthCode_).[[Number]]. | |
1. Return the Record { [[Year]]: _y2_, [[Month]]: _month_ }. | |
1. Let _arithmeticalMonth_ be MonthCodeToArithmeticalMonth(_calendar_, _monthCode_, _y2_). | |
1. Assert: _arithmeticalMonth_ is not ~invalid~. | |
1. Else, | |
1. Let _arithmeticalMonth_ be ParseMonthCode(_monthCode_).[[Number]]. | |
1. Return the Record { [[Year]]: _y2_, [[Month]]: _arithmeticalMonth_ }. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code was deleted in 6abbe6e
spec.emu
Outdated
_month_: an integer, | ||
_day_: an integer, | ||
): a Record with fields [[Year]] (an integer), [[Month]] (an integer), and [[Day]] (an integer) | ||
</h1> | ||
<dl class="header"> | ||
<dt>description</dt> | ||
<dd> | ||
It interprets the given _year_ and potentially out-of-range _month_ and _day_ as arithmetical values in the given _calendar_ and returns in-range values by overflowing out-of-range _month_ or _day_ values into the next-highest unit. | ||
This date may be outside the range given by ISODateTimeWithinLimits. | ||
</dd> | ||
</dl> | ||
<p>It performs the following steps when called:</p> | ||
<emu-alg> | ||
1. Let _resolvedYear_ be _year_. | ||
1. Let _resolvedMonth_ be _month_. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_month_: an integer, | |
_day_: an integer, | |
): a Record with fields [[Year]] (an integer), [[Month]] (an integer), and [[Day]] (an integer) | |
</h1> | |
<dl class="header"> | |
<dt>description</dt> | |
<dd> | |
It interprets the given _year_ and potentially out-of-range _month_ and _day_ as arithmetical values in the given _calendar_ and returns in-range values by overflowing out-of-range _month_ or _day_ values into the next-highest unit. | |
This date may be outside the range given by ISODateTimeWithinLimits. | |
</dd> | |
</dl> | |
<p>It performs the following steps when called:</p> | |
<emu-alg> | |
1. Let _resolvedYear_ be _year_. | |
1. Let _resolvedMonth_ be _month_. | |
_arithmeticalMonth_: an integer, | |
_day_: an integer, | |
): a Record with fields [[Year]] (an integer), [[Month]] (an integer), and [[Day]] (an integer) | |
</h1> | |
<dl class="header"> | |
<dt>description</dt> | |
<dd> | |
It interprets the given _year_ and potentially out-of-range _arithmeticalMonth_ and _day_ as arithmetical values in the given _calendar_ and returns in-range values by overflowing out-of-range _arithmeticalMonth_ or _day_ values into the next-highest unit. | |
This date may be outside the range given by ISODateTimeWithinLimits. | |
</dd> | |
</dl> | |
<p>It performs the following steps when called:</p> | |
<emu-alg> | |
1. Let _resolvedYear_ be _year_. | |
1. Let _resolvedArithmeticalMonth_ be _arithmeticalMonth_. |
and so on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this particular function, I don't think the verbosity of repeating "arithmetical" a dozen times lends clarity. This AO is very much defined as working on arithmetical values only.
However, I did change the argument name in f54148f.
spec.emu
Outdated
The return value indicates whether the date _date1_, the result of adding the duration denoted by _years_, _months_, _weeks_, and _days_ to _baseDate_ in the calendar system denoted by _calendar_, surpasses _isoDate2_ in the direction denoted by _sign_. | ||
If _weeks_ and _days_ are both zero, then _date1_ need not exist (for example, it could be February 30). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the asymmetry of baseDate vs. isoDate2. What about fromIsoDate and toIsoDate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had used isoDate2 to match the name in 262 but I will change this according to your suggestion here which I agree is better. f157b7a
spec.emu
Outdated
1. Let _month_ be MonthCodeToArithmeticalMonth(_calendar_, _year_, _fields_.[[MonthCode]]). | ||
1. If _month_ is ~invalid~, throw a *RangeError* exception. | ||
1. Else, | ||
1. Let _month_ be RegulateNonISOYearMonth(_calendar_, _year_, _fields_.[[MonthCode]], 0).[[Month]]. | ||
1. Else, | ||
1. Assert: _fields_.[[Month]] is not ~unset~. | ||
1. Let _month_ be _fields_.[[Month]]. | ||
1. Let _day_ be _fields_.[[Day]]. | ||
1. Assert: _day_ is not ~unset~. | ||
1. Let _daysInMonth_ be CalendarDaysInMonth(_calendar_, _year_, _month_). | ||
1. If _daysInMonth_ ≤ _day_, then | ||
1. If _overflow_ is ~reject~, throw a *RangeError* exception. | ||
1. Let _regulatedDay_ be _daysInMonth_. | ||
1. Else, | ||
1. Let _regulatedDay_ be _day_. | ||
1. Return ? CalendarDateArithmeticalToISO(_calendar_, _year_, _month_, _regulatedDay_). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. Let _month_ be MonthCodeToArithmeticalMonth(_calendar_, _year_, _fields_.[[MonthCode]]). | |
1. If _month_ is ~invalid~, throw a *RangeError* exception. | |
1. Else, | |
1. Let _month_ be RegulateNonISOYearMonth(_calendar_, _year_, _fields_.[[MonthCode]], 0).[[Month]]. | |
1. Else, | |
1. Assert: _fields_.[[Month]] is not ~unset~. | |
1. Let _month_ be _fields_.[[Month]]. | |
1. Let _day_ be _fields_.[[Day]]. | |
1. Assert: _day_ is not ~unset~. | |
1. Let _daysInMonth_ be CalendarDaysInMonth(_calendar_, _year_, _month_). | |
1. If _daysInMonth_ ≤ _day_, then | |
1. If _overflow_ is ~reject~, throw a *RangeError* exception. | |
1. Let _regulatedDay_ be _daysInMonth_. | |
1. Else, | |
1. Let _regulatedDay_ be _day_. | |
1. Return ? CalendarDateArithmeticalToISO(_calendar_, _year_, _month_, _regulatedDay_). | |
1. Let _arithmeticalMonth_ be MonthCodeToArithmeticalMonth(_calendar_, _year_, _fields_.[[MonthCode]]). | |
1. If _arithmeticalMonth_ is ~invalid~, throw a *RangeError* exception. | |
1. Else, | |
1. Let _arithmeticalMonth_ be RegulateNonISOYearMonth(_calendar_, _year_, _fields_.[[MonthCode]], 0).[[Month]]. | |
1. Else, | |
1. Assert: _fields_.[[Month]] is not ~unset~. | |
1. Let _arithmeticalMonth_ be _fields_.[[Month]]. | |
1. Let _day_ be _fields_.[[Day]]. | |
1. Assert: _day_ is not ~unset~. | |
1. Let _daysInMonth_ be CalendarDaysInMonth(_calendar_, _year_, _arithmeticalMonth_). | |
1. If _daysInMonth_ ≤ _day_, then | |
1. If _overflow_ is ~reject~, throw a *RangeError* exception. | |
1. Let _regulatedDay_ be _daysInMonth_. | |
1. Else, | |
1. Let _regulatedDay_ be _day_. | |
1. Return ? CalendarDateArithmeticalToISO(_calendar_, _year_, _arithmeticalMonth_, _regulatedDay_). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved in f54148f
<emu-clause id="sec-temporal-parsemonthcode" type="implementation-defined abstract operation"> | ||
<h1> | ||
ParseMonthCode ( | ||
_monthCode_: a String, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree we should narrow down the possible set of month codes (which we already have) and define that (essentially mark the existing definition) as the term "month code" or "month code type" akin to "calendar type" that we utilize from upstream Temporal. I don't think it's a bad idea to place this definition in the Temporal spec since it can be utilized in the upstream AO https://tc39.es/proposal-temporal/#sec-temporal-tomonthcode.
spec.emu
Outdated
1. If IsValidMonthCodeForCalendar(_calendar_, _monthCode_) is *false*, then | ||
1. Return ~invalid~. | ||
1. Let _monthCodeParts_ be ParseMonthCode(_monthCode_). | ||
1. If _calendar_ is not *"chinese"*, *"dangi"*, or *"hebrew"*, then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we can move this elsewhere as the list or table of supported calendars with leap months to make it easier to reuse and maintain and refer to that "central" (not necessarily for now, just disjointed) definition here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of moving this to a table, and the same table can also be used in @gibson042's proposed AO CalendarHasLeapMonths
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added it to #table-additional-month-codes
in 6abbe6e
spec.emu
Outdated
|
||
<emu-clause id="sec-temporal-regulatenonisoyearmonth" type="implementation-defined abstract operation"> | ||
<h1> | ||
RegulateNonISOYearMonth ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ConstrainNonISOYearMonth
sounds good as well but yeah don't mind Regulate either since it's consistent with upstream
spec.emu
Outdated
<dl class="header"> | ||
<dt>description</dt> | ||
<dd> | ||
Interprets _isoDate_ as a date in _calendar_, adds _years_, and returns the best-match arithmetic _year_ and _month_ according to the calendar. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isoDate
isn't defined here, replace with "a YearMonth corresponding to arithmeticYear and monthCode".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deleted this AO in 6abbe6e
This PR was included in the Stage 2.7 presentation. This PR was approved as part of Stage 2.7 with the following understanding: "changes the spec text to transform some parts of the spec from prose to algorithmic spec steps" |
I believe I have responded to all of the threads. PTAL. Thank you @Manishearth @gibson042 @ryzokuken! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor suggestion: the adjective for "arithmetic" can be "arithmetical" but could also be "arithmetic", e.g. "arithmetic mean".
Brevity is important in spec text, so I'd suggest globally replacing "arithmetical" wtih just "arithmetic".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good. A few minor suggestions only.
<emu-clause id="sec-temporal-createmonthcode" type="implementation-defined abstract operation"> | ||
<h1> | ||
CreateMonthCode ( | ||
_number_: an integer, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a more descriptive name than number
that could be appropriate here, specifcally that would distinguish this numnber from arithmetic month, common month, etc.? For example, for a month code like M06L, do we have a term for the "6" part of that code? If not, should we have a term for it?
At a minimum, maybe change this to _monthNumber_
if we don't want to use a separate term?
<h1> | ||
CreateMonthCode ( | ||
_number_: an integer, | ||
_isLeap_: a Boolean, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_isLeap_: a Boolean, | |
_isLeapMonth_: a Boolean, |
Might be good to distinguish from leap years vs. leap months. I know it's obvious to us, but for readers who are not familar wtih lunisolar calendars it might be clearer to emphasize that this is a leap month not a leap year.
<emu-clause id="sec-temporal-calendarmonthsinyear" type="implementation-defined abstract operation"> | ||
<h1> | ||
CalendarMonthsInYear ( | ||
_calendar_: a calendar type that is not *"iso8601"*, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why we chose "calendar type" instead of "calendar identifier" to align with "time zone identifier" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was the term already in use in 402.
<dl class="header"> | ||
<dt>description</dt> | ||
<dd> | ||
It interprets _year_ as arithmetical value in the given _calendar_ and returns the number of months in the corresponding year. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It interprets _year_ as arithmetical value in the given _calendar_ and returns the number of months in the corresponding year. | |
It interprets _year_ as arithmetic year in the given _calendar_ and returns the number of months in the corresponding year. |
"Arithmethical Value" sounds like it could be a floating point thing that could be confused wtih "mathematical value" in ECMA-262. Also, do we need the "-al" per my earlier comment?
<dl class="header"> | ||
<dt>description</dt> | ||
<dd> | ||
It interprets the given _year_ and potentially out-of-range _arithmeticalMonth_ and _day_ as arithmetical values in the given _calendar_ and returns in-range values by overflowing out-of-range _arithmeticalMonth_ or _day_ values into the next-highest unit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It interprets the given _year_ and potentially out-of-range _arithmeticalMonth_ and _day_ as arithmetical values in the given _calendar_ and returns in-range values by overflowing out-of-range _arithmeticalMonth_ or _day_ values into the next-highest unit. | |
It interprets the given _year_ and potentially out-of-range _arithmeticalMonth_ and/or _day_ as arithmetical values in the given _calendar_ and returns in-range values by overflowing out-of-range _arithmeticalMonth_ or _day_ values into the next-highest unit. |
There's a minor ambiguity possible where it's unclear whether the _day_
could also be out of range. Using and/or might clarify,.
I prefer using the explicitly-adjective "arithmetical", but I was actually thinking of using a term like "monotonic" to emphasize how they actually behave, in another PR. But since this spec currently uses "arithmetic", I can keep using that term to reduce the diff, if other people feel the difference warrants fixing. |
Fixes #55. More steps toward #57.
This PR is based on #66, and it also depends on #68 and tc39/proposal-temporal#3138.
I rewrote NonISODateAdd, NonISODateUntil, and NonISOCalendarDateToISO to more precisely specify their algorithms. They are still ultimately calendar-dependent, but the calendar-dependent parts are boiled down to more bite-sized abstract operations:
CalendarDateArithmeticalToISO
CalendarDaysInMonth
CalendarMonthsInYear
YearContainsMonthCode