0
# Calendar System
1
2
Specialized classes for working with calendar-specific date components like year-month and month-day combinations. These classes handle partial date representations and calendar-aware operations.
3
4
## Capabilities
5
6
### PlainYearMonth
7
8
Represents a year and month combination in a calendar system. Ideal for monthly reports, subscription periods, or any year-month specific operations.
9
10
```typescript { .api }
11
/**
12
* Represents a year and month combination in a calendar
13
*/
14
class PlainYearMonth {
15
/** Creates a PlainYearMonth from various inputs */
16
static from(item: PlainYearMonthLike | string, options?: AssignmentOptions): PlainYearMonth;
17
/** Compares two year-months and returns -1, 0, or 1 */
18
static compare(one: PlainYearMonthLike, two: PlainYearMonthLike): ComparisonResult;
19
20
// Year-month component properties
21
readonly calendarId: string;
22
readonly year: number;
23
readonly month: number;
24
readonly monthCode: string;
25
readonly era: string | undefined;
26
readonly eraYear: number | undefined;
27
28
// Calendar-computed properties
29
readonly daysInMonth: number;
30
readonly daysInYear: number;
31
readonly monthsInYear: number;
32
readonly inLeapYear: boolean;
33
34
// Year-month manipulation methods
35
/** Returns a new PlainYearMonth with the duration added */
36
add(duration: DurationLike, options?: ArithmeticOptions): PlainYearMonth;
37
/** Returns a new PlainYearMonth with the duration subtracted */
38
subtract(duration: DurationLike, options?: ArithmeticOptions): PlainYearMonth;
39
/** Returns a new PlainYearMonth with the specified fields changed */
40
with(yearMonthLike: PlainYearMonthLike, options?: AssignmentOptions): PlainYearMonth;
41
42
// Comparison and difference methods
43
/** Returns the duration from this year-month until the other year-month */
44
until(other: PlainYearMonthLike, options?: DifferenceOptions<YearMonthUnit>): Duration;
45
/** Returns the duration from the other year-month since this year-month */
46
since(other: PlainYearMonthLike, options?: DifferenceOptions<YearMonthUnit>): Duration;
47
/** Tests if this year-month equals another year-month */
48
equals(other: PlainYearMonthLike): boolean;
49
50
// Conversion methods
51
/** Combines this year-month with a day to create a PlainDate */
52
toPlainDate(day: PlainDateLike): PlainDate;
53
54
// String representation methods
55
/** Returns a locale-formatted string representation */
56
toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
57
/** Returns an ISO 8601 string representation */
58
toString(options?: ShowCalendarOption): string;
59
/** Returns a JSON representation (same as toString) */
60
toJSON(): string;
61
/** Throws a TypeError when used in comparison operators */
62
valueOf(): never;
63
}
64
```
65
66
**Usage Examples:**
67
68
```typescript
69
import { Temporal } from "temporal-polyfill";
70
71
// Creating year-months
72
const currentMonth = Temporal.Now.plainDateISO().toPlainYearMonth();
73
const fromString = Temporal.PlainYearMonth.from('2024-03');
74
const fromObject = Temporal.PlainYearMonth.from({ year: 2024, month: 3 });
75
76
// Monthly operations
77
const nextMonth = currentMonth.add({ months: 1 });
78
const lastYear = currentMonth.subtract({ years: 1 });
79
const sameMonthNextYear = currentMonth.with({ year: currentMonth.year + 1 });
80
81
// Calendar information
82
console.log(currentMonth.daysInMonth); // e.g., 31 for March
83
console.log(currentMonth.inLeapYear); // true/false
84
console.log(currentMonth.monthsInYear); // 12 for Gregorian calendar
85
86
// Creating full dates from year-month
87
const firstOfMonth = currentMonth.toPlainDate({ day: 1 });
88
const lastOfMonth = currentMonth.toPlainDate({ day: currentMonth.daysInMonth });
89
90
// Monthly comparisons
91
const monthsBetween = fromString.until(nextMonth, { largestUnit: 'month' });
92
const isEarlier = Temporal.PlainYearMonth.compare(fromString, nextMonth) < 0;
93
94
// Business use cases
95
function getQuarterStart(yearMonth: Temporal.PlainYearMonth): Temporal.PlainYearMonth {
96
const quarterMonth = Math.floor((yearMonth.month - 1) / 3) * 3 + 1;
97
return yearMonth.with({ month: quarterMonth });
98
}
99
100
function getMonthlyReport(yearMonth: Temporal.PlainYearMonth) {
101
const startOfMonth = yearMonth.toPlainDate({ day: 1 });
102
const endOfMonth = yearMonth.toPlainDate({ day: yearMonth.daysInMonth });
103
return { startOfMonth, endOfMonth, daysInMonth: yearMonth.daysInMonth };
104
}
105
```
106
107
### PlainMonthDay
108
109
Represents a month and day combination in a calendar system. Perfect for recurring events like birthdays, anniversaries, or holidays.
110
111
```typescript { .api }
112
/**
113
* Represents a month and day combination in a calendar
114
*/
115
class PlainMonthDay {
116
/** Creates a PlainMonthDay from various inputs */
117
static from(item: PlainMonthDayLike | string, options?: AssignmentOptions): PlainMonthDay;
118
119
// Month-day component properties
120
readonly calendarId: string;
121
readonly monthCode: string;
122
readonly day: number;
123
124
// Month-day manipulation methods
125
/** Returns a new PlainMonthDay with the specified fields changed */
126
with(monthDayLike: PlainMonthDayLike, options?: AssignmentOptions): PlainMonthDay;
127
128
// Comparison methods
129
/** Tests if this month-day equals another month-day */
130
equals(other: PlainMonthDayLike): boolean;
131
132
// Conversion methods
133
/** Combines this month-day with a year to create a PlainDate */
134
toPlainDate(year: PlainYearMonthLike): PlainDate;
135
136
// String representation methods
137
/** Returns a locale-formatted string representation */
138
toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
139
/** Returns an ISO 8601 string representation */
140
toString(options?: ShowCalendarOption): string;
141
/** Returns a JSON representation (same as toString) */
142
toJSON(): string;
143
/** Throws a TypeError when used in comparison operators */
144
valueOf(): never;
145
}
146
```
147
148
**Usage Examples:**
149
150
```typescript
151
import { Temporal } from "temporal-polyfill";
152
153
// Creating month-days
154
const birthday = Temporal.PlainMonthDay.from('06-15'); // June 15
155
const fromObject = Temporal.PlainMonthDay.from({ month: 12, day: 25 }); // Christmas
156
const fromDate = Temporal.PlainDate.from('2024-03-15').toPlainMonthDay();
157
158
// Creating specific year dates from month-day
159
const thisYear = birthday.toPlainDate({ year: 2024 });
160
const nextYear = birthday.toPlainDate({ year: 2025 });
161
162
// Holiday and recurring event handling
163
const holidays = [
164
Temporal.PlainMonthDay.from('01-01'), // New Year's Day
165
Temporal.PlainMonthDay.from('07-04'), // Independence Day
166
Temporal.PlainMonthDay.from('12-25'), // Christmas
167
];
168
169
function getHolidaysForYear(year: number): Temporal.PlainDate[] {
170
return holidays.map(holiday => holiday.toPlainDate({ year }));
171
}
172
173
function isHoliday(date: Temporal.PlainDate): boolean {
174
const monthDay = date.toPlainMonthDay();
175
return holidays.some(holiday => holiday.equals(monthDay));
176
}
177
178
// Age calculation on birthday
179
function getNextBirthday(
180
birthday: Temporal.PlainMonthDay,
181
referenceDate: Temporal.PlainDate = Temporal.Now.plainDateISO()
182
): Temporal.PlainDate {
183
let birthdayThisYear = birthday.toPlainDate({ year: referenceDate.year });
184
185
if (Temporal.PlainDate.compare(birthdayThisYear, referenceDate) < 0) {
186
// Birthday already passed this year, get next year's
187
birthdayThisYear = birthday.toPlainDate({ year: referenceDate.year + 1 });
188
}
189
190
return birthdayThisYear;
191
}
192
193
// Leap year handling
194
const feb29 = Temporal.PlainMonthDay.from('02-29');
195
196
function getLeapDayForYear(year: number): Temporal.PlainDate | null {
197
try {
198
return feb29.toPlainDate({ year });
199
} catch {
200
return null; // Not a leap year
201
}
202
}
203
204
// Subscription management
205
class RecurringEvent {
206
constructor(
207
public readonly monthDay: Temporal.PlainMonthDay,
208
public readonly description: string
209
) {}
210
211
getNextOccurrence(after: Temporal.PlainDate = Temporal.Now.plainDateISO()): Temporal.PlainDate {
212
let occurrence = this.monthDay.toPlainDate({ year: after.year });
213
214
if (Temporal.PlainDate.compare(occurrence, after) <= 0) {
215
occurrence = this.monthDay.toPlainDate({ year: after.year + 1 });
216
}
217
218
return occurrence;
219
}
220
221
getOccurrenceInYear(year: number): Temporal.PlainDate {
222
return this.monthDay.toPlainDate({ year });
223
}
224
}
225
226
const anniversary = new RecurringEvent(
227
Temporal.PlainMonthDay.from('06-01'),
228
'Company Anniversary'
229
);
230
```
231
232
### Calendar-Aware Operations
233
234
Working with different calendar systems and handling calendar-specific behavior.
235
236
```typescript { .api }
237
// Calendar interface (for reference)
238
interface Calendar {
239
readonly id: string;
240
dateFromFields(fields: DateLike, options?: AssignmentOptions): PlainDate;
241
yearMonthFromFields(fields: YearMonthLike, options?: AssignmentOptions): PlainYearMonth;
242
monthDayFromFields(fields: MonthDayLike, options?: AssignmentOptions): PlainMonthDay;
243
dateAdd(date: PlainDate, duration: Duration, options?: ArithmeticOptions): PlainDate;
244
dateUntil(one: PlainDate, two: PlainDate, options?: DifferenceOptions): Duration;
245
year(date: PlainDate): number;
246
month(date: PlainDate): number;
247
monthCode(date: PlainDate): string;
248
day(date: PlainDate): number;
249
era(date: PlainDate): string | undefined;
250
eraYear(date: PlainDate): number | undefined;
251
dayOfWeek(date: PlainDate): number;
252
dayOfYear(date: PlainDate): number;
253
weekOfYear(date: PlainDate): number;
254
daysInWeek(date: PlainDate): number;
255
daysInMonth(date: PlainDate): number;
256
daysInYear(date: PlainDate): number;
257
monthsInYear(date: PlainDate): number;
258
inLeapYear(date: PlainDate): boolean;
259
toString(): string;
260
toJSON(): string;
261
}
262
```
263
264
**Usage Examples:**
265
266
```typescript
267
import { Temporal } from "temporal-polyfill";
268
269
// Working with different calendars (theoretical - actual calendar support varies)
270
const gregorianYM = Temporal.PlainYearMonth.from('2024-03');
271
const isoYearMonth = gregorianYM.withCalendar('iso8601');
272
273
// Month code handling (important for non-Gregorian calendars)
274
const marchMD = Temporal.PlainMonthDay.from({ monthCode: 'M03', day: 15 });
275
console.log(marchMD.monthCode); // 'M03'
276
277
// Era-aware operations (for calendars with eras)
278
const historicalYM = Temporal.PlainYearMonth.from({
279
era: 'ce',
280
eraYear: 2024,
281
month: 3
282
});
283
284
// Calendar property access
285
function getCalendarInfo(yearMonth: Temporal.PlainYearMonth): object {
286
return {
287
calendar: yearMonth.calendarId,
288
year: yearMonth.year,
289
month: yearMonth.month,
290
monthCode: yearMonth.monthCode,
291
era: yearMonth.era,
292
eraYear: yearMonth.eraYear,
293
daysInMonth: yearMonth.daysInMonth,
294
daysInYear: yearMonth.daysInYear,
295
monthsInYear: yearMonth.monthsInYear,
296
inLeapYear: yearMonth.inLeapYear
297
};
298
}
299
```
300
301
## Types
302
303
```typescript { .api }
304
// Core type definitions for calendar system classes
305
type PlainYearMonthLike = PlainYearMonth | PlainYearMonthFields | string;
306
type PlainMonthDayLike = PlainMonthDay | PlainMonthDayFields | string;
307
type CalendarLike = string | Calendar;
308
309
interface PlainYearMonthFields {
310
era?: string;
311
eraYear?: number;
312
year: number;
313
month?: number;
314
monthCode?: string;
315
calendar?: CalendarLike;
316
}
317
318
interface PlainMonthDayFields {
319
monthCode?: string;
320
month?: number;
321
day: number;
322
calendar?: CalendarLike;
323
}
324
325
// Unit types for year-month operations
326
type YearMonthUnit = 'year' | 'month';
327
328
// Options for calendar system operations
329
interface ShowCalendarOption {
330
calendarName?: 'auto' | 'always' | 'never' | 'critical';
331
}
332
333
interface AssignmentOptions {
334
overflow?: OverflowMode;
335
}
336
337
interface ArithmeticOptions {
338
overflow?: OverflowMode;
339
}
340
341
interface DifferenceOptions<T extends string> {
342
largestUnit?: T;
343
smallestUnit?: T;
344
roundingIncrement?: number;
345
roundingMode?: RoundingMode;
346
}
347
348
// Common types
349
type OverflowMode = 'constrain' | 'reject';
350
type RoundingMode = 'ceil' | 'floor' | 'expand' | 'trunc' | 'halfCeil' | 'halfFloor' | 'halfExpand' | 'halfTrunc' | 'halfEven';
351
type ComparisonResult = -1 | 0 | 1;
352
353
// Date-like interface for toPlainDate operations
354
interface DateLike {
355
era?: string;
356
eraYear?: number;
357
year?: number;
358
month?: number;
359
monthCode?: string;
360
day?: number;
361
calendar?: CalendarLike;
362
}
363
364
interface YearMonthLike {
365
era?: string;
366
eraYear?: number;
367
year?: number;
368
month?: number;
369
monthCode?: string;
370
calendar?: CalendarLike;
371
}
372
373
interface MonthDayLike {
374
monthCode?: string;
375
month?: number;
376
day?: number;
377
calendar?: CalendarLike;
378
}
379
```