A lightweight polyfill for Temporal, successor to the JavaScript Date object
Overall
score
96%
Evaluation — 96%
↑ 1.19xAgent success when using this tile
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.
Represents a year and month combination in a calendar system. Ideal for monthly reports, subscription periods, or any year-month specific operations.
/**
* Represents a year and month combination in a calendar
*/
class PlainYearMonth {
/** Creates a PlainYearMonth from various inputs */
static from(item: PlainYearMonthLike | string, options?: AssignmentOptions): PlainYearMonth;
/** Compares two year-months and returns -1, 0, or 1 */
static compare(one: PlainYearMonthLike, two: PlainYearMonthLike): ComparisonResult;
// Year-month component properties
readonly calendarId: string;
readonly year: number;
readonly month: number;
readonly monthCode: string;
readonly era: string | undefined;
readonly eraYear: number | undefined;
// Calendar-computed properties
readonly daysInMonth: number;
readonly daysInYear: number;
readonly monthsInYear: number;
readonly inLeapYear: boolean;
// Year-month manipulation methods
/** Returns a new PlainYearMonth with the duration added */
add(duration: DurationLike, options?: ArithmeticOptions): PlainYearMonth;
/** Returns a new PlainYearMonth with the duration subtracted */
subtract(duration: DurationLike, options?: ArithmeticOptions): PlainYearMonth;
/** Returns a new PlainYearMonth with the specified fields changed */
with(yearMonthLike: PlainYearMonthLike, options?: AssignmentOptions): PlainYearMonth;
// Comparison and difference methods
/** Returns the duration from this year-month until the other year-month */
until(other: PlainYearMonthLike, options?: DifferenceOptions<YearMonthUnit>): Duration;
/** Returns the duration from the other year-month since this year-month */
since(other: PlainYearMonthLike, options?: DifferenceOptions<YearMonthUnit>): Duration;
/** Tests if this year-month equals another year-month */
equals(other: PlainYearMonthLike): boolean;
// Conversion methods
/** Combines this year-month with a day to create a PlainDate */
toPlainDate(day: PlainDateLike): PlainDate;
// String representation methods
/** Returns a locale-formatted string representation */
toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
/** Returns an ISO 8601 string representation */
toString(options?: ShowCalendarOption): string;
/** Returns a JSON representation (same as toString) */
toJSON(): string;
/** Throws a TypeError when used in comparison operators */
valueOf(): never;
}Usage Examples:
import { Temporal } from "temporal-polyfill";
// Creating year-months
const currentMonth = Temporal.Now.plainDateISO().toPlainYearMonth();
const fromString = Temporal.PlainYearMonth.from('2024-03');
const fromObject = Temporal.PlainYearMonth.from({ year: 2024, month: 3 });
// Monthly operations
const nextMonth = currentMonth.add({ months: 1 });
const lastYear = currentMonth.subtract({ years: 1 });
const sameMonthNextYear = currentMonth.with({ year: currentMonth.year + 1 });
// Calendar information
console.log(currentMonth.daysInMonth); // e.g., 31 for March
console.log(currentMonth.inLeapYear); // true/false
console.log(currentMonth.monthsInYear); // 12 for Gregorian calendar
// Creating full dates from year-month
const firstOfMonth = currentMonth.toPlainDate({ day: 1 });
const lastOfMonth = currentMonth.toPlainDate({ day: currentMonth.daysInMonth });
// Monthly comparisons
const monthsBetween = fromString.until(nextMonth, { largestUnit: 'month' });
const isEarlier = Temporal.PlainYearMonth.compare(fromString, nextMonth) < 0;
// Business use cases
function getQuarterStart(yearMonth: Temporal.PlainYearMonth): Temporal.PlainYearMonth {
const quarterMonth = Math.floor((yearMonth.month - 1) / 3) * 3 + 1;
return yearMonth.with({ month: quarterMonth });
}
function getMonthlyReport(yearMonth: Temporal.PlainYearMonth) {
const startOfMonth = yearMonth.toPlainDate({ day: 1 });
const endOfMonth = yearMonth.toPlainDate({ day: yearMonth.daysInMonth });
return { startOfMonth, endOfMonth, daysInMonth: yearMonth.daysInMonth };
}Represents a month and day combination in a calendar system. Perfect for recurring events like birthdays, anniversaries, or holidays.
/**
* Represents a month and day combination in a calendar
*/
class PlainMonthDay {
/** Creates a PlainMonthDay from various inputs */
static from(item: PlainMonthDayLike | string, options?: AssignmentOptions): PlainMonthDay;
// Month-day component properties
readonly calendarId: string;
readonly monthCode: string;
readonly day: number;
// Month-day manipulation methods
/** Returns a new PlainMonthDay with the specified fields changed */
with(monthDayLike: PlainMonthDayLike, options?: AssignmentOptions): PlainMonthDay;
// Comparison methods
/** Tests if this month-day equals another month-day */
equals(other: PlainMonthDayLike): boolean;
// Conversion methods
/** Combines this month-day with a year to create a PlainDate */
toPlainDate(year: PlainYearMonthLike): PlainDate;
// String representation methods
/** Returns a locale-formatted string representation */
toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
/** Returns an ISO 8601 string representation */
toString(options?: ShowCalendarOption): string;
/** Returns a JSON representation (same as toString) */
toJSON(): string;
/** Throws a TypeError when used in comparison operators */
valueOf(): never;
}Usage Examples:
import { Temporal } from "temporal-polyfill";
// Creating month-days
const birthday = Temporal.PlainMonthDay.from('06-15'); // June 15
const fromObject = Temporal.PlainMonthDay.from({ month: 12, day: 25 }); // Christmas
const fromDate = Temporal.PlainDate.from('2024-03-15').toPlainMonthDay();
// Creating specific year dates from month-day
const thisYear = birthday.toPlainDate({ year: 2024 });
const nextYear = birthday.toPlainDate({ year: 2025 });
// Holiday and recurring event handling
const holidays = [
Temporal.PlainMonthDay.from('01-01'), // New Year's Day
Temporal.PlainMonthDay.from('07-04'), // Independence Day
Temporal.PlainMonthDay.from('12-25'), // Christmas
];
function getHolidaysForYear(year: number): Temporal.PlainDate[] {
return holidays.map(holiday => holiday.toPlainDate({ year }));
}
function isHoliday(date: Temporal.PlainDate): boolean {
const monthDay = date.toPlainMonthDay();
return holidays.some(holiday => holiday.equals(monthDay));
}
// Age calculation on birthday
function getNextBirthday(
birthday: Temporal.PlainMonthDay,
referenceDate: Temporal.PlainDate = Temporal.Now.plainDateISO()
): Temporal.PlainDate {
let birthdayThisYear = birthday.toPlainDate({ year: referenceDate.year });
if (Temporal.PlainDate.compare(birthdayThisYear, referenceDate) < 0) {
// Birthday already passed this year, get next year's
birthdayThisYear = birthday.toPlainDate({ year: referenceDate.year + 1 });
}
return birthdayThisYear;
}
// Leap year handling
const feb29 = Temporal.PlainMonthDay.from('02-29');
function getLeapDayForYear(year: number): Temporal.PlainDate | null {
try {
return feb29.toPlainDate({ year });
} catch {
return null; // Not a leap year
}
}
// Subscription management
class RecurringEvent {
constructor(
public readonly monthDay: Temporal.PlainMonthDay,
public readonly description: string
) {}
getNextOccurrence(after: Temporal.PlainDate = Temporal.Now.plainDateISO()): Temporal.PlainDate {
let occurrence = this.monthDay.toPlainDate({ year: after.year });
if (Temporal.PlainDate.compare(occurrence, after) <= 0) {
occurrence = this.monthDay.toPlainDate({ year: after.year + 1 });
}
return occurrence;
}
getOccurrenceInYear(year: number): Temporal.PlainDate {
return this.monthDay.toPlainDate({ year });
}
}
const anniversary = new RecurringEvent(
Temporal.PlainMonthDay.from('06-01'),
'Company Anniversary'
);Working with different calendar systems and handling calendar-specific behavior.
// Calendar interface (for reference)
interface Calendar {
readonly id: string;
dateFromFields(fields: DateLike, options?: AssignmentOptions): PlainDate;
yearMonthFromFields(fields: YearMonthLike, options?: AssignmentOptions): PlainYearMonth;
monthDayFromFields(fields: MonthDayLike, options?: AssignmentOptions): PlainMonthDay;
dateAdd(date: PlainDate, duration: Duration, options?: ArithmeticOptions): PlainDate;
dateUntil(one: PlainDate, two: PlainDate, options?: DifferenceOptions): Duration;
year(date: PlainDate): number;
month(date: PlainDate): number;
monthCode(date: PlainDate): string;
day(date: PlainDate): number;
era(date: PlainDate): string | undefined;
eraYear(date: PlainDate): number | undefined;
dayOfWeek(date: PlainDate): number;
dayOfYear(date: PlainDate): number;
weekOfYear(date: PlainDate): number;
daysInWeek(date: PlainDate): number;
daysInMonth(date: PlainDate): number;
daysInYear(date: PlainDate): number;
monthsInYear(date: PlainDate): number;
inLeapYear(date: PlainDate): boolean;
toString(): string;
toJSON(): string;
}Usage Examples:
import { Temporal } from "temporal-polyfill";
// Working with different calendars (theoretical - actual calendar support varies)
const gregorianYM = Temporal.PlainYearMonth.from('2024-03');
const isoYearMonth = gregorianYM.withCalendar('iso8601');
// Month code handling (important for non-Gregorian calendars)
const marchMD = Temporal.PlainMonthDay.from({ monthCode: 'M03', day: 15 });
console.log(marchMD.monthCode); // 'M03'
// Era-aware operations (for calendars with eras)
const historicalYM = Temporal.PlainYearMonth.from({
era: 'ce',
eraYear: 2024,
month: 3
});
// Calendar property access
function getCalendarInfo(yearMonth: Temporal.PlainYearMonth): object {
return {
calendar: yearMonth.calendarId,
year: yearMonth.year,
month: yearMonth.month,
monthCode: yearMonth.monthCode,
era: yearMonth.era,
eraYear: yearMonth.eraYear,
daysInMonth: yearMonth.daysInMonth,
daysInYear: yearMonth.daysInYear,
monthsInYear: yearMonth.monthsInYear,
inLeapYear: yearMonth.inLeapYear
};
}// Core type definitions for calendar system classes
type PlainYearMonthLike = PlainYearMonth | PlainYearMonthFields | string;
type PlainMonthDayLike = PlainMonthDay | PlainMonthDayFields | string;
type CalendarLike = string | Calendar;
interface PlainYearMonthFields {
era?: string;
eraYear?: number;
year: number;
month?: number;
monthCode?: string;
calendar?: CalendarLike;
}
interface PlainMonthDayFields {
monthCode?: string;
month?: number;
day: number;
calendar?: CalendarLike;
}
// Unit types for year-month operations
type YearMonthUnit = 'year' | 'month';
// Options for calendar system operations
interface ShowCalendarOption {
calendarName?: 'auto' | 'always' | 'never' | 'critical';
}
interface AssignmentOptions {
overflow?: OverflowMode;
}
interface ArithmeticOptions {
overflow?: OverflowMode;
}
interface DifferenceOptions<T extends string> {
largestUnit?: T;
smallestUnit?: T;
roundingIncrement?: number;
roundingMode?: RoundingMode;
}
// Common types
type OverflowMode = 'constrain' | 'reject';
type RoundingMode = 'ceil' | 'floor' | 'expand' | 'trunc' | 'halfCeil' | 'halfFloor' | 'halfExpand' | 'halfTrunc' | 'halfEven';
type ComparisonResult = -1 | 0 | 1;
// Date-like interface for toPlainDate operations
interface DateLike {
era?: string;
eraYear?: number;
year?: number;
month?: number;
monthCode?: string;
day?: number;
calendar?: CalendarLike;
}
interface YearMonthLike {
era?: string;
eraYear?: number;
year?: number;
month?: number;
monthCode?: string;
calendar?: CalendarLike;
}
interface MonthDayLike {
monthCode?: string;
month?: number;
day?: number;
calendar?: CalendarLike;
}Install with Tessl CLI
npx tessl i tessl/npm-temporal-polyfilldocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10