@zwoninstitute/il-gaemi
Version:
Temporal 기반 Typescript 날짜/시간 유틸리티 패키지
1 lines • 62.5 kB
Source Map (JSON)
{"version":3,"sources":["../src/date/index.ts","../src/timezone/index.ts","../src/format/index.ts","../src/errors.ts","../src/transform/index.ts","../src/index.ts"],"sourcesContent":["import { Temporal } from \"@js-temporal/polyfill\";\nimport type { Holiday, WeekDay, PlainDate } from \"../types\";\nimport { InvalidDateError } from \"../errors\";\n\n/**\n * Determines whether a given date is a business day (workday).\n *\n * A business day is defined as a day that is:\n * - Not a weekend day (configurable, defaults to Saturday and Sunday)\n * - Not a holiday from the provided holiday list\n *\n * @param date - The date to check. Can be a Temporal.PlainDate object or an ISO date string (YYYY-MM-DD)\n * @param holidayList - An array of holiday objects. Each holiday can be either a one-time holiday or a recurring annual holiday\n * @param dayOffWeekdays - An array of weekday numbers representing non-working days. Uses ISO weekday numbering (1=Monday, 7=Sunday). Defaults to [6, 7] (Saturday, Sunday)\n * @returns `true` if the date is a business day, `false` otherwise\n *\n * @example\n * ```typescript\n * // Check if a specific date is a workday\n * const isWorkday1 = isWorkday('2024-01-15'); // true (Monday)\n * const isWorkday2 = isWorkday('2024-01-13'); // false (Saturday)\n *\n * // With custom holidays\n * const holidays = [\n * { date: '2024-01-01', recurring: false }, // New Year's Day\n * { date: '2024-12-25', recurring: true } // Christmas (recurring)\n * ];\n * const isWorkday3 = isWorkday('2024-01-01', holidays); // false\n *\n * // With custom weekend days (e.g., Friday-Saturday weekend)\n * const isWorkday4 = isWorkday('2024-01-12', [], [5, 6]); // false (Friday in this case)\n * ```\n */\nexport function isWorkday(\n date: PlainDate | string,\n holidayList: Holiday[] = [],\n dayOffWeekdays: WeekDay[] = [6, 7],\n): boolean {\n const plainDate = typeof date === \"string\" ? Temporal.PlainDate.from(date) : date;\n\n const dayOfWeek = plainDate.dayOfWeek;\n if (dayOffWeekdays.includes(dayOfWeek as WeekDay)) {\n return false;\n }\n\n const dateString = plainDate.toString();\n const isHoliday = holidayList.some((holiday) => {\n if (holiday.recurring) {\n const holidayDate = Temporal.PlainDate.from(holiday.date);\n return holidayDate.month === plainDate.month && holidayDate.day === plainDate.day;\n }\n return holiday.date === dateString;\n });\n\n return !isHoliday;\n}\n\n/**\n * Returns the day of the week for a given date using ISO weekday numbering.\n *\n * @param date - The date to get the weekday for. Can be a Temporal.PlainDate object or an ISO date string (YYYY-MM-DD)\n * @returns The weekday number (1=Monday, 2=Tuesday, ..., 7=Sunday)\n *\n * @example\n * ```typescript\n * const weekday1 = getWeekDay('2024-01-15'); // 1 (Monday)\n * const weekday2 = getWeekDay('2024-01-14'); // 7 (Sunday)\n *\n * // Using with Temporal.PlainDate\n * const date = Temporal.PlainDate.from('2024-01-16');\n * const weekday3 = getWeekDay(date); // 2 (Tuesday)\n * ```\n */\nexport function getWeekDay(date: PlainDate | string): WeekDay {\n const plainDate = typeof date === \"string\" ? Temporal.PlainDate.from(date) : date;\n\n return plainDate.dayOfWeek as WeekDay;\n}\n\n/**\n * Calculates which week number a given date belongs to within its month.\n *\n * The week calculation follows these rules:\n * - Weeks start on Monday (ISO week date system)\n * - If the Monday of the week containing the given date falls in a different month,\n * the week number is calculated based on that Monday's month\n * - Week numbering starts from 1\n *\n * @param date - The date to calculate the week number for. Can be a Temporal.PlainDate object or an ISO date string (YYYY-MM-DD)\n * @returns An object containing the year, month, and week number that the date belongs to\n *\n * @example\n * ```typescript\n * // For a date in the middle of a month\n * const week1 = getWeekNum('2024-01-15'); // { year: 2024, month: 1, weekNum: 3 }\n *\n * // For a date where the Monday falls in the previous month\n * const week2 = getWeekNum('2024-02-01'); // Might return { year: 2024, month: 1, weekNum: 5 }\n *\n * // Using with Temporal.PlainDate\n * const date = Temporal.PlainDate.from('2024-01-31');\n * const week3 = getWeekNum(date); // { year: 2024, month: 1, weekNum: 5 }\n * ```\n */\nexport function getWeekNum(date: PlainDate | string): { month: number; year: number; weekNum: number } {\n const plainDate = typeof date === \"string\" ? Temporal.PlainDate.from(date) : date;\n\n const dayOfWeek = plainDate.dayOfWeek;\n const daysFromMonday = dayOfWeek - 1;\n const mondayOfWeek = plainDate.subtract({ days: daysFromMonday });\n\n const targetMonth = mondayOfWeek.month;\n const targetYear = mondayOfWeek.year;\n\n const firstDayOfMonth = mondayOfWeek.with({ day: 1 });\n\n const firstDayWeekday = firstDayOfMonth.dayOfWeek;\n\n const daysToFirstMonday = firstDayWeekday === 1 ? 0 : 8 - firstDayWeekday;\n const firstMondayOfMonth = firstDayOfMonth.add({ days: daysToFirstMonday });\n\n const daysDiff = mondayOfWeek.since(firstMondayOfMonth).days;\n\n const weekNum = Math.floor(daysDiff / 7) + 1;\n\n return { month: targetMonth, year: targetYear, weekNum };\n}\n\n/**\n * Finds the next business day after a given date.\n *\n * This function will increment the date by one day repeatedly until it finds\n * a day that qualifies as a business day according to the `isWorkday` function.\n *\n * @param date - The starting date. Can be a Temporal.PlainDate object or an ISO date string (YYYY-MM-DD)\n * @param holidayList - An array of holiday objects to consider when determining business days\n * @returns The next business day as a Temporal.PlainDate object\n *\n * @example\n * ```typescript\n * // Find next workday after Friday\n * const nextWorkday1 = getNextWorkday('2024-01-12'); // 2024-01-15 (Monday)\n *\n * // Find next workday considering holidays\n * const holidays = [{ date: '2024-01-15', recurring: false }];\n * const nextWorkday2 = getNextWorkday('2024-01-12', holidays); // 2024-01-16 (Tuesday)\n *\n * // Using with Temporal.PlainDate\n * const date = Temporal.PlainDate.from('2024-01-31');\n * const nextWorkday3 = getNextWorkday(date); // 2024-02-01 or next available workday\n * ```\n */\nexport function getNextWorkday(\n date: PlainDate | string,\n holidayList: Holiday[] = [],\n dayOffWeekdays: WeekDay[] = [6, 7],\n): PlainDate {\n let currentDate = typeof date === \"string\" ? Temporal.PlainDate.from(date) : date;\n\n do {\n currentDate = currentDate.add({ days: 1 });\n } while (!isWorkday(currentDate, holidayList, dayOffWeekdays));\n\n return currentDate;\n}\n\n/**\n * Finds the previous business day before a given date.\n *\n * This function will decrement the date by one day repeatedly until it finds\n * a day that qualifies as a business day according to the `isWorkday` function.\n *\n * @param date - The starting date. Can be a Temporal.PlainDate object or an ISO date string (YYYY-MM-DD)\n * @param holidayList - An array of holiday objects to consider when determining business days\n * @returns The previous business day as a Temporal.PlainDate object\n *\n * @example\n * ```typescript\n * // Find previous workday before Monday\n * const prevWorkday1 = getPreviousWorkday('2024-01-15'); // 2024-01-12 (Friday)\n *\n * // Find previous workday considering holidays\n * const holidays = [{ date: '2024-01-12', recurring: false }];\n * const prevWorkday2 = getPreviousWorkday('2024-01-15', holidays); // 2024-01-11 (Thursday)\n *\n * // Using with Temporal.PlainDate\n * const date = Temporal.PlainDate.from('2024-02-01');\n * const prevWorkday3 = getPreviousWorkday(date); // 2024-01-31 or previous available workday\n * ```\n */\nexport function getPreviousWorkday(\n date: PlainDate | string,\n holidayList: Holiday[] = [],\n dayOffWeekdays: WeekDay[] = [6, 7],\n): PlainDate {\n let currentDate = typeof date === \"string\" ? Temporal.PlainDate.from(date) : date;\n\n do {\n currentDate = currentDate.subtract({ days: 1 });\n } while (!isWorkday(currentDate, holidayList, dayOffWeekdays));\n\n return currentDate;\n}\n","import { Temporal } from \"@js-temporal/polyfill\";\nimport type { ZonedDateTime } from \"../types\";\nimport { InvalidDateError, InvalidDateFormatError } from \"../errors\";\n\n/**\n * Default timezone for the library (Korea Standard Time).\n *\n * This constant is used as the default timezone throughout the library\n * when no specific timezone is provided.\n */\nexport const DEFAULT_TIMEZONE = \"Asia/Seoul\";\n\n/**\n * Returns the current date and time in Asia/Seoul timezone.\n *\n * This is a convenience function that provides the current moment\n * in Korean Standard Time (KST).\n *\n * @returns The current ZonedDateTime in Asia/Seoul timezone\n *\n * @example\n * ```typescript\n * const now = getNow();\n * console.log(now.toString()); // \"2024-01-15T14:30:00+09:00[Asia/Seoul]\"\n *\n * // Access individual components\n * console.log(now.year); // 2024\n * console.log(now.month); // 1\n * console.log(now.day); // 15\n * console.log(now.hour); // 14\n * ```\n */\nexport function getNow(): ZonedDateTime {\n return Temporal.Now.zonedDateTimeISO(DEFAULT_TIMEZONE);\n}\n\n/**\n * Creates a date in the default timezone (Asia/Seoul).\n *\n * @param year - The year\n * @param month - The month (1-12)\n * @param day - The day (1-31)\n * @returns A ZonedDateTime object in the default timezone\n *\n * @example\n * ```typescript\n * const date = getDate(2024, 1, 15);\n * console.log(date.toString()); // \"2024-01-15T00:00:00+09:00[Asia/Seoul]\"\n * ```\n */\nexport function getDate(year: number, month: number, day: number): ZonedDateTime {\n return Temporal.PlainDate.from({ year, month, day }).toZonedDateTime(DEFAULT_TIMEZONE);\n}\n\n/**\n * Creates a date and time in the default timezone (Asia/Seoul).\n *\n * @param year - The year\n * @param month - The month (1-12)\n * @param day - The day (1-31)\n * @param hour - The hour (0-23)\n * @param minute - The minute (0-59)\n * @param second - The second (0-59, optional)\n * @param millisecond - The millisecond (0-999, optional)\n * @param microsecond - The microsecond (0-999, optional)\n * @param nanosecond - The nanosecond (0-999, optional)\n * @returns A ZonedDateTime object in the default timezone\n *\n * @example\n * ```typescript\n * const dateTime = getDateTime(2024, 1, 15, 14, 30, 45, 123, 456, 789);\n * console.log(dateTime.toString()); // \"2024-01-15T14:30:45.123456789+09:00[Asia/Seoul]\"\n * ```\n */\nexport function getDateTime(\n year: number,\n month: number,\n day: number,\n hour: number,\n minute: number,\n second?: number,\n millisecond?: number,\n microsecond?: number,\n nanosecond?: number,\n): ZonedDateTime {\n return Temporal.PlainDateTime.from({\n year,\n month,\n day,\n hour,\n minute,\n second,\n millisecond,\n microsecond,\n nanosecond,\n }).toZonedDateTime(DEFAULT_TIMEZONE);\n}\n\n/**\n * Creates a date and time in UTC timezone.\n *\n * @param year - The year\n * @param month - The month (1-12)\n * @param day - The day (1-31)\n * @param hour - The hour (0-23)\n * @param minute - The minute (0-59)\n * @param second - The second (0-59, optional)\n * @param millisecond - The millisecond (0-999, optional)\n * @param microsecond - The microsecond (0-999, optional)\n * @param nanosecond - The nanosecond (0-999, optional)\n * @returns A ZonedDateTime object in UTC timezone\n *\n * @example\n * ```typescript\n * const utcDateTime = getDateTimeUTC(2024, 1, 15, 14, 30, 45);\n * console.log(utcDateTime.toString()); // \"2024-01-15T14:30:45+00:00[UTC]\"\n * ```\n */\nexport function getDateTimeUTC(\n year: number,\n month: number,\n day: number,\n hour: number,\n minute: number,\n second?: number,\n millisecond?: number,\n microsecond?: number,\n nanosecond?: number,\n): ZonedDateTime {\n return Temporal.PlainDateTime.from({\n year,\n month,\n day,\n hour,\n minute,\n second,\n millisecond,\n microsecond,\n nanosecond,\n }).toZonedDateTime(\"UTC\");\n}\n\n/**\n * Creates a date in UTC timezone.\n *\n * @param year - The year\n * @param month - The month (1-12)\n * @param day - The day (1-31)\n * @returns A ZonedDateTime object in UTC timezone\n *\n * @example\n * ```typescript\n * const utcDate = getDateUTC(2024, 1, 15);\n * console.log(utcDate.toString()); // \"2024-01-15T00:00:00+00:00[UTC]\"\n * ```\n */\nexport function getDateUTC(year: number, month: number, day: number): ZonedDateTime {\n return Temporal.PlainDate.from({ year, month, day }).toZonedDateTime(\"UTC\");\n}\n\n/**\n * Creates a PlainTime object with time information.\n *\n * @param hour - The hour (0-23)\n * @param minute - The minute (0-59)\n * @param second - The second (0-59, optional)\n * @param millisecond - The millisecond (0-999, optional)\n * @param microsecond - The microsecond (0-999, optional)\n * @param nanosecond - The nanosecond (0-999, optional)\n * @returns A PlainTime object\n *\n * @example\n * ```typescript\n * const time = getTime(14, 30, 45, 123, 456, 789);\n * console.log(time.toString()); // \"14:30:45.123456789\"\n * ```\n */\nexport function getTime(\n hour: number,\n minute: number,\n second?: number,\n millisecond?: number,\n microsecond?: number,\n nanosecond?: number,\n): Temporal.PlainTime {\n return Temporal.PlainTime.from({ hour, minute, second, millisecond, microsecond, nanosecond });\n}\n\n/**\n * Returns the current date and time in UTC timezone.\n *\n * This function provides the current moment in Coordinated Universal Time (UTC),\n * which is useful for storing timestamps in a timezone-neutral format.\n *\n * @returns The current ZonedDateTime in UTC timezone\n *\n * @example\n * ```typescript\n * const nowUTC = getNowUTC();\n * console.log(nowUTC.toString()); // \"2024-01-15T05:30:00+00:00[UTC]\"\n *\n * // Compare with local time\n * const nowLocal = getNow();\n * console.log(nowLocal.toString()); // \"2024-01-15T14:30:00+09:00[Asia/Seoul]\"\n *\n * // Both represent the same instant\n * console.log(nowUTC.epochMilliseconds === nowLocal.epochMilliseconds); // true\n * ```\n */\nexport function getNowUTC(): ZonedDateTime {\n return Temporal.Now.zonedDateTimeISO(\"UTC\");\n}\n\n/**\n * Converts a date/time to a ZonedDateTime in the specified timezone.\n *\n * This function handles various input types and converts them to a ZonedDateTime\n * with the specified timezone. It's particularly useful for timezone conversions\n * and ensuring consistent timezone handling throughout an application.\n *\n * @param date - The date/time to convert. Can be a ZonedDateTime, PlainDateTime, or an ISO string\n * @param timeZone - The target timezone. Defaults to Asia/Seoul\n * @returns A ZonedDateTime in the specified timezone\n *\n * @example\n * ```typescript\n * // From string (date only) - assumes start of day in target timezone\n * const zoned1 = convertToZonedDateTime('2024-01-15');\n * console.log(zoned1.toString()); // \"2024-01-15T00:00:00+09:00[Asia/Seoul]\"\n *\n * // From ISO datetime string - converts to target timezone\n * const zoned2 = convertToZonedDateTime('2024-01-15T12:00:00Z', 'America/New_York');\n * console.log(zoned2.toString()); // \"2024-01-15T07:00:00-05:00[America/New_York]\"\n *\n * // From PlainDateTime - interprets in target timezone\n * const plainDT = Temporal.PlainDateTime.from('2024-01-15T12:00:00');\n * const zoned3 = convertToZonedDateTime(plainDT, 'Europe/London');\n * console.log(zoned3.toString()); // \"2024-01-15T12:00:00+00:00[Europe/London]\"\n *\n * // From existing ZonedDateTime - converts to new timezone\n * const existing = Temporal.Now.zonedDateTimeISO('UTC');\n * const converted = convertToZonedDateTime(existing, 'Asia/Tokyo');\n * // Same instant, different timezone representation\n * ```\n */\nexport function convertToZonedDateTime(\n date: ZonedDateTime | Temporal.PlainDateTime | string,\n timeZone: string = DEFAULT_TIMEZONE,\n): ZonedDateTime {\n if (typeof date === \"string\") {\n if (date.includes(\"T\")) {\n return Temporal.Instant.from(date).toZonedDateTimeISO(timeZone);\n }\n const plainDate = Temporal.PlainDate.from(date);\n const plainDateTime = plainDate.toPlainDateTime(Temporal.PlainTime.from(\"00:00:00\"));\n return plainDateTime.toZonedDateTime(timeZone);\n }\n\n if (date instanceof Temporal.PlainDateTime) {\n return date.toZonedDateTime(timeZone);\n }\n\n return date.withTimeZone(timeZone);\n}\n\n/**\n * Converts a ZonedDateTime to UTC timezone.\n *\n * This function takes a ZonedDateTime in any timezone and returns\n * the equivalent moment in UTC. The instant in time remains the same,\n * only the timezone representation changes.\n *\n * @param zonedDateTime - The ZonedDateTime to convert to UTC\n * @returns The same instant represented in UTC timezone\n *\n * @example\n * ```typescript\n * // Convert Korean time to UTC\n * const kst = Temporal.ZonedDateTime.from('2024-01-15T14:30:00+09:00[Asia/Seoul]');\n * const utc = toUTC(kst);\n * console.log(utc.toString()); // \"2024-01-15T05:30:00+00:00[UTC]\"\n *\n * // The epoch milliseconds are identical (same instant)\n * console.log(kst.epochMilliseconds === utc.epochMilliseconds); // true\n *\n * // Different timezone representations\n * console.log(kst.timeZone.id); // \"Asia/Seoul\"\n * console.log(utc.timeZone.id); // \"UTC\"\n * ```\n */\nexport function toUTC(zonedDateTime: ZonedDateTime): ZonedDateTime {\n return zonedDateTime.withTimeZone(\"UTC\");\n}\n\n/**\n * Converts a UTC ZonedDateTime to a specified timezone.\n *\n * This function takes a ZonedDateTime in UTC and converts it to\n * the specified timezone. This is the inverse operation of `toUTC`.\n *\n * @param utcDateTime - The UTC ZonedDateTime to convert\n * @param timeZone - The target timezone. Defaults to Asia/Seoul\n * @returns The same instant represented in the target timezone\n *\n * @example\n * ```typescript\n * // Start with UTC time\n * const utc = Temporal.ZonedDateTime.from('2024-01-15T05:30:00+00:00[UTC]');\n *\n * // Convert to different timezones\n * const kst = fromUTC(utc); // Default to Asia/Seoul\n * console.log(kst.toString()); // \"2024-01-15T14:30:00+09:00[Asia/Seoul]\"\n *\n * const est = fromUTC(utc, 'America/New_York');\n * console.log(est.toString()); // \"2024-01-15T00:30:00-05:00[America/New_York]\"\n *\n * const jst = fromUTC(utc, 'Asia/Tokyo');\n * console.log(jst.toString()); // \"2024-01-15T14:30:00+09:00[Asia/Tokyo]\"\n *\n * // All represent the same instant\n * console.log(utc.epochMilliseconds === kst.epochMilliseconds); // true\n * ```\n */\nexport function fromUTC(utcDateTime: ZonedDateTime, timeZone: string = DEFAULT_TIMEZONE): ZonedDateTime {\n return utcDateTime.withTimeZone(timeZone);\n}\n\n/**\n * Calculates the time difference between two timezones in hours.\n *\n * This function determines how many hours ahead or behind the target timezone\n * is compared to the source timezone. Positive values indicate the target\n * is ahead, negative values indicate it's behind.\n *\n * @param fromTimeZone - The source timezone to compare from\n * @param toTimeZone - The target timezone to compare to\n * @param referenceDate - The reference date for calculation. Defaults to current time in Asia/Seoul. This is important for timezones with daylight saving time\n * @returns The time difference in hours (positive if target is ahead, negative if behind)\n *\n * @example\n * ```typescript\n * // Calculate offset from UTC to different timezones\n * const utcToKst = getTimeZoneOffset('UTC', 'Asia/Seoul');\n * console.log(utcToKst); // 9 (KST is UTC+9)\n *\n * const utcToEst = getTimeZoneOffset('UTC', 'America/New_York');\n * console.log(utcToEst); // -5 (EST is UTC-5) or -4 (EDT is UTC-4) depending on date\n *\n * // Calculate offset between non-UTC timezones\n * const kstToJst = getTimeZoneOffset('Asia/Seoul', 'Asia/Tokyo');\n * console.log(kstToJst); // 0 (both are UTC+9)\n *\n * const kstToEst = getTimeZoneOffset('Asia/Seoul', 'America/New_York');\n * console.log(kstToEst); // -14 (or -13 during EDT)\n *\n * // With specific reference date (useful for historical calculations)\n * const summerDate = Temporal.ZonedDateTime.from('2024-07-15T12:00:00+09:00[Asia/Seoul]');\n * const summerOffset = getTimeZoneOffset('UTC', 'America/New_York', summerDate);\n * console.log(summerOffset); // -4 (EDT in summer)\n *\n * const winterDate = Temporal.ZonedDateTime.from('2024-01-15T12:00:00+09:00[Asia/Seoul]');\n * const winterOffset = getTimeZoneOffset('UTC', 'America/New_York', winterDate);\n * console.log(winterOffset); // -5 (EST in winter)\n * ```\n */\nexport function getTimeZoneOffset(fromTimeZone: string, toTimeZone: string, referenceDate?: ZonedDateTime): number {\n const baseDate = referenceDate || getNow();\n const fromZoned = baseDate.withTimeZone(fromTimeZone);\n const toZoned = baseDate.withTimeZone(toTimeZone);\n\n const fromOffset = fromZoned.offsetNanoseconds;\n const toOffset = toZoned.offsetNanoseconds;\n\n return (toOffset - fromOffset) / (1000 * 1000 * 1000 * 60 * 60); // 나노초를 시간으로 변환\n}\n","import { Temporal } from \"@js-temporal/polyfill\";\nimport type { DateFormatType, ZonedDateTime, PlainDate, PlainDateTime } from \"../types\";\nimport {\n InvalidDateFormatError,\n InvalidDateError,\n UnsupportedFormatTypeError,\n MissingParameterError,\n IncompatibleOperationError,\n} from \"../errors\";\n\n/**\n * Predefined format patterns for common date/time formatting needs.\n */\nconst FORMAT_PATTERNS = {\n date: \"YYYY-MM-DD\",\n time: \"HH:mm:ss\",\n datetime: \"YYYY-MM-DD HH:mm:ss\",\n iso: \"ISO\",\n} as const;\n\n/**\n * Parses various date string formats and converts them to Temporal objects.\n *\n * Supported formats:\n * - ISO format: '2024-01-15', '2024-01-15T14:30:00'\n * - Dot separated: '2024.01.15', '24.01.15'\n * - Slash separated: '2024/01/15', '01/15/24'\n * - Korean format: '2024년 1월 15일', '2024년1월15일'\n * - Compact format: '20240115'\n * - Various separators: '2024-1-15', '2024.1.15'\n *\n * @param dateString - The date string to parse\n * @returns A Temporal PlainDate or ZonedDateTime object\n * @throws {Error} When the date string format is not recognized or invalid\n */\nfunction parseFlexibleDateString(dateString: string): PlainDate | ZonedDateTime | PlainDateTime {\n const trimmed = dateString.trim();\n\n // ISO format with timezone (ZonedDateTime)\n if (trimmed.includes(\"T\") && (trimmed.includes(\"+\") || trimmed.includes(\"Z\") || trimmed.includes(\"[\"))) {\n try {\n return Temporal.ZonedDateTime.from(trimmed);\n } catch {\n throw new InvalidDateError(trimmed);\n }\n }\n\n // ISO datetime format without timezone\n if (trimmed.includes(\"T\")) {\n try {\n return Temporal.PlainDateTime.from(trimmed);\n } catch {\n throw new InvalidDateError(trimmed);\n }\n }\n\n // Standard ISO date format\n if (/^\\d{4}-\\d{1,2}-\\d{1,2}$/.test(trimmed)) {\n try {\n return Temporal.PlainDate.from(trimmed);\n } catch {\n throw new InvalidDateError(trimmed);\n }\n }\n\n // Korean format: '2024년 1월 15일' or '2024년1월15일'\n const koreanMatch = trimmed.match(/(\\d{4})년\\s*(\\d{1,2})월\\s*(\\d{1,2})일/);\n if (koreanMatch) {\n const [, year, month, day] = koreanMatch;\n try {\n return Temporal.PlainDate.from({\n year: parseInt(year),\n month: parseInt(month),\n day: parseInt(day),\n });\n } catch {\n throw new InvalidDateError(trimmed);\n }\n }\n\n // Dot separated format: '2024.01.15', '24.01.15'\n const dotMatch = trimmed.match(/^(\\d{2,4})\\.(\\d{1,2})\\.(\\d{1,2})$/);\n if (dotMatch) {\n let [, year, month, day] = dotMatch;\n // Handle 2-digit year\n if (year.length === 2) {\n const currentYear = new Date().getFullYear();\n const century = Math.floor(currentYear / 100) * 100;\n const twoDigitYear = parseInt(year);\n year = (century + twoDigitYear).toString();\n }\n try {\n return Temporal.PlainDate.from({\n year: parseInt(year),\n month: parseInt(month),\n day: parseInt(day),\n });\n } catch {\n throw new InvalidDateError(trimmed);\n }\n }\n\n // Slash separated format: '2024/01/15', '01/15/24'\n const slashMatch = trimmed.match(/^(\\d{1,4})\\/(\\d{1,2})\\/(\\d{1,4})$/);\n if (slashMatch) {\n let [, first, second, third] = slashMatch;\n let year: string, month: string, day: string;\n\n // Determine if it's MM/DD/YY or YYYY/MM/DD format\n if (first.length === 4) {\n // YYYY/MM/DD format\n year = first;\n month = second;\n day = third;\n } else if (third.length <= 2) {\n // MM/DD/YY format\n month = first;\n day = second;\n const currentYear = new Date().getFullYear();\n const century = Math.floor(currentYear / 100) * 100;\n year = (century + parseInt(third)).toString();\n } else {\n // MM/DD/YYYY format\n month = first;\n day = second;\n year = third;\n }\n\n try {\n return Temporal.PlainDate.from({\n year: parseInt(year),\n month: parseInt(month),\n day: parseInt(day),\n });\n } catch {\n throw new InvalidDateError(trimmed);\n }\n }\n\n // Compact format: '20240115'\n const compactMatch = trimmed.match(/^(\\d{4})(\\d{2})(\\d{2})$/);\n if (compactMatch) {\n const [, year, month, day] = compactMatch;\n try {\n return Temporal.PlainDate.from({\n year: parseInt(year),\n month: parseInt(month),\n day: parseInt(day),\n });\n } catch {\n throw new InvalidDateError(trimmed);\n }\n }\n\n // Dash separated with single digits: '2024-1-15'\n const dashMatch = trimmed.match(/^(\\d{4})-(\\d{1,2})-(\\d{1,2})$/);\n if (dashMatch) {\n const [, year, month, day] = dashMatch;\n try {\n return Temporal.PlainDate.from({\n year: parseInt(year),\n month: parseInt(month),\n day: parseInt(day),\n });\n } catch {\n throw new InvalidDateError(trimmed);\n }\n }\n\n // Try default Temporal parsing as fallback\n try {\n return Temporal.PlainDate.from(trimmed);\n } catch {\n try {\n return Temporal.PlainDateTime.from(trimmed);\n } catch {\n try {\n return Temporal.ZonedDateTime.from(trimmed);\n } catch {\n throw new InvalidDateFormatError(dateString, [\n \"ISO 8601 (YYYY-MM-DD)\",\n \"ISO DateTime (YYYY-MM-DDTHH:mm:ss)\",\n \"ISO with timezone (YYYY-MM-DDTHH:mm:ss+09:00[Asia/Seoul])\",\n \"Korean format (2024년 1월 15일)\",\n \"Dot separated (2024.01.15)\",\n \"Slash separated (2024/01/15)\",\n \"Compact format (20240115)\",\n ]);\n }\n }\n }\n}\n\n/**\n * Formats a Temporal date/time object into a string representation.\n *\n * This function provides flexible formatting options for various Temporal types,\n * supporting predefined formats (date, time, datetime, iso) as well as custom formatting.\n *\n * @param date - The date/time to format. Can be a ZonedDateTime, PlainDate, PlainDateTime, or an ISO string\n * @param type - The format type to use. Defaults to \"datetime\"\n * @param formatString - Custom format string (required when type is \"custom\"). Supports tokens like YYYY, MM, DD, HH, mm, ss\n * @returns The formatted date/time string\n *\n * @throws {Error} When PlainDate is used with \"time\" format type\n * @throws {Error} When formatString is not provided for \"custom\" type\n * @throws {Error} When an unsupported format type is provided\n *\n * @example\n * ```typescript\n * // Basic formatting\n * const date = Temporal.PlainDate.from('2024-01-15');\n * const formatted1 = format(date, 'date'); // \"2024-01-15\"\n * const formatted2 = format(date, 'datetime'); // \"2024-01-15 00:00:00\"\n *\n * // With ZonedDateTime\n * const zonedDate = Temporal.Now.zonedDateTimeISO('Asia/Seoul');\n * const formatted3 = format(zonedDate, 'iso'); // ISO 8601 format\n *\n * // Custom formatting\n * const formatted4 = format(date, 'custom', 'YYYY/MM/DD'); // \"2024/01/15\"\n * const formatted5 = format(zonedDate, 'custom', 'YYYY-MM-DD HH:mm'); // \"2024-01-15 14:30\"\n *\n * // From string input\n * const formatted6 = format('2024-01-15', 'date'); // \"2024-01-15\"\n * ```\n */\nexport function format(\n date: ZonedDateTime | PlainDate | PlainDateTime | string,\n type: DateFormatType = \"datetime\",\n formatString?: string,\n): string {\n let temporalDate: ZonedDateTime | PlainDate | PlainDateTime;\n\n if (typeof date === \"string\") {\n temporalDate = parseFlexibleDateString(date);\n } else {\n temporalDate = date;\n }\n\n switch (type) {\n case \"date\":\n if (temporalDate instanceof Temporal.PlainDate) {\n return temporalDate.toString();\n }\n return temporalDate.toPlainDate().toString();\n\n case \"time\":\n if (temporalDate instanceof Temporal.PlainDate) {\n throw new IncompatibleOperationError(\"formatting as time\", \"PlainDate does not contain time information\");\n }\n return temporalDate.toPlainTime().toString();\n\n case \"datetime\":\n if (temporalDate instanceof Temporal.PlainDate) {\n return `${temporalDate.toString()} 00:00:00`;\n }\n const plainDateTime =\n temporalDate instanceof Temporal.ZonedDateTime ? temporalDate.toPlainDateTime() : temporalDate;\n return plainDateTime.toString().replace(\"T\", \" \");\n\n case \"iso\":\n if (temporalDate instanceof Temporal.ZonedDateTime) {\n return temporalDate.toString();\n }\n if (temporalDate instanceof Temporal.PlainDateTime) {\n return temporalDate.toString();\n }\n return temporalDate.toString();\n\n case \"custom\":\n if (!formatString) {\n throw new MissingParameterError(\"formatString\");\n }\n return formatCustom(temporalDate, formatString);\n\n default:\n throw new UnsupportedFormatTypeError(type, [\"date\", \"time\", \"datetime\", \"iso\", \"custom\"]);\n }\n}\n\n/**\n * Formats a Temporal object using a custom format string with token replacement.\n *\n * Supported format tokens:\n * - YYYY: 4-digit year (e.g., 2024)\n * - YY: 2-digit year (e.g., 24)\n * - MM: 2-digit month with leading zero (e.g., 01, 12)\n * - M: Month without leading zero (e.g., 1, 12)\n * - DD: 2-digit day with leading zero (e.g., 01, 31)\n * - D: Day without leading zero (e.g., 1, 31)\n * - HH: 2-digit hour with leading zero (e.g., 00, 23)\n * - H: Hour without leading zero (e.g., 0, 23)\n * - mm: 2-digit minute with leading zero (e.g., 00, 59)\n * - m: Minute without leading zero (e.g., 0, 59)\n * - ss: 2-digit second with leading zero (e.g., 00, 59)\n * - s: Second without leading zero (e.g., 0, 59)\n *\n * @param date - The Temporal object to format\n * @param formatString - The format string containing tokens to replace\n * @returns The formatted string with tokens replaced by actual values\n *\n * @example\n * ```typescript\n * const date = Temporal.PlainDate.from('2024-01-15');\n * const datetime = Temporal.PlainDateTime.from('2024-01-15T14:30:45');\n *\n * formatCustom(date, 'YYYY/MM/DD'); // \"2024/01/15\"\n * formatCustom(date, 'M/D/YY'); // \"1/15/24\"\n * formatCustom(datetime, 'YYYY-MM-DD HH:mm:ss'); // \"2024-01-15 14:30:45\"\n * formatCustom(datetime, 'H시 m분'); // \"14시 30분\"\n * ```\n */\nfunction formatCustom(date: ZonedDateTime | PlainDate | PlainDateTime, formatString: string): string {\n let result = formatString;\n\n const plainDate = date instanceof Temporal.PlainDate ? date : date.toPlainDate();\n\n const plainTime = date instanceof Temporal.PlainDate ? null : date.toPlainTime();\n\n result = result.replace(/YYYY/g, plainDate.year.toString().padStart(4, \"0\"));\n result = result.replace(/YY/g, (plainDate.year % 100).toString().padStart(2, \"0\"));\n\n result = result.replace(/MM/g, plainDate.month.toString().padStart(2, \"0\"));\n result = result.replace(/M/g, plainDate.month.toString());\n\n result = result.replace(/DD/g, plainDate.day.toString().padStart(2, \"0\"));\n result = result.replace(/D/g, plainDate.day.toString());\n\n if (plainTime) {\n result = result.replace(/HH/g, plainTime.hour.toString().padStart(2, \"0\"));\n result = result.replace(/H/g, plainTime.hour.toString());\n\n result = result.replace(/mm/g, plainTime.minute.toString().padStart(2, \"0\"));\n result = result.replace(/m/g, plainTime.minute.toString());\n\n result = result.replace(/ss/g, plainTime.second.toString().padStart(2, \"0\"));\n result = result.replace(/s/g, plainTime.second.toString());\n }\n\n return result;\n}\n\n/**\n * Formats a date in Korean style (e.g., \"2024년 1월 15일\").\n *\n * This is a convenience function that uses the custom format with Korean suffixes.\n *\n * @param date - The date to format. Can be a ZonedDateTime, PlainDate, PlainDateTime, or an ISO string\n * @returns A Korean-formatted date string\n *\n * @example\n * ```typescript\n * const date = Temporal.PlainDate.from('2024-01-15');\n * const korean = formatKorean(date); // \"2024년 1월 15일\"\n *\n * const datetime = Temporal.ZonedDateTime.from('2024-01-15T14:30:00+09:00[Asia/Seoul]');\n * const korean2 = formatKorean(datetime); // \"2024년 1월 15일\"\n *\n * // From string\n * const korean3 = formatKorean('2024-12-25'); // \"2024년 12월 25일\"\n * ```\n */\nexport function formatKorean(date: ZonedDateTime | PlainDate | PlainDateTime | string): string {\n return format(date, \"custom\", \"YYYY년 M월 D일\");\n}\n\n/**\n * Formats a date as a relative time expression (e.g., \"3 days ago\", \"2 hours later\").\n *\n * This function calculates the time difference between the given date and a base date,\n * then returns a human-readable relative time string in Korean.\n *\n * @param date - The target date to compare. Can be a ZonedDateTime, PlainDate, PlainDateTime, or an ISO string\n * @param baseDate - The reference date for comparison. Defaults to current time in Asia/Seoul timezone\n * @returns A Korean relative time string\n *\n * @example\n * ```typescript\n * const now = Temporal.Now.zonedDateTimeISO('Asia/Seoul');\n * const yesterday = now.subtract({ days: 1 });\n * const tomorrow = now.add({ days: 1 });\n * const twoHoursLater = now.add({ hours: 2 });\n * const fiveMinutesAgo = now.subtract({ minutes: 5 });\n *\n * formatRelative(yesterday); // \"1일 전\"\n * formatRelative(tomorrow); // \"1일 후\"\n * formatRelative(twoHoursLater); // \"2시간 후\"\n * formatRelative(fiveMinutesAgo); // \"5분 전\"\n *\n * // With custom base date\n * const baseDate = Temporal.ZonedDateTime.from('2024-01-15T12:00:00+09:00[Asia/Seoul]');\n * const targetDate = '2024-01-16T12:00:00+09:00[Asia/Seoul]';\n * formatRelative(targetDate, baseDate); // \"1일 후\"\n *\n * // Very recent times\n * const justNow = now.subtract({ seconds: 30 });\n * formatRelative(justNow); // \"방금 전\"\n * ```\n */\nexport function formatRelative(\n date: ZonedDateTime | PlainDate | PlainDateTime | string,\n baseDate?: ZonedDateTime,\n): string {\n const targetDate =\n typeof date === \"string\"\n ? (() => {\n const parsed = parseFlexibleDateString(date);\n return parsed instanceof Temporal.ZonedDateTime\n ? parsed\n : parsed instanceof Temporal.PlainDateTime\n ? parsed.toZonedDateTime(\"Asia/Seoul\")\n : parsed.toPlainDateTime(Temporal.PlainTime.from(\"00:00:00\")).toZonedDateTime(\"Asia/Seoul\");\n })()\n : date instanceof Temporal.ZonedDateTime\n ? date\n : date instanceof Temporal.PlainDateTime\n ? date.toZonedDateTime(\"Asia/Seoul\")\n : date.toPlainDateTime(Temporal.PlainTime.from(\"00:00:00\")).toZonedDateTime(\"Asia/Seoul\");\n\n const base = baseDate || Temporal.Now.zonedDateTimeISO(\"Asia/Seoul\");\n\n const duration = targetDate.since(base, { largestUnit: \"day\" });\n const days = duration.days;\n const hours = duration.hours;\n const minutes = duration.minutes;\n\n if (Math.abs(days) >= 1) {\n return days > 0 ? `${days}일 후` : `${Math.abs(days)}일 전`;\n }\n\n if (Math.abs(hours) >= 1) {\n return hours > 0 ? `${hours}시간 후` : `${Math.abs(hours)}시간 전`;\n }\n\n if (Math.abs(minutes) >= 1) {\n return minutes > 0 ? `${minutes}분 후` : `${Math.abs(minutes)}분 전`;\n }\n\n return \"방금 전\";\n}\n","/**\n * Base error class for all zwon-date-function errors\n */\nexport class DateError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DateError\";\n }\n}\n\n/**\n * Error thrown when an invalid date format is encountered\n */\nexport class InvalidDateFormatError extends DateError {\n constructor(dateString: string, supportedFormats?: string[]) {\n const message = supportedFormats\n ? `Unsupported date format: ${dateString}. Supported formats: ${supportedFormats.join(\", \")}`\n : `Unsupported date format: ${dateString}`;\n super(message);\n this.name = \"InvalidDateFormatError\";\n }\n}\n\n/**\n * Error thrown when an invalid date value is encountered\n */\nexport class InvalidDateError extends DateError {\n constructor(dateString: string) {\n super(`Invalid date: ${dateString}`);\n this.name = \"InvalidDateError\";\n }\n}\n\n/**\n * Error thrown when an unsupported format type is used\n */\nexport class UnsupportedFormatTypeError extends DateError {\n constructor(formatType: string, supportedTypes?: string[]) {\n const message = supportedTypes\n ? `Unsupported format type: ${formatType}. Supported types: ${supportedTypes.join(\", \")}`\n : `Unsupported format type: ${formatType}`;\n super(message);\n this.name = \"UnsupportedFormatTypeError\";\n }\n}\n\n/**\n * Error thrown when a required parameter is missing\n */\nexport class MissingParameterError extends DateError {\n constructor(parameterName: string) {\n super(`Missing required parameter: ${parameterName}`);\n this.name = \"MissingParameterError\";\n }\n}\n\n/**\n * Error thrown when an incompatible operation is attempted\n */\nexport class IncompatibleOperationError extends DateError {\n constructor(operation: string, reason: string) {\n super(`Incompatible operation: ${operation}. Reason: ${reason}`);\n this.name = \"IncompatibleOperationError\";\n }\n}\n","import { Temporal } from \"@js-temporal/polyfill\";\nimport type { ZonedDateTime, PlainDate, PlainDateTime } from \"../types\";\nimport { DEFAULT_TIMEZONE } from \"../timezone\";\n\n/**\n * 📚 **DATABASE STORAGE RECOMMENDATIONS**\n *\n * When storing Temporal data in databases, consider these patterns:\n *\n * **BEST PRACTICE: Two-field approach for ZonedDateTime**\n * ```sql\n * CREATE TABLE events (\n * id SERIAL PRIMARY KEY,\n * event_time_utc TIMESTAMP NOT NULL, -- Always UTC\n * event_timezone VARCHAR(50) NOT NULL -- e.g., 'Asia/Seoul'\n * );\n * ```\n *\n * **GOOD: Single field with Instant/ZonedDateTime**\n * ```typescript\n * // Store Instant or ZonedDateTime.epochMilliseconds\n * const instant = Temporal.Now.instant();\n * const date = temporalToDate(instant); // No data loss\n * ```\n *\n * **CAUTION: Single field with Plain types**\n * ```typescript\n * // Requires timezone assumption - document this clearly!\n * const plainDate = Temporal.PlainDate.from('2024-01-15');\n * const date = temporalToDate(plainDate); // Assumes Asia/Seoul\n * ```\n *\n * **AVOID: Storing timezone-less data without clear rules**\n * - Always document which timezone Plain types assume\n * - Consider using explicit functions like plainDateToDate() instead\n */\n\n/**\n * Converts a Temporal object to a JavaScript Date object for database storage.\n *\n * This function handles the conversion from various Temporal types to Date objects\n * that can be stored in database columns. It ensures proper timezone handling\n * and maintains the exact moment in time.\n *\n * ⚠️ **IMPORTANT TIMEZONE CONSIDERATIONS:**\n * - `Temporal.Instant` and `Temporal.ZonedDateTime`: No data loss (recommended)\n * - `Temporal.PlainDateTime` and `Temporal.PlainDate`: **Timezone assumption required**\n * - These are interpreted in the DEFAULT_TIMEZONE (Asia/Seoul)\n * - This is an arbitrary decision that may not match your intent\n * - Consider using ZonedDateTime instead for explicit timezone handling\n *\n * @param temporal - The Temporal object to convert\n * @returns A JavaScript Date object representing the same moment in time\n *\n * @example\n * ```typescript\n * // ✅ Recommended: No data loss\n * const instant = Temporal.Now.instant();\n * const zonedDateTime = getNow();\n * const dateFromInstant = temporalToDate(instant);\n * const dateFromZoned = temporalToDate(zonedDateTime);\n *\n * // ⚠️ Timezone assumption: Interpreted as Asia/Seoul\n * const plainDate = Temporal.PlainDate.from('2024-01-15');\n * const dateFromPlain = temporalToDate(plainDate);\n * // This assumes 2024-01-15 00:00:00 in Asia/Seoul timezone!\n *\n * const plainDateTime = Temporal.PlainDateTime.from('2024-01-15T14:30:00');\n * const dateFromPlainDT = temporalToDate(plainDateTime);\n * // This assumes the time is in Asia/Seoul timezone!\n * ```\n */\nexport function temporalToDate(\n temporal: Temporal.Instant | ZonedDateTime | PlainDate | PlainDateTime | null | undefined,\n): Date | null {\n if (!temporal) {\n return null;\n }\n\n if (temporal instanceof Temporal.Instant) {\n return new Date(temporal.epochMilliseconds);\n }\n\n if (temporal instanceof Temporal.ZonedDateTime) {\n return new Date(temporal.epochMilliseconds);\n }\n\n if (temporal instanceof Temporal.PlainDate) {\n const zonedDateTime = temporal.toZonedDateTime({\n timeZone: DEFAULT_TIMEZONE,\n plainTime: Temporal.PlainTime.from(\"00:00:00\"),\n });\n return new Date(zonedDateTime.epochMilliseconds);\n }\n\n if (temporal instanceof Temporal.PlainDateTime) {\n const zonedDateTime = temporal.toZonedDateTime(DEFAULT_TIMEZONE);\n return new Date(zonedDateTime.epochMilliseconds);\n }\n\n throw new Error(`Unsupported temporal type: ${typeof temporal}`);\n}\n\n/**\n * Converts a JavaScript Date object to a ZonedDateTime in the specified timezone.\n *\n * This function converts Date objects from the database back into ZonedDateTime\n * objects with proper timezone information. The default timezone is Asia/Seoul\n * but can be customized.\n *\n * @param date - The Date object to convert\n * @param timeZone - The target timezone (defaults to Asia/Seoul)\n * @returns A ZonedDateTime object in the specified timezone\n *\n * @example\n * ```typescript\n * const date = new Date('2024-01-15T05:30:00.000Z');\n * const zoned = dateToZonedDateTime(date);\n * console.log(zoned.timeZoneId); // \"Asia/Seoul\"\n * console.log(zoned.hour); // 14 (5:30 UTC = 14:30 KST)\n *\n * // Convert to different timezone\n * const nyTime = dateToZonedDateTime(date, 'America/New_York');\n * console.log(nyTime.hour); // 0 (5:30 UTC = 00:30 EST)\n * ```\n */\nexport function dateToZonedDateTime(\n date: Date | null | undefined,\n timeZone: string = DEFAULT_TIMEZONE,\n): ZonedDateTime | null {\n if (!date) {\n return null;\n }\n\n return Temporal.Instant.fromEpochMilliseconds(date.getTime()).toZonedDateTimeISO(timeZone);\n}\n\n/**\n * Converts a JavaScript Date object to a PlainDate.\n *\n * This function extracts the date components from a Date object and creates\n * a PlainDate. The conversion uses the default timezone to determine the\n * local date representation.\n *\n * @param date - The Date object to convert\n * @param timeZone - The timezone to use for date calculation (defaults to Asia/Seoul)\n * @returns A PlainDate object representing the date in the specified timezone\n *\n * @example\n * ```typescript\n * const date = new Date('2024-01-15T05:30:00.000Z');\n * const plainDate = dateToPlainDate(date);\n * console.log(plainDate.toString()); // \"2024-01-15\" (in Asia/Seoul timezone)\n *\n * // Same instant, different timezone\n * const utcPlainDate = dateToPlainDate(date, 'UTC');\n * console.log(utcPlainDate.toString()); // \"2024-01-15\" (in UTC)\n * ```\n */\nexport function dateToPlainDate(date: Date | null | undefined, timeZone: string = DEFAULT_TIMEZONE): PlainDate | null {\n if (!date) {\n return null;\n }\n\n const zonedDateTime = dateToZonedDateTime(date, timeZone);\n return zonedDateTime?.toPlainDate() || null;\n}\n\n/**\n * Converts a JavaScript Date object to a PlainDateTime.\n *\n * This function extracts the date and time components from a Date object\n * and creates a PlainDateTime. The conversion uses the specified timezone\n * to determine the local representation.\n *\n * @param date - The Date object to convert\n * @param timeZone - The timezone to use for calculation (defaults to Asia/Seoul)\n * @returns A PlainDateTime object representing the date and time in the specified timezone\n *\n * @example\n * ```typescript\n * const date = new Date('2024-01-15T05:30:00.000Z');\n * const plainDateTime = dateToPlainDateTime(date);\n * console.log(plainDateTime.toString()); // \"2024-01-15T14:30:00\" (in Asia/Seoul)\n *\n * // Same instant, different timezone\n * const utcPlainDateTime = dateToPlainDateTime(date, 'UTC');\n * console.log(utcPlainDateTime.toString()); // \"2024-01-15T05:30:00\" (in UTC)\n * ```\n */\nexport function dateToPlainDateTime(\n date: Date | null | undefined,\n timeZone: string = DEFAULT_TIMEZONE,\n): PlainDateTime | null {\n if (!date) {\n return null;\n }\n\n const zonedDateTime = dateToZonedDateTime(date, timeZone);\n return zonedDateTime?.toPlainDateTime() || null;\n}\n\n/**\n * 🚨 **SAFER ALTERNATIVES TO temporalToDate** 🚨\n *\n * These functions require explicit timezone specification for Plain types,\n * avoiding the implicit timezone assumption in temporalToDate.\n */\n\n/**\n * Safely converts PlainDate to Date with explicit timezone.\n *\n * @param plainDate - The PlainDate to convert\n * @param timeZone - The timezone to interpret the date in\n * @param timeOfDay - The time of day (defaults to start of day)\n * @returns Date object representing the specified moment\n *\n * @example\n * ```typescript\n * const plainDate = Temporal.PlainDate.from('2024-01-15');\n *\n * // Explicit timezone - safer than temporalToDate\n * const seoulDate = plainDateToDate(plainDate, 'Asia/Seoul');\n * const nyDate = plainDateToDate(plainDate, 'America/New_York');\n *\n * // With specific time\n * const noonDate = plainDateToDate(\n * plainDate,\n * 'Asia/Seoul',\n * Temporal.PlainTime.from('12:00:00')\n * );\n * ```\n */\nexport function plainDateToDate(\n plainDate: PlainDate,\n timeZone: string,\n timeOfDay: Temporal.PlainTime = Temporal.PlainTime.from(\"00:00:00\"),\n): Date {\n const zonedDateTime = plainDate.toZonedDateTime({\n timeZone,\n plainTime: timeOfDay,\n });\n return new Date(zonedDateTime.epochMilliseconds);\n}\n\n/**\n * Safely converts PlainDateTime to Date with explicit timezone.\n *\n * @param plainDateTime - The PlainDateTime to convert\n * @param timeZone - The timezone to interpret the datetime in\n * @returns Date object representing the specified moment\n *\n * @example\n * ```typescript\n * const plainDateTime = Temporal.PlainDateTime.from('2024-01-15T14:30:00');\n *\n * // Explicit timezone - safer than temporalToDate\n * const seoulDate = plainDateTimeToDate(plainDateTime, 'Asia/Seoul');\n * const utcDate = plainDateTimeToDate(plainDateTime, 'UTC');\n *\n * // These could represent very different moments in time!\n * console.log(seoulDate.getTime() !== utcDate.getTime()); // true\n * ```\n */\nexport function plainDateTimeToDate(plainDateTime: PlainDateTime, timeZone: string): Date {\n const zonedDateTime = plainDateTime.toZonedDateTime(timeZone);\n return new Date(zonedDateTime.epochMilliseconds);\n}\n","/**\n * @fileoverview A comprehensive date and time utility library built on top of the Temporal API.\n *\n * This library provides powerful date/time manipulation, formatting, timezone handling,\n * and business day calculations with a focus on Korean localization and international support.\n *\n * ## Features\n *\n * - **Business Day Calculations**: Determine workdays, skip holidays and weekends\n * - **Flexible Date Formatting**: Support for various output formats including Korean style\n * - **Timezone Management**: Convert between timezones with ease\n * - **Temporal API Integration**: Built on the modern Temporal API for precise date/time handling\n * - **Type Safety**: Full TypeScript support with comprehensive type definitions\n * - **Transform Integration**: Transform to Date Object, ZonedDateTime, PlainDate, PlainDateTime\n *\n * ## Quick Start\n *\n * ```typescript\n * import { isWorkday, format, getNow, getNextWorkday } from 'zwon-date-function';\n *\n * // Check if today is a business day\n * const today = getNow();\n * console.log(isWorkday(today)); // true/false\n *\n * // Format dates in different styles\n * console.log(format(today, 'date')); // \"2024-01-15\"\n * console.log(format(today, 'korean')); // \"2024년 1월 15일\"\n *\n * // Find the next business day\n * const nextWorkday = getNextWorkday(today);\n * console.log(format(nextWorkday, 'date')); // Next business day\n *\n * // Work with timezones\n * const utcTime = getNowUTC();\n * const koreanTime = convertToZonedDateTime(utcTime, 'Asia/Seoul');\n *\n * // Transform to Date Object, ZonedDateTime, PlainDate, PlainDateTime\n * import { temporalToDate } from 'zwon-date-function';\n *\n * ```\n *\n * ## Module Organization\n *\n * The library is organized into several modules:\n *\n * - **Date Module**: Business day calculations and week number utilities\n * - **Format Module**: Date/time formatting with multiple output styles\n * - **Timezone Module**: Timezone conversion and management utilities\n * - **Transfo