149 lines
5.0 KiB
TypeScript
149 lines
5.0 KiB
TypeScript
import type { TextualYearMonth, MonthDay, UnixTimeRange } from './datetime.ts';
|
|
|
|
export class FiscalYearStart {
|
|
public static readonly JanuaryFirstDay = new FiscalYearStart(1, 1);
|
|
public static readonly Default = FiscalYearStart.JanuaryFirstDay;
|
|
|
|
private static readonly MONTH_MAX_DAYS: number[] = [
|
|
31, // January
|
|
28, // February (Disallow fiscal year start on leap day)
|
|
31, // March
|
|
30, // April
|
|
31, // May
|
|
30, // June
|
|
31, // July
|
|
31, // August
|
|
30, // September
|
|
31, // October
|
|
30, // November
|
|
31 // December
|
|
];
|
|
|
|
public readonly month: number; // 1-based (1 = January, 12 = December)
|
|
public readonly day: number;
|
|
public readonly value: number;
|
|
|
|
private constructor(month: number, day: number) {
|
|
this.month = month;
|
|
this.day = day;
|
|
this.value = (month << 8) | day;
|
|
}
|
|
|
|
public static of(month: number, day: number): FiscalYearStart | undefined {
|
|
if (!FiscalYearStart.isValidFiscalYearMonthDay(month, day)) {
|
|
return undefined;
|
|
}
|
|
|
|
return new FiscalYearStart(month, day);
|
|
}
|
|
|
|
/**
|
|
* Create a FiscalYearStart from a uint16 value (two bytes - month high, day low)
|
|
* @param value uint16 value (month in high byte, day in low byte)
|
|
* @returns FiscalYearStart instance or undefined if the value is out of range
|
|
*/
|
|
public static valueOf(value: number): FiscalYearStart | undefined {
|
|
if (value < 0x0101 || value > 0x0C1F) {
|
|
return undefined;
|
|
}
|
|
|
|
const month = (value >> 8) & 0xFF; // high byte
|
|
const day = value & 0xFF; // low byte
|
|
|
|
return FiscalYearStart.of(month, day);
|
|
}
|
|
|
|
/**
|
|
* Create a FiscalYearStart from a month/day string
|
|
* @param monthDay MM-dd string (e.g. "04-01" = 1 April)
|
|
* @returns FiscalYearStart instance or undefined if the monthDay is invalid
|
|
*/
|
|
public static parse(monthDay: string): FiscalYearStart | undefined {
|
|
if (!monthDay || !monthDay.includes('-')) {
|
|
return undefined;
|
|
}
|
|
|
|
const parts = monthDay.split('-');
|
|
|
|
if (parts.length !== 2) {
|
|
return undefined;
|
|
}
|
|
|
|
const month = parseInt(parts[0] as string, 10);
|
|
const day = parseInt(parts[1] as string, 10);
|
|
|
|
return FiscalYearStart.of(month, day);
|
|
}
|
|
|
|
public toMonthDashDayString(): TextualYearMonth {
|
|
return `${this.month.toString().padStart(2, '0')}-${this.day.toString().padStart(2, '0')}` as TextualYearMonth;
|
|
}
|
|
|
|
public toMonthDay(): MonthDay {
|
|
return {
|
|
month: this.month,
|
|
day: this.day
|
|
};
|
|
}
|
|
|
|
private static isValidFiscalYearMonthDay(month: number, day: number): boolean {
|
|
return 1 <= month && month <= 12 && 1 <= day && day <= (FiscalYearStart.MONTH_MAX_DAYS[month - 1] as number);
|
|
}
|
|
}
|
|
|
|
export class FiscalYearUnixTime implements UnixTimeRange {
|
|
public readonly year: number;
|
|
public readonly minUnixTime: number;
|
|
public readonly maxUnixTime: number;
|
|
|
|
private constructor(fiscalYear: number, minUnixTime: number, maxUnixTime: number) {
|
|
this.year = fiscalYear;
|
|
this.minUnixTime = minUnixTime;
|
|
this.maxUnixTime = maxUnixTime;
|
|
}
|
|
|
|
public static of(fiscalYear: number, minUnixTime: number, maxUnixTime: number): FiscalYearUnixTime {
|
|
return new FiscalYearUnixTime(fiscalYear, minUnixTime, maxUnixTime);
|
|
}
|
|
}
|
|
|
|
export const LANGUAGE_DEFAULT_FISCAL_YEAR_FORMAT_VALUE: number = 0;
|
|
|
|
export class FiscalYearFormat {
|
|
private static readonly allInstances: FiscalYearFormat[] = [];
|
|
private static readonly allInstancesByType: Record<number, FiscalYearFormat> = {};
|
|
private static readonly allInstancesByTypeName: Record<string, FiscalYearFormat> = {};
|
|
|
|
public static readonly StartYYYY_EndYYYY = new FiscalYearFormat(1, 'StartYYYY_EndYYYY');
|
|
public static readonly StartYYYY_EndYY = new FiscalYearFormat(2, 'StartYYYY_EndYY');
|
|
public static readonly StartYY_EndYY = new FiscalYearFormat(3, 'StartYY_EndYY');
|
|
public static readonly EndYYYY = new FiscalYearFormat(4, 'EndYYYY');
|
|
public static readonly EndYY = new FiscalYearFormat(5, 'EndYY');
|
|
|
|
public static readonly Default = FiscalYearFormat.EndYYYY;
|
|
|
|
public readonly type: number;
|
|
public readonly typeName: string;
|
|
|
|
private constructor(type: number, typeName: string) {
|
|
this.type = type;
|
|
this.typeName = typeName;
|
|
|
|
FiscalYearFormat.allInstances.push(this);
|
|
FiscalYearFormat.allInstancesByType[type] = this;
|
|
FiscalYearFormat.allInstancesByTypeName[typeName] = this;
|
|
}
|
|
|
|
public static values(): FiscalYearFormat[] {
|
|
return FiscalYearFormat.allInstances;
|
|
}
|
|
|
|
public static valueOf(type: number): FiscalYearFormat | undefined {
|
|
return FiscalYearFormat.allInstancesByType[type];
|
|
}
|
|
|
|
public static parse(typeName: string): FiscalYearFormat | undefined {
|
|
return FiscalYearFormat.allInstancesByTypeName[typeName];
|
|
}
|
|
}
|