Skip to content

Commit c9f6798

Browse files
committed
public API
1 parent 817bfa4 commit c9f6798

File tree

15 files changed

+115
-85
lines changed

15 files changed

+115
-85
lines changed

components/calendar/src/cal/east_asian_traditional.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ impl<R: Rules> DateFieldsResolver for EastAsianTraditional<R> {
613613

614614
// leap_month identifies the ordinal month number of the leap month,
615615
// so its month number will be leap_month - 1
616-
if month == Month::new_unchecked(leap_month - 1, true) {
616+
if month == Month::leap(leap_month - 1) {
617617
return Ok(leap_month);
618618
}
619619

@@ -1535,11 +1535,8 @@ mod test {
15351535
for year in [4659, 4660] {
15361536
let year = cal.year_info_from_extended(year);
15371537
for (month, error) in [
1538-
(Month::new_unchecked(4, true), MonthCodeError::NotInYear),
1539-
(
1540-
Month::new_unchecked(13, false),
1541-
MonthCodeError::NotInCalendar,
1542-
),
1538+
(Month::leap(4), MonthCodeError::NotInYear),
1539+
(Month::new(13), MonthCodeError::NotInCalendar),
15431540
] {
15441541
assert_eq!(
15451542
cal.ordinal_from_month(&year, month, reject),
@@ -1682,7 +1679,7 @@ mod test {
16821679
use crate::{cal::Gregorian, Date};
16831680

16841681
let mut related_iso = 1900;
1685-
let mut lunar_month = Month::new_unchecked(11, false);
1682+
let mut lunar_month = Month::new(11);
16861683

16871684
for year in 1901..=2100 {
16881685
println!("Validating year {year}...");
@@ -1737,7 +1734,7 @@ mod test {
17371734
let chinese = Date::try_new_from_codes(
17381735
None,
17391736
related_iso,
1740-
lunar_month.to_month_code(),
1737+
lunar_month.code(),
17411738
lunar_day,
17421739
ChineseTraditional::new(),
17431740
)
@@ -1825,21 +1822,21 @@ mod test {
18251822
for (start_year, start_month, end_year, end_month, by) in [
18261823
(
18271824
reference_year_end.extended_year(),
1828-
reference_year_end.month().month_number(),
1825+
reference_year_end.month().number(),
18291826
year_1900_start.extended_year(),
1830-
year_1900_start.month().month_number(),
1827+
year_1900_start.month().number(),
18311828
-1,
18321829
),
18331830
(
18341831
reference_year_end.extended_year(),
1835-
reference_year_end.month().month_number(),
1832+
reference_year_end.month().number(),
18361833
year_2035_end.extended_year(),
1837-
year_2035_end.month().month_number(),
1834+
year_2035_end.month().number(),
18381835
1,
18391836
),
18401837
(
18411838
year_1900_start.extended_year(),
1842-
year_1900_start.month().month_number(),
1839+
year_1900_start.month().number(),
18431840
-10000,
18441841
1,
18451842
-1,

components/calendar/src/cal/hebrew.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -326,16 +326,16 @@ impl Calendar for Hebrew {
326326
let standard = self.month_from_ordinal(&date.0.year(), date.0.month());
327327

328328
let formatting = if standard.number() == 6 && date.0.month() == 7 {
329-
Month::new_unchecked(6, true) // M06L
329+
Month::leap(6)
330330
} else {
331331
standard
332332
};
333333

334334
types::MonthInfo {
335335
ordinal: date.0.month(),
336-
standard_code: standard.to_month_code(),
336+
standard_code: standard.code(),
337337
standard,
338-
formatting_code: formatting.to_month_code(),
338+
formatting_code: formatting.code(),
339339
formatting,
340340
}
341341
}
@@ -377,19 +377,19 @@ mod tests {
377377
use super::*;
378378
use crate::types::MonthCode;
379379

380-
pub const TISHREI: Month = Month::new_unchecked(1, false);
381-
pub const ḤESHVAN: Month = Month::new_unchecked(2, false);
382-
pub const KISLEV: Month = Month::new_unchecked(3, false);
383-
pub const TEVET: Month = Month::new_unchecked(4, false);
384-
pub const SHEVAT: Month = Month::new_unchecked(5, false);
385-
pub const ADARI: Month = Month::new_unchecked(5, true);
386-
pub const ADAR: Month = Month::new_unchecked(6, false);
387-
pub const NISAN: Month = Month::new_unchecked(7, false);
388-
pub const IYYAR: Month = Month::new_unchecked(8, false);
389-
pub const SIVAN: Month = Month::new_unchecked(9, false);
390-
pub const TAMMUZ: Month = Month::new_unchecked(10, false);
391-
pub const AV: Month = Month::new_unchecked(11, false);
392-
pub const ELUL: Month = Month::new_unchecked(12, false);
380+
pub const TISHREI: Month = Month::new(1);
381+
pub const ḤESHVAN: Month = Month::new(2);
382+
pub const KISLEV: Month = Month::new(3);
383+
pub const TEVET: Month = Month::new(4);
384+
pub const SHEVAT: Month = Month::new(5);
385+
pub const ADARI: Month = Month::leap(5);
386+
pub const ADAR: Month = Month::new(6);
387+
pub const NISAN: Month = Month::new(7);
388+
pub const IYYAR: Month = Month::new(8);
389+
pub const SIVAN: Month = Month::new(9);
390+
pub const TAMMUZ: Month = Month::new(10);
391+
pub const AV: Month = Month::new(11);
392+
pub const ELUL: Month = Month::new(12);
393393

394394
/// The leap years used in the tests below
395395
const LEAP_YEARS_IN_TESTS: [i32; 1] = [5782];
@@ -452,7 +452,7 @@ mod tests {
452452
fn test_conversions() {
453453
for ((iso_y, iso_m, iso_d), (y, m, d)) in ISO_HEBREW_DATE_PAIRS.into_iter() {
454454
let iso_date = Date::try_new_iso(iso_y, iso_m, iso_d).unwrap();
455-
let hebrew_date = Date::try_new_from_codes(Some("am"), y, m.to_month_code(), d, Hebrew)
455+
let hebrew_date = Date::try_new_from_codes(Some("am"), y, m.code(), d, Hebrew)
456456
.expect("Date should parse");
457457

458458
let iso_to_hebrew = iso_date.to_calendar(Hebrew);

components/calendar/src/cal/iso.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ mod test {
184184
assert_eq!(
185185
(
186186
date_from_rd.era_year().year,
187-
date_from_rd.month().month_number(),
187+
date_from_rd.month().number(),
188188
date_from_rd.day_of_month().0
189189
),
190190
(case.year, case.month, case.day),

components/calendar/src/calendar_arithmetic.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ pub(crate) trait DateFieldsResolver: Calendar {
184184
/// The default impl is for non-lunisolar calendars!
185185
#[inline]
186186
fn month_from_ordinal(&self, _year: &Self::YearInfo, ordinal_month: u8) -> Month {
187-
Month::new_unchecked(ordinal_month, false)
187+
Month::new(ordinal_month)
188188
}
189189
}
190190

@@ -573,12 +573,8 @@ impl<C: DateFieldsResolver> ArithmeticDate<C> {
573573
.map_err(|e| {
574574
// TODO: Use a narrower error type here. For now, convert into DateError.
575575
match e {
576-
MonthCodeError::NotInCalendar => {
577-
DateError::UnknownMonthCode(base_month.to_month_code())
578-
}
579-
MonthCodeError::NotInYear => {
580-
DateError::UnknownMonthCode(base_month.to_month_code())
581-
}
576+
MonthCodeError::NotInCalendar => DateError::UnknownMonthCode(base_month.code()),
577+
MonthCodeError::NotInYear => DateError::UnknownMonthCode(base_month.code()),
582578
}
583579
})?;
584580
// 1. Let _endOfMonth_ be BalanceNonISODate(_calendar_, _y0_, _m0_ + _duration_.[[Months]] + 1, 0).

components/calendar/src/error.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,9 +309,11 @@ impl From<UnknownEraError> for DateFromFieldsError {
309309
}
310310
}
311311

312-
/// Internal narrow error type for functions that only fail on parsing month codes
312+
/// Error for [`Month`](crate::types::Month) parsing
313313
#[derive(Debug)]
314-
pub(crate) enum MonthCodeParseError {
314+
#[non_exhaustive]
315+
pub enum MonthCodeParseError {
316+
/// Invalid syntax
315317
InvalidSyntax,
316318
}
317319

components/calendar/src/types.rs

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ impl MonthCode {
371371
pub fn new_normal(number: u8) -> Option<Self> {
372372
(1..=99)
373373
.contains(&number)
374-
.then(|| Month::new_unchecked(number, false).to_month_code())
374+
.then(|| Month::new(number).code())
375375
}
376376

377377
/// Construct a "leap" month code given a number ("MxxL").
@@ -380,7 +380,7 @@ impl MonthCode {
380380
pub fn new_leap(number: u8) -> Option<Self> {
381381
(1..=99)
382382
.contains(&number)
383-
.then(|| Month::new_unchecked(number, true).to_month_code())
383+
.then(|| Month::leap(number).code())
384384
}
385385
}
386386

@@ -427,17 +427,42 @@ impl fmt::Display for MonthCode {
427427
}
428428
}
429429

430-
/// A [`MonthCode`] that has been parsed into its internal representation.
431-
#[derive(Copy, Clone, Debug, PartialEq)]
432-
pub(crate) struct Month {
430+
/// A representation of a month.
431+
#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
432+
pub struct Month {
433433
/// Month number between 0 and 99
434434
number: u8,
435435
is_leap: bool,
436436
}
437437

438438
impl Month {
439-
#[inline]
440-
pub(crate) fn try_from_utf8(bytes: &[u8]) -> Result<Self, MonthCodeParseError> {
439+
/// Constructs a non-leap with with the given number.
440+
///
441+
/// The input saturates at 99.
442+
pub const fn new(number: u8) -> Self {
443+
Self {
444+
number: if number > 99 { 99 } else { number },
445+
is_leap: false,
446+
}
447+
}
448+
449+
/// Constructs a non-leap with with the given number.
450+
///
451+
/// The input saturates at 99.
452+
pub const fn leap(number: u8) -> Self {
453+
Self {
454+
number,
455+
is_leap: true,
456+
}
457+
}
458+
459+
/// Parses Temporal month code syntax
460+
pub fn try_from_str(s: &str) -> Result<Self, MonthCodeParseError> {
461+
Self::try_from_utf8(s.as_bytes())
462+
}
463+
464+
/// Parses Temporal month code syntax
465+
pub fn try_from_utf8(bytes: &[u8]) -> Result<Self, MonthCodeParseError> {
441466
match *bytes {
442467
[b'M', tens, ones] => Ok(Self {
443468
number: (tens - b'0') * 10 + ones - b'0',
@@ -452,19 +477,22 @@ impl Month {
452477
}
453478

454479
/// Create a new ValidMonthCode without checking that the number is between 1 and 99
455-
#[inline]
456480
pub(crate) const fn new_unchecked(number: u8, is_leap: bool) -> Self {
457481
debug_assert!(1 <= number && number <= 99);
458482
Self { number, is_leap }
459483
}
460484

461-
/// Returns the month number according to the month code.
485+
/// Returns the month number.
486+
///
487+
/// A month number N is not necessarily the Nth month in the year if there are leap
488+
/// months in the year, rather it is associated with the Nth month of a "regular"
489+
/// year. There may be multiple month Ns in a year.
462490
///
463491
/// This is NOT the same as the ordinal month!
464492
///
465493
/// # Examples
466494
///
467-
/// ```ignore
495+
/// ```
468496
/// use icu::calendar::Date;
469497
/// use icu::calendar::cal::Hebrew;
470498
///
@@ -473,25 +501,24 @@ impl Month {
473501
///
474502
/// // Hebrew year 5784 was a leap year, so the ordinal month and month number diverge.
475503
/// assert_eq!(month_info.ordinal, 10);
476-
/// assert_eq!(month_info.valid_month_code.number(), 9);
504+
/// assert_eq!(month_info.number(), 9);
477505
/// ```
478-
#[inline]
479506
pub fn number(self) -> u8 {
480507
self.number
481508
}
482509

483510
/// Returns whether the month is a leap month.
484511
///
485-
/// This is true for intercalary months in [`Hebrew`] and [`LunarChinese`].
512+
/// This is true for intercalary months in [`Hebrew`] and [`EastAsianTraditional`].
486513
///
487514
/// [`Hebrew`]: crate::cal::Hebrew
488-
/// [`LunarChinese`]: crate::cal::LunarChinese
489-
#[inline]
515+
/// [`LunarChinese`]: crate::cal::east_asian_traditional::EastAsianTraditional
490516
pub fn is_leap(self) -> bool {
491517
self.is_leap
492518
}
493519

494-
pub(crate) fn to_month_code(self) -> MonthCode {
520+
/// Returns the [`MonthCode`] for this month.
521+
pub fn code(self) -> MonthCode {
495522
#[allow(clippy::unwrap_used)] // by construction
496523
MonthCode(
497524
TinyAsciiStr::try_from_raw([
@@ -547,39 +574,45 @@ pub struct MonthInfo {
547574
pub(crate) formatting: Month,
548575
}
549576

577+
impl core::ops::Deref for MonthInfo {
578+
type Target = Month;
579+
580+
fn deref(&self) -> &Self::Target {
581+
&self.standard
582+
}
583+
}
584+
550585
impl MonthInfo {
551586
pub(crate) fn non_lunisolar(number: u8) -> Self {
552-
Self::for_month_and_ordinal(Month::new_unchecked(number, false), number)
587+
Self::for_month_and_ordinal(Month::new(number), number)
553588
}
554589

555590
pub(crate) fn for_month_and_ordinal(month: Month, ordinal: u8) -> Self {
556591
Self {
557592
ordinal,
558-
standard_code: month.to_month_code(),
593+
standard_code: month.code(),
559594
standard: month,
560-
formatting_code: month.to_month_code(),
595+
formatting_code: month.code(),
561596
formatting: month,
562597
}
563598
}
564599

565-
/// Gets the month number. A month number N is not necessarily the Nth month in the year
566-
/// if there are leap months in the year, rather it is associated with the Nth month of a "regular"
567-
/// year. There may be multiple month Ns in a year
600+
#[doc(hidden)] // available through Deref<Target = Month>
568601
pub fn month_number(self) -> u8 {
569602
self.standard.number()
570603
}
571604

572-
/// Get whether the month is a leap month
605+
#[doc(hidden)] // available through Deref<Target = Month>
573606
pub fn is_leap(self) -> bool {
574607
self.standard.is_leap()
575608
}
576609

577-
#[doc(hidden)]
610+
#[doc(hidden)] // for formatting
578611
pub fn formatting_month_number(self) -> u8 {
579612
self.formatting.number()
580613
}
581614

582-
#[doc(hidden)]
615+
#[doc(hidden)] // for formatting
583616
pub fn formatting_is_leap(self) -> bool {
584617
self.formatting.is_leap()
585618
}

components/time/src/zone/zone_name_timestamp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ impl serde::Serialize for ZoneNameTimestamp {
219219
if serializer.is_human_readable() {
220220
let date_time = self.to_zoned_date_time_iso();
221221
let year = date_time.date.era_year().year;
222-
let month = date_time.date.month().month_number();
222+
let month = date_time.date.month().number();
223223
let day = date_time.date.day_of_month().0;
224224
let hour = date_time.time.hour.number();
225225
let minute = date_time.time.minute.number();

ffi/capi/bindings/cpp/icu4x/CalendarError.d.hpp

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ffi/capi/bindings/dart/CalendarError.g.dart

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ffi/capi/bindings/js/CalendarError.d.ts

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)