From e6eaee9f1ec038e46bec4063a89f564c0639a1ee Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 22 Jul 2024 12:23:28 +1200 Subject: [PATCH] adjust formatting apis --- packages/effect/src/DateTime.ts | 109 +++++++++----------------- packages/effect/test/DateTime.test.ts | 8 +- packages/schema/src/Schema.ts | 2 +- 3 files changed, 44 insertions(+), 75 deletions(-) diff --git a/packages/effect/src/DateTime.ts b/packages/effect/src/DateTime.ts index 57cfee975f6..b384b029f5b 100644 --- a/packages/effect/src/DateTime.ts +++ b/packages/effect/src/DateTime.ts @@ -235,7 +235,7 @@ const ProtoZoned = { Equal.equals(this.zone, that.zone) }, toString(this: Zoned) { - return `DateTime.Zoned(${zonedToString(this)})` + return `DateTime.Zoned(${formatIsoZoned(this)})` } } @@ -1011,17 +1011,6 @@ const offsetToString = (offset: number): string => { */ export const zonedOffsetIso = (self: Zoned): string => offsetToString(zonedOffset(self)) -/** - * Format a `DateTime.Zoned` as a string. - * - * It uses the format: `YYYY-MM-DDTHH:mm:ss.sss+HH:MM[Time/Zone]`. - * - * @since 3.6.0 - * @category conversions - */ -export const zonedToString = (self: Zoned): string => - self.zone._tag === "Offset" ? formatIsoOffset(self) : `${formatIsoOffset(self)}[${self.zone.id}]` - /** * Get the milliseconds since the Unix epoch of a `DateTime`. * @@ -1780,9 +1769,21 @@ export const endOf: { // formatting // ============================================================================= +const intlTimeZone = (self: TimeZone): string => { + if (self._tag === "Named") { + return self.id + } + return offsetToString(self.offset) +} + /** * Format a `DateTime` as a string using the `DateTimeFormat` API. * + * The `timeZone` option is set to the offset of the time zone. + * + * Note: On Node versions < 22, fixed "Offset" zones will set the time zone to + * "UTC" and use the adjusted `Date`. + * * @since 3.6.0 * @category formatting */ @@ -1809,7 +1810,19 @@ export const format: { readonly locale?: string | undefined } | undefined -): string => new Intl.DateTimeFormat(options?.locale, options).format(toEpochMillis(self))) +): string => { + try { + return new Intl.DateTimeFormat(options?.locale, { + timeZone: self._tag === "Utc" ? "UTC" : intlTimeZone(self.zone), + ...options + }).format(self.epochMillis) + } catch (_) { + return new Intl.DateTimeFormat(options?.locale, { + timeZone: "UTC", + ...options + }).format(toDate(self)) + } +}) /** * Format a `DateTime` as a string using the `DateTimeFormat` API. @@ -1846,7 +1859,7 @@ export const formatUtc: { new Intl.DateTimeFormat(options?.locale, { ...options, timeZone: "UTC" - }).format(toEpochMillis(self))) + }).format(self.epochMillis)) /** * Format a `DateTime` as a string using the `DateTimeFormat` API. @@ -1857,62 +1870,7 @@ export const formatUtc: { export const formatIntl: { (format: Intl.DateTimeFormat): (self: DateTime) => string (self: DateTime, format: Intl.DateTimeFormat): string -} = dual(2, (self: DateTime, format: Intl.DateTimeFormat): string => format.format(toEpochMillis(self))) - -const intlTimeZone = (self: TimeZone): string => { - if (self._tag === "Named") { - return self.id - } - return offsetToString(self.offset) -} - -/** - * Format a `DateTime` as a string using the `DateTimeFormat` API. - * - * The `timeZone` option is set to the offset of the time zone. - * - * Note: On Node versions < 22, fixed "Offset" zones will set the time zone to - * "UTC" and use the adjusted `Date`. - * - * @since 3.6.0 - * @category formatting - */ -export const formatZoned: { - ( - options?: - | Intl.DateTimeFormatOptions & { - readonly locale?: string | undefined - } - | undefined - ): (self: Zoned) => string - ( - self: Zoned, - options?: - | Intl.DateTimeFormatOptions & { - readonly locale?: string | undefined - } - | undefined - ): string -} = dual((args) => isDateTime(args[0]), ( - self: Zoned, - options?: - | Intl.DateTimeFormatOptions & { - readonly locale?: string | undefined - } - | undefined -): string => { - try { - return new Intl.DateTimeFormat(options?.locale, { - ...options, - timeZone: intlTimeZone(self.zone) - }).format(toEpochMillis(self)) - } catch (_) { - return new Intl.DateTimeFormat(options?.locale, { - ...options, - timeZone: "UTC" - }).format(toDate(self)) - } -}) +} = dual(2, (self: DateTime, format: Intl.DateTimeFormat): string => format.format(self.epochMillis)) /** * Format a `DateTime` as a UTC ISO string. @@ -1932,3 +1890,14 @@ export const formatIsoOffset = (self: DateTime): string => { const date = toDate(self) return self._tag === "Utc" ? date.toISOString() : `${date.toISOString().slice(0, -1)}${zonedOffsetIso(self)}` } + +/** + * Format a `DateTime.Zoned` as a string. + * + * It uses the format: `YYYY-MM-DDTHH:mm:ss.sss+HH:MM[Time/Zone]`. + * + * @since 3.6.0 + * @category formatting + */ +export const formatIsoZoned = (self: Zoned): string => + self.zone._tag === "Offset" ? formatIsoOffset(self) : `${formatIsoOffset(self)}[${self.zone.id}]` diff --git a/packages/effect/test/DateTime.test.ts b/packages/effect/test/DateTime.test.ts index 4fc2395db39..365f5b89d10 100644 --- a/packages/effect/test/DateTime.test.ts +++ b/packages/effect/test/DateTime.test.ts @@ -178,14 +178,14 @@ describe("DateTime", () => { })) }) - describe("formatWithZone", () => { + describe("format zoned", () => { it.effect("full", () => Effect.gen(function*() { const now = yield* DateTime.nowInCurrentZone.pipe( DateTime.withCurrentZoneNamed("Pacific/Auckland") ) assert.strictEqual( - DateTime.formatZoned(now, { dateStyle: "full", timeStyle: "full" }), + DateTime.format(now, { dateStyle: "full", timeStyle: "full" }), "Thursday, January 1, 1970 at 12:00:00 PM New Zealand Standard Time" ) })) @@ -195,7 +195,7 @@ describe("DateTime", () => { const now = yield* DateTime.now const formatted = now.pipe( DateTime.setZoneOffset(10 * 60 * 60 * 1000), - DateTime.formatZoned({ dateStyle: "long", timeStyle: "short" }) + DateTime.format({ dateStyle: "long", timeStyle: "short" }) ) assert.strictEqual(formatted, "January 1, 1970 at 10:00 AM") })) @@ -336,7 +336,7 @@ describe("DateTime", () => { it.effect("roundtrip", () => Effect.gen(function*() { const dt = yield* DateTime.makeZonedFromString("2024-07-21T20:12:34.112546348+12:00[Pacific/Auckland]").pipe( - Option.map(DateTime.zonedToString), + Option.map(DateTime.formatIsoZoned), Option.flatMap(DateTime.makeZonedFromString) ) assert.deepStrictEqual(dt.zone, DateTime.zoneUnsafeMakeNamed("Pacific/Auckland")) diff --git a/packages/schema/src/Schema.ts b/packages/schema/src/Schema.ts index 3848aab0494..2c0b1bf0aff 100644 --- a/packages/schema/src/Schema.ts +++ b/packages/schema/src/Schema.ts @@ -5946,7 +5946,7 @@ export class DateTimeZoned extends transformOrFail( onNone: () => ParseResult.fail(new ParseResult.Type(ast, s)), onSome: ParseResult.succeed }), - encode: (dt) => ParseResult.succeed(dateTime.zonedToString(dt)) + encode: (dt) => ParseResult.succeed(dateTime.formatIsoZoned(dt)) } ).annotations({ identifier: "DateTimeZoned" }) {}