@internationalized/date 3.0.0-alpha.1 → 3.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,7 +11,7 @@
11
11
  */
12
12
 
13
13
  import {add, addTime, addZoned, constrain, constrainTime, cycleDate, cycleTime, cycleZoned, set, setTime, setZoned, subtract, subtractTime, subtractZoned} from './manipulation';
14
- import {AnyCalendarDate, AnyTime, Calendar, CycleOptions, CycleTimeOptions, DateField, DateFields, Disambiguation, Duration, TimeField, TimeFields} from './types';
14
+ import {AnyCalendarDate, AnyTime, Calendar, CycleOptions, CycleTimeOptions, DateDuration, DateField, DateFields, DateTimeDuration, Disambiguation, TimeDuration, TimeField, TimeFields} from './types';
15
15
  import {compareDate, compareTime} from './queries';
16
16
  import {dateTimeToString, dateToString, timeToString, zonedDateTimeToString} from './string';
17
17
  import {GregorianCalendar} from './calendars/GregorianCalendar';
@@ -37,15 +37,25 @@ function shiftArgs(args: any[]) {
37
37
  return [calendar, era, year, month, day];
38
38
  }
39
39
 
40
+ /** A CalendarDate represents a date without any time components in a specific calendar system. */
40
41
  export class CalendarDate {
41
42
  // This prevents TypeScript from allowing other types with the same fields to match.
42
43
  // i.e. a ZonedDateTime should not be be passable to a parameter that expects CalendarDate.
43
44
  // If that behavior is desired, use the AnyCalendarDate interface instead.
44
45
  #type;
46
+ /** The calendar system associated with this date, e.g. Gregorian. */
45
47
  public readonly calendar: Calendar;
48
+ /** The calendar era for this date, e.g. "BC" or "AD". */
46
49
  public readonly era: string;
50
+ /** The year of this date within the era. */
47
51
  public readonly year: number;
52
+ /**
53
+ * The month number within the year. Note that some calendar systems such as Hebrew
54
+ * may have a variable number of months per year. Therefore, month numbers may not
55
+ * always correspond to the same month names in different years.
56
+ */
48
57
  public readonly month: number;
58
+ /** The day number within the month. */
49
59
  public readonly day: number;
50
60
 
51
61
  constructor(year: number, month: number, day: number);
@@ -62,6 +72,7 @@ export class CalendarDate {
62
72
  constrain(this);
63
73
  }
64
74
 
75
+ /** Returns a copy of this date. */
65
76
  copy(): CalendarDate {
66
77
  if (this.era) {
67
78
  return new CalendarDate(this.calendar, this.era, this.year, this.month, this.day);
@@ -70,88 +81,135 @@ export class CalendarDate {
70
81
  }
71
82
  }
72
83
 
73
- add(duration: Duration) {
84
+ /** Returns a new `CalendarDate` with the given duration added to it. */
85
+ add(duration: DateDuration): CalendarDate {
74
86
  return add(this, duration);
75
87
  }
76
88
 
77
- subtract(duration: Duration) {
89
+ /** Returns a new `CalendarDate` with the given duration subtracted from it. */
90
+ subtract(duration: DateDuration): CalendarDate {
78
91
  return subtract(this, duration);
79
92
  }
80
93
 
81
- set(fields: DateFields) {
94
+ /** Returns a new `CalendarDate` with the given fields set to the provided values. Other fields will be constrained accordingly. */
95
+ set(fields: DateFields): CalendarDate {
82
96
  return set(this, fields);
83
97
  }
84
98
 
85
- cycle(field: DateField, amount: number, options?: CycleOptions) {
99
+ /**
100
+ * Returns a new `CalendarDate` with the given field adjusted by a specified amount.
101
+ * When the resulting value reaches the limits of the field, it wraps around.
102
+ */
103
+ cycle(field: DateField, amount: number, options?: CycleOptions): CalendarDate {
86
104
  return cycleDate(this, field, amount, options);
87
105
  }
88
106
 
89
- toDate(timeZone: string) {
107
+ /** Converts the date to a native JavaScript Date object, with the time set to midnight in the given time zone. */
108
+ toDate(timeZone: string): Date {
90
109
  return toDate(this, timeZone);
91
110
  }
92
111
 
93
- toString() {
112
+ /** Converts the date to an ISO 8601 formatted string. */
113
+ toString(): string {
94
114
  return dateToString(this);
95
115
  }
96
116
 
97
- compare(b: AnyCalendarDate) {
117
+ /** Compares this date with another. A negative result indicates that this date is before the given one, and a positive date indicates that it is after. */
118
+ compare(b: AnyCalendarDate): number {
98
119
  return compareDate(this, b);
99
120
  }
100
121
  }
101
122
 
123
+ /** A Time represents a clock time without any date components. */
102
124
  export class Time {
103
125
  // This prevents TypeScript from allowing other types with the same fields to match.
104
126
  #type;
127
+ /** The hour, numbered from 0 to 23. */
128
+ public readonly hour: number;
129
+ /** The minute in the hour. */
130
+ public readonly minute: number;
131
+ /** The second in the minute. */
132
+ public readonly second: number;
133
+ /** The millisecond in the second. */
134
+ public readonly millisecond: number;
105
135
 
106
136
  constructor(
107
- public readonly hour: number = 0,
108
- public readonly minute: number = 0,
109
- public readonly second: number = 0,
110
- public readonly millisecond: number = 0
137
+ hour: number = 0,
138
+ minute: number = 0,
139
+ second: number = 0,
140
+ millisecond: number = 0
111
141
  ) {
142
+ this.hour = hour;
143
+ this.minute = minute;
144
+ this.second = second;
145
+ this.millisecond = millisecond;
112
146
  constrainTime(this);
113
147
  }
114
148
 
149
+ /** Returns a copy of this time. */
115
150
  copy(): Time {
116
151
  return new Time(this.hour, this.minute, this.second, this.millisecond);
117
152
  }
118
153
 
119
- add(duration: Duration) {
154
+ /** Returns a new `Time` with the given duration added to it. */
155
+ add(duration: TimeDuration) {
120
156
  return addTime(this, duration);
121
157
  }
122
158
 
123
- subtract(duration: Duration) {
159
+ /** Returns a new `Time` with the given duration subtracted from it. */
160
+ subtract(duration: TimeDuration) {
124
161
  return subtractTime(this, duration);
125
162
  }
126
163
 
164
+ /** Returns a new `Time` with the given fields set to the provided values. Other fields will be constrained accordingly. */
127
165
  set(fields: TimeFields) {
128
166
  return setTime(this, fields);
129
167
  }
130
168
 
169
+ /**
170
+ * Returns a new `Time` with the given field adjusted by a specified amount.
171
+ * When the resulting value reaches the limits of the field, it wraps around.
172
+ */
131
173
  cycle(field: TimeField, amount: number, options?: CycleTimeOptions) {
132
174
  return cycleTime(this, field, amount, options);
133
175
  }
134
176
 
177
+ /** Converts the time to an ISO 8601 formatted string. */
135
178
  toString() {
136
179
  return timeToString(this);
137
180
  }
138
181
 
182
+ /** Compares this time with another. A negative result indicates that this time is before the given one, and a positive time indicates that it is after. */
139
183
  compare(b: AnyTime) {
140
184
  return compareTime(this, b);
141
185
  }
142
186
  }
143
187
 
188
+ /** A CalendarDateTime represents a date and time without a time zone, in a specific calendar system. */
144
189
  export class CalendarDateTime {
145
190
  // This prevents TypeScript from allowing other types with the same fields to match.
146
191
  #type;
192
+ /** The calendar system associated with this date, e.g. Gregorian. */
147
193
  public readonly calendar: Calendar;
194
+ /** The calendar era for this date, e.g. "BC" or "AD". */
148
195
  public readonly era: string;
196
+ /** The year of this date within the era. */
149
197
  public readonly year: number;
198
+ /**
199
+ * The month number within the year. Note that some calendar systems such as Hebrew
200
+ * may have a variable number of months per year. Therefore, month numbers may not
201
+ * always correspond to the same month names in different years.
202
+ */
150
203
  public readonly month: number;
204
+ /** The day number within the month. */
151
205
  public readonly day: number;
206
+ /** The hour in the day, numbered from 0 to 23. */
152
207
  public readonly hour: number;
208
+ /** The minute in the hour. */
153
209
  public readonly minute: number;
210
+ /** The second in the minute. */
154
211
  public readonly second: number;
212
+ /** The millisecond in the second. */
155
213
  public readonly millisecond: number;
156
214
 
157
215
  constructor(year: number, month: number, day: number, hour?: number, minute?: number, second?: number, millisecond?: number);
@@ -172,6 +230,7 @@ export class CalendarDateTime {
172
230
  constrain(this);
173
231
  }
174
232
 
233
+ /** Returns a copy of this date. */
175
234
  copy(): CalendarDateTime {
176
235
  if (this.era) {
177
236
  return new CalendarDateTime(this.calendar, this.era, this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
@@ -180,19 +239,26 @@ export class CalendarDateTime {
180
239
  }
181
240
  }
182
241
 
183
- add(duration: Duration) {
242
+ /** Returns a new `CalendarDateTime` with the given duration added to it. */
243
+ add(duration: DateTimeDuration): CalendarDateTime {
184
244
  return add(this, duration);
185
245
  }
186
246
 
187
- subtract(duration: Duration) {
247
+ /** Returns a new `CalendarDateTime` with the given duration subtracted from it. */
248
+ subtract(duration: DateTimeDuration): CalendarDateTime {
188
249
  return subtract(this, duration);
189
250
  }
190
251
 
191
- set(fields: DateFields & TimeFields) {
252
+ /** Returns a new `CalendarDateTime` with the given fields set to the provided values. Other fields will be constrained accordingly. */
253
+ set(fields: DateFields & TimeFields): CalendarDateTime {
192
254
  return set(setTime(this, fields), fields);
193
255
  }
194
256
 
195
- cycle(field: DateField | TimeField, amount: number, options?: CycleTimeOptions) {
257
+ /**
258
+ * Returns a new `CalendarDateTime` with the given field adjusted by a specified amount.
259
+ * When the resulting value reaches the limits of the field, it wraps around.
260
+ */
261
+ cycle(field: DateField | TimeField, amount: number, options?: CycleTimeOptions): CalendarDateTime {
196
262
  switch (field) {
197
263
  case 'era':
198
264
  case 'year':
@@ -204,15 +270,18 @@ export class CalendarDateTime {
204
270
  }
205
271
  }
206
272
 
207
- toDate(timeZone: string) {
208
- return toDate(this, timeZone);
273
+ /** Converts the date to a native JavaScript Date object in the given time zone. */
274
+ toDate(timeZone: string, disambiguation?: Disambiguation): Date {
275
+ return toDate(this, timeZone, disambiguation);
209
276
  }
210
277
 
211
- toString() {
278
+ /** Converts the date to an ISO 8601 formatted string. */
279
+ toString(): string {
212
280
  return dateTimeToString(this);
213
281
  }
214
282
 
215
- compare(b: CalendarDate | CalendarDateTime | ZonedDateTime) {
283
+ /** Compares this date with another. A negative result indicates that this date is before the given one, and a positive date indicates that it is after. */
284
+ compare(b: CalendarDate | CalendarDateTime | ZonedDateTime): number {
216
285
  let res = compareDate(this, b);
217
286
  if (res === 0) {
218
287
  return compareTime(this, toCalendarDateTime(b));
@@ -222,19 +291,35 @@ export class CalendarDateTime {
222
291
  }
223
292
  }
224
293
 
294
+ /** A ZonedDateTime represents a date and time in a specific time zone and calendar system. */
225
295
  export class ZonedDateTime {
226
296
  // This prevents TypeScript from allowing other types with the same fields to match.
227
297
  #type;
298
+ /** The calendar system associated with this date, e.g. Gregorian. */
228
299
  public readonly calendar: Calendar;
300
+ /** The calendar era for this date, e.g. "BC" or "AD". */
229
301
  public readonly era: string;
302
+ /** The year of this date within the era. */
230
303
  public readonly year: number;
304
+ /**
305
+ * The month number within the year. Note that some calendar systems such as Hebrew
306
+ * may have a variable number of months per year. Therefore, month numbers may not
307
+ * always correspond to the same month names in different years.
308
+ */
231
309
  public readonly month: number;
310
+ /** The day number within the month. */
232
311
  public readonly day: number;
312
+ /** The hour in the day, numbered from 0 to 23. */
233
313
  public readonly hour: number;
314
+ /** The minute in the hour. */
234
315
  public readonly minute: number;
316
+ /** The second in the minute. */
235
317
  public readonly second: number;
318
+ /** The millisecond in the second. */
236
319
  public readonly millisecond: number;
320
+ /** The IANA time zone identifier that this date and time is represented in. */
237
321
  public readonly timeZone: string;
322
+ /** The UTC offset for this time, in seconds. */
238
323
  public readonly offset: number;
239
324
 
240
325
  constructor(year: number, month: number, day: number, timeZone: string, offset: number, hour?: number, minute?: number, second?: number, millisecond?: number);
@@ -259,6 +344,7 @@ export class ZonedDateTime {
259
344
  constrain(this);
260
345
  }
261
346
 
347
+ /** Returns a copy of this date. */
262
348
  copy(): ZonedDateTime {
263
349
  if (this.era) {
264
350
  return new ZonedDateTime(this.calendar, this.era, this.year, this.month, this.day, this.timeZone, this.offset, this.hour, this.minute, this.second, this.millisecond);
@@ -267,34 +353,45 @@ export class ZonedDateTime {
267
353
  }
268
354
  }
269
355
 
270
- add(duration: Duration) {
356
+ /** Returns a new `ZonedDateTime` with the given duration added to it. */
357
+ add(duration: DateTimeDuration) {
271
358
  return addZoned(this, duration);
272
359
  }
273
360
 
274
- subtract(duration: Duration) {
361
+ /** Returns a new `ZonedDateTime` with the given duration subtracted from it. */
362
+ subtract(duration: DateTimeDuration) {
275
363
  return subtractZoned(this, duration);
276
364
  }
277
365
 
366
+ /** Returns a new `ZonedDateTime` with the given fields set to the provided values. Other fields will be constrained accordingly. */
278
367
  set(fields: DateFields & TimeFields, disambiguation?: Disambiguation) {
279
368
  return setZoned(this, fields, disambiguation);
280
369
  }
281
370
 
371
+ /**
372
+ * Returns a new `ZonedDateTime` with the given field adjusted by a specified amount.
373
+ * When the resulting value reaches the limits of the field, it wraps around.
374
+ */
282
375
  cycle(field: DateField | TimeField, amount: number, options?: CycleTimeOptions) {
283
376
  return cycleZoned(this, field, amount, options);
284
377
  }
285
378
 
379
+ /** Converts the date to a native JavaScript Date object. */
286
380
  toDate() {
287
381
  return zonedToDate(this);
288
382
  }
289
383
 
384
+ /** Converts the date to an ISO 8601 formatted string, including the UTC offset and time zone identifier. */
290
385
  toString() {
291
386
  return zonedDateTimeToString(this);
292
387
  }
293
388
 
389
+ /** Converts the date to an ISO 8601 formatted string in UTC. */
294
390
  toAbsoluteString() {
295
391
  return this.toDate().toISOString();
296
392
  }
297
393
 
394
+ /** Compares this date with another. A negative result indicates that this date is before the given one, and a positive date indicates that it is after. */
298
395
  compare(b: CalendarDate | CalendarDateTime | ZonedDateTime) {
299
396
  // TODO: Is this a bad idea??
300
397
  return this.toDate().getTime() - toZoned(b, this.timeZone).toDate().getTime();
@@ -20,6 +20,7 @@ interface DateRangeFormatPart extends Intl.DateTimeFormatPart {
20
20
  source: 'startRange' | 'endRange' | 'shared'
21
21
  }
22
22
 
23
+ /** A wrapper around Intl.DateTimeFormat that fixes various browser bugs, and polyfills new features. */
23
24
  export class DateFormatter implements Intl.DateTimeFormat {
24
25
  private formatter: Intl.DateTimeFormat;
25
26
  private options: Intl.DateTimeFormatOptions;
@@ -30,14 +31,17 @@ export class DateFormatter implements Intl.DateTimeFormat {
30
31
  this.options = options;
31
32
  }
32
33
 
34
+ /** Formats a date as a string according to the locale and format options passed to the constructor. */
33
35
  format(value: Date): string {
34
36
  return this.formatter.format(value);
35
37
  }
36
38
 
39
+ /** Formats a date to an array of parts such as separators, numbers, punctuation, and more. */
37
40
  formatToParts(value: Date): Intl.DateTimeFormatPart[] {
38
41
  return this.formatter.formatToParts(value);
39
42
  }
40
43
 
44
+ /** Formats a date range as a string. */
41
45
  formatRange(start: Date, end: Date): string {
42
46
  // @ts-ignore
43
47
  if (typeof this.formatter.formatRange === 'function') {
@@ -53,6 +57,7 @@ export class DateFormatter implements Intl.DateTimeFormat {
53
57
  return `${this.formatter.format(start)} – ${this.formatter.format(end)}`;
54
58
  }
55
59
 
60
+ /** Formats a date range as an array of parts. */
56
61
  formatRangeToParts(start: Date, end: Date): DateRangeFormatPart[] {
57
62
  // @ts-ignore
58
63
  if (typeof this.formatter.formatRangeToParts === 'function') {
@@ -73,6 +78,7 @@ export class DateFormatter implements Intl.DateTimeFormat {
73
78
  ];
74
79
  }
75
80
 
81
+ /** Returns the resolved formatting options based on the values passed to the constructor. */
76
82
  resolvedOptions(): ResolvedDateTimeFormatOptions {
77
83
  let resolvedOptions = this.formatter.resolvedOptions() as ResolvedDateTimeFormatOptions;
78
84
  if (hasBuggyResolvedHourCycle()) {
@@ -20,6 +20,11 @@ import {Mutable} from '../utils';
20
20
 
21
21
  const BUDDHIST_ERA_START = -543;
22
22
 
23
+ /**
24
+ * The Buddhist calendar is the same as the Gregorian calendar, but counts years
25
+ * starting from the birth of Buddha in 543 BC (Gregorian). It supports only one
26
+ * era, identified as 'BE'.
27
+ */
23
28
  export class BuddhistCalendar extends GregorianCalendar {
24
29
  identifier = 'buddhist';
25
30
 
@@ -30,16 +35,22 @@ export class BuddhistCalendar extends GregorianCalendar {
30
35
  }
31
36
 
32
37
  toJulianDay(date: AnyCalendarDate) {
33
- return super.toJulianDay(
34
- new CalendarDate(
35
- date.year + BUDDHIST_ERA_START,
36
- date.month,
37
- date.day
38
- )
39
- );
38
+ return super.toJulianDay(toGregorian(date));
40
39
  }
41
40
 
42
41
  getEras() {
43
42
  return ['BE'];
44
43
  }
44
+
45
+ getDaysInMonth(date: AnyCalendarDate): number {
46
+ return super.getDaysInMonth(toGregorian(date));
47
+ }
48
+ }
49
+
50
+ function toGregorian(date: AnyCalendarDate) {
51
+ return new CalendarDate(
52
+ date.year + BUDDHIST_ERA_START,
53
+ date.month,
54
+ date.day
55
+ );
45
56
  }
@@ -61,6 +61,11 @@ function getDaysInMonth(year: number, month: number) {
61
61
  }
62
62
  }
63
63
 
64
+ /**
65
+ * The Ethiopic calendar system is the official calendar used in Ethiopia.
66
+ * It includes 12 months of 30 days each, plus 5 or 6 intercalary days depending
67
+ * on whether it is a leap year. Two eras are supported: 'AA' and 'AM'.
68
+ */
64
69
  export class EthiopicCalendar implements Calendar {
65
70
  identifier = 'ethiopic';
66
71
 
@@ -111,6 +116,10 @@ export class EthiopicCalendar implements Calendar {
111
116
  }
112
117
  }
113
118
 
119
+ /**
120
+ * The Ethiopic (Amete Alem) calendar is the same as the modern Ethiopic calendar,
121
+ * except years were measured from a different epoch. Only one era is supported: 'AA'.
122
+ */
114
123
  export class EthiopicAmeteAlemCalendar extends EthiopicCalendar {
115
124
  identifier = 'ethioaa'; // also known as 'ethiopic-amete-alem' in ICU
116
125
 
@@ -126,6 +135,11 @@ export class EthiopicAmeteAlemCalendar extends EthiopicCalendar {
126
135
  }
127
136
  }
128
137
 
138
+ /**
139
+ * The Coptic calendar is similar to the Ethiopic calendar.
140
+ * It includes 12 months of 30 days each, plus 5 or 6 intercalary days depending
141
+ * on whether it is a leap year. Two eras are supported: 'BCE' and 'CE'.
142
+ */
129
143
  export class CopticCalendar extends EthiopicCalendar {
130
144
  identifier = 'coptic';
131
145
 
@@ -47,6 +47,10 @@ const daysInMonth = {
47
47
  leapyear: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
48
48
  };
49
49
 
50
+ /**
51
+ * The Gregorian calendar is the most commonly used calendar system in the world. It supports two eras: BC, and AD.
52
+ * Years always contain 12 months, and 365 or 366 days depending on whether it is a leap year.
53
+ */
50
54
  export class GregorianCalendar implements Calendar {
51
55
  identifier = 'gregory';
52
56
 
@@ -122,6 +122,11 @@ function getDaysInMonth(year: number, month: number): number {
122
122
  return 30;
123
123
  }
124
124
 
125
+ /**
126
+ * The Hebrew calendar is used in Israel and around the world by the Jewish faith.
127
+ * Years include either 12 or 13 months depending on whether it is a leap year.
128
+ * In leap years, an extra month is inserted at month 6.
129
+ */
125
130
  export class HebrewCalendar implements Calendar {
126
131
  identifier = 'hebrew';
127
132
 
@@ -24,6 +24,11 @@ const INDIAN_ERA_START = 78;
24
24
  // The Indian year starts 80 days later than the Gregorian year.
25
25
  const INDIAN_YEAR_START = 80;
26
26
 
27
+ /**
28
+ * The Indian National Calendar is similar to the Gregorian calendar, but with
29
+ * years numbered since the Saka era in 78 AD (Gregorian). There are 12 months
30
+ * in each year, with either 30 or 31 days. Only one era identifier is supported: 'saka'.
31
+ */
27
32
  export class IndianCalendar extends GregorianCalendar {
28
33
  identifier = 'indian';
29
34
 
@@ -42,6 +42,13 @@ function isLeapYear(year: number): boolean {
42
42
  return (14 + 11 * year) % 30 < 11;
43
43
  }
44
44
 
45
+ /**
46
+ * The Islamic calendar, also known as the "Hijri" calendar, is used throughout much of the Arab world.
47
+ * The civil variant uses simple arithmetic rules rather than astronomical calculations to approximate
48
+ * the traditional calendar, which is based on sighting of the crescent moon. It uses Friday, July 16 622 CE (Julian) as the epoch.
49
+ * Each year has 12 months, with either 354 or 355 days depending on whether it is a leap year.
50
+ * Learn more about the available Islamic calendars [here](https://cldr.unicode.org/development/development-process/design-proposals/islamic-calendar-types).
51
+ */
45
52
  export class IslamicCivilCalendar implements Calendar {
46
53
  identifier = 'islamic-civil';
47
54
 
@@ -79,6 +86,13 @@ export class IslamicCivilCalendar implements Calendar {
79
86
  }
80
87
  }
81
88
 
89
+ /**
90
+ * The Islamic calendar, also known as the "Hijri" calendar, is used throughout much of the Arab world.
91
+ * The tabular variant uses simple arithmetic rules rather than astronomical calculations to approximate
92
+ * the traditional calendar, which is based on sighting of the crescent moon. It uses Thursday, July 15 622 CE (Julian) as the epoch.
93
+ * Each year has 12 months, with either 354 or 355 days depending on whether it is a leap year.
94
+ * Learn more about the available Islamic calendars [here](https://cldr.unicode.org/development/development-process/design-proposals/islamic-calendar-types).
95
+ */
82
96
  export class IslamicTabularCalendar extends IslamicCivilCalendar {
83
97
  identifier = 'islamic-tbla';
84
98
 
@@ -122,6 +136,13 @@ function umalquraYearLength(year: number): number {
122
136
  return UMALQURA_YEAR_START_TABLE[year + 1 - UMALQURA_YEAR_START] - UMALQURA_YEAR_START_TABLE[year - UMALQURA_YEAR_START];
123
137
  }
124
138
 
139
+ /**
140
+ * The Islamic calendar, also known as the "Hijri" calendar, is used throughout much of the Arab world.
141
+ * The Umalqura variant is primarily used in Saudi Arabia. It is a lunar calendar, based on astronomical
142
+ * calculations that predict the sighting of a crescent moon. Month and year lengths vary between years
143
+ * depending on these calculations.
144
+ * Learn more about the available Islamic calendars [here](https://cldr.unicode.org/development/development-process/design-proposals/islamic-calendar-types).
145
+ */
125
146
  export class IslamicUmalquraCalendar extends IslamicCivilCalendar {
126
147
  identifier = 'islamic-umalqura';
127
148
 
@@ -64,6 +64,11 @@ function toGregorian(date: AnyCalendarDate) {
64
64
  );
65
65
  }
66
66
 
67
+ /**
68
+ * The Japanese calendar is based on the Gregorian calendar, but with eras for the reign of each Japanese emperor.
69
+ * Whenever a new emperor ascends to the throne, a new era begins and the year starts again from 1.
70
+ * Note that eras before 1868 (Gregorian) are not currently supported by this implementation.
71
+ */
67
72
  export class JapaneseCalendar extends GregorianCalendar {
68
73
  identifier = 'japanese';
69
74
 
@@ -141,6 +146,10 @@ export class JapaneseCalendar extends GregorianCalendar {
141
146
  return years;
142
147
  }
143
148
 
149
+ getDaysInMonth(date: AnyCalendarDate): number {
150
+ return super.getDaysInMonth(toGregorian(date));
151
+ }
152
+
144
153
  getMinimumMonthInYear(date: AnyCalendarDate): number {
145
154
  let start = getMinimums(date);
146
155
  return start ? start[1] : 1;
@@ -42,6 +42,12 @@ function persianToJulianDay(year: number, month: number, day: number): number {
42
42
  );
43
43
  }
44
44
 
45
+ /**
46
+ * The Persian calendar is the main calendar used in Iran and Afghanistan. It has 12 months
47
+ * in each year, the first 6 of which have 31 days, and the next 5 have 30 days. The 12th month
48
+ * has either 29 or 30 days depending on whether it is a leap year. The Persian year starts
49
+ * around the March equinox.
50
+ */
45
51
  export class PersianCalendar implements Calendar {
46
52
  identifier = 'persian';
47
53
 
@@ -37,6 +37,11 @@ function gregorianToTaiwan(year: number, date: Mutable<AnyCalendarDate>) {
37
37
  }
38
38
  }
39
39
 
40
+ /**
41
+ * The Taiwanese calendar is the same as the Gregorian calendar, but years
42
+ * are numbered starting from 1912 (Gregorian). Two eras are supported:
43
+ * 'before_minguo' and 'minguo'.
44
+ */
40
45
  export class TaiwanCalendar extends GregorianCalendar {
41
46
  identifier = 'roc'; // Republic of China
42
47
 
@@ -47,13 +52,7 @@ export class TaiwanCalendar extends GregorianCalendar {
47
52
  }
48
53
 
49
54
  toJulianDay(date: AnyCalendarDate) {
50
- return super.toJulianDay(
51
- new CalendarDate(
52
- gregorianYear(date),
53
- date.month,
54
- date.day
55
- )
56
- );
55
+ return super.toJulianDay(toGregorian(date));
57
56
  }
58
57
 
59
58
  getEras() {
@@ -67,4 +66,16 @@ export class TaiwanCalendar extends GregorianCalendar {
67
66
  getYearsToAdd(date: Mutable<AnyCalendarDate>, years: number) {
68
67
  return date.era === 'before_minguo' ? -years : years;
69
68
  }
69
+
70
+ getDaysInMonth(date: AnyCalendarDate): number {
71
+ return super.getDaysInMonth(toGregorian(date));
72
+ }
73
+ }
74
+
75
+ function toGregorian(date: AnyCalendarDate) {
76
+ return new CalendarDate(
77
+ gregorianYear(date),
78
+ date.month,
79
+ date.day
80
+ );
70
81
  }