Skip to content

Commit

Permalink
adjust formatting apis
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart committed Jul 22, 2024
1 parent 0de2f34 commit e6eaee9
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 75 deletions.
109 changes: 39 additions & 70 deletions packages/effect/src/DateTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)})`
}
}

Expand Down Expand Up @@ -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`.
*
Expand Down Expand Up @@ -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
*/
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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}]`
8 changes: 4 additions & 4 deletions packages/effect/test/DateTime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
}))
Expand All @@ -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")
}))
Expand Down Expand Up @@ -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"))
Expand Down
2 changes: 1 addition & 1 deletion packages/schema/src/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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" }) {}

Expand Down

0 comments on commit e6eaee9

Please sign in to comment.