@@ -215,6 +215,52 @@ export declare namespace TimeZone {
215215 }
216216}
217217
218+ /**
219+ * A `Disambiguation` is used to resolve ambiguities when a `DateTime` is
220+ * ambiguous, such as during a daylight saving time transition.
221+ *
222+ * For more information, see the [Temporal documentation](https://tc39.es/proposal-temporal/docs/timezone.html#ambiguity-due-to-dst-or-other-time-zone-offset-changes)
223+ *
224+ * - `"compatible"`: (default) Behavior matching Temporal API and legacy JavaScript Date and moment.js.
225+ * For repeated times, chooses the earlier occurrence. For gap times, chooses the later interpretation.
226+ *
227+ * - `"earlier"`: For repeated times, always choose the earlier occurrence.
228+ * For gap times, choose the time before the gap.
229+ *
230+ * - `"later"`: For repeated times, always choose the later occurrence.
231+ * For gap times, choose the time after the gap.
232+ *
233+ * - `"reject"`: Throw an `RangeError` when encountering ambiguous or non-existent times.
234+ *
235+ * @example
236+ * ```ts
237+ * import { DateTime } from "effect"
238+ *
239+ * // Fall-back example: 01:30 on Nov 2, 2025 in New York happens twice
240+ * const ambiguousTime = { year: 2025, month: 11, day: 2, hours: 1, minutes: 30 }
241+ * const timeZone = DateTime.zoneUnsafeMakeNamed("America/New_York")
242+ *
243+ * DateTime.makeZoned(ambiguousTime, { timeZone, adjustForTimeZone: true, disambiguation: "earlier" })
244+ * // Earlier occurrence (DST time): 2025-11-02T05:30:00.000Z
245+ *
246+ * DateTime.makeZoned(ambiguousTime, { timeZone, adjustForTimeZone: true, disambiguation: "later" })
247+ * // Later occurrence (standard time): 2025-11-02T06:30:00.000Z
248+ *
249+ * // Gap example: 02:30 on Mar 9, 2025 in New York doesn't exist
250+ * const gapTime = { year: 2025, month: 3, day: 9, hours: 2, minutes: 30 }
251+ *
252+ * DateTime.makeZoned(gapTime, { timeZone, adjustForTimeZone: true, disambiguation: "earlier" })
253+ * // Time before gap: 2025-03-09T06:30:00.000Z (01:30 EST)
254+ *
255+ * DateTime.makeZoned(gapTime, { timeZone, adjustForTimeZone: true, disambiguation: "later" })
256+ * // Time after gap: 2025-03-09T07:30:00.000Z (03:30 EDT)
257+ * ```
258+ *
259+ * @since 3.18.0
260+ * @category models
261+ */
262+ export type Disambiguation = "compatible" | "earlier" | "later" | "reject"
263+
218264// =============================================================================
219265// guards
220266// =============================================================================
@@ -332,6 +378,13 @@ export const unsafeMake: <A extends DateTime.Input>(input: A) => DateTime.Preser
332378 * `adjustForTimeZone` is set to `true`. In that case, the input is treated as
333379 * already in the time zone.
334380 *
381+ * When `adjustForTimeZone` is true and ambiguous times occur during DST transitions,
382+ * the `disambiguation` option controls how to resolve the ambiguity:
383+ * - `compatible` (default): Choose earlier time for repeated times, later for gaps
384+ * - `earlier`: Always choose the earlier of two possible times
385+ * - `later`: Always choose the later of two possible times
386+ * - `reject`: Throw an error when ambiguous times are encountered
387+ *
335388 * @since 3.6.0
336389 * @category constructors
337390 * @example
@@ -344,12 +397,22 @@ export const unsafeMake: <A extends DateTime.Input>(input: A) => DateTime.Preser
344397export const unsafeMakeZoned : ( input : DateTime . Input , options ?: {
345398 readonly timeZone ?: number | string | TimeZone | undefined
346399 readonly adjustForTimeZone ?: boolean | undefined
400+ readonly disambiguation ?: Disambiguation | undefined
347401} ) => Zoned = Internal . unsafeMakeZoned
348402
349403/**
350404 * Create a `DateTime.Zoned` using `DateTime.make` and a time zone.
351405 *
352- * The input is treated as UTC and then the time zone is attached.
406+ * The input is treated as UTC and then the time zone is attached, unless
407+ * `adjustForTimeZone` is set to `true`. In that case, the input is treated as
408+ * already in the time zone.
409+ *
410+ * When `adjustForTimeZone` is true and ambiguous times occur during DST transitions,
411+ * the `disambiguation` option controls how to resolve the ambiguity:
412+ * - `compatible` (default): Choose earlier time for repeated times, later for gaps
413+ * - `earlier`: Always choose the earlier of two possible times
414+ * - `later`: Always choose the later of two possible times
415+ * - `reject`: Throw an error when ambiguous times are encountered
353416 *
354417 * If the date time input or time zone is invalid, `None` will be returned.
355418 *
@@ -367,6 +430,7 @@ export const makeZoned: (
367430 options ?: {
368431 readonly timeZone ?: number | string | TimeZone | undefined
369432 readonly adjustForTimeZone ?: boolean | undefined
433+ readonly disambiguation ?: Disambiguation | undefined
370434 }
371435) => Option . Option < Zoned > = Internal . makeZoned
372436
@@ -491,9 +555,11 @@ export const toUtc: (self: DateTime) => Utc = Internal.toUtc
491555export const setZone : {
492556 ( zone : TimeZone , options ?: {
493557 readonly adjustForTimeZone ?: boolean | undefined
558+ readonly disambiguation ?: Disambiguation | undefined
494559 } ) : ( self : DateTime ) => Zoned
495560 ( self : DateTime , zone : TimeZone , options ?: {
496561 readonly adjustForTimeZone ?: boolean | undefined
562+ readonly disambiguation ?: Disambiguation | undefined
497563 } ) : Zoned
498564} = Internal . setZone
499565
@@ -519,9 +585,11 @@ export const setZone: {
519585export const setZoneOffset : {
520586 ( offset : number, options ?: {
521587 readonly adjustForTimeZone ?: boolean | undefined
588+ readonly disambiguation ?: Disambiguation | undefined
522589 } ) : ( self : DateTime ) => Zoned
523590 ( self : DateTime , offset : number , options ?: {
524591 readonly adjustForTimeZone ?: boolean | undefined
592+ readonly disambiguation ?: Disambiguation | undefined
525593 } ) : Zoned
526594} = Internal . setZoneOffset
527595
@@ -616,9 +684,11 @@ export const zoneToString: (self: TimeZone) => string = Internal.zoneToString
616684export const setZoneNamed : {
617685 ( zoneId : string, options ?: {
618686 readonly adjustForTimeZone ?: boolean | undefined
687+ readonly disambiguation ?: Disambiguation | undefined
619688 } ) : ( self : DateTime ) => Option . Option < Zoned >
620689 ( self : DateTime , zoneId : string , options ?: {
621690 readonly adjustForTimeZone ?: boolean | undefined
691+ readonly disambiguation ?: Disambiguation | undefined
622692 } ) : Option . Option < Zoned >
623693} = Internal . setZoneNamed
624694
@@ -642,9 +712,11 @@ export const setZoneNamed: {
642712export const unsafeSetZoneNamed : {
643713 ( zoneId : string, options ?: {
644714 readonly adjustForTimeZone ?: boolean | undefined
715+ readonly disambiguation ?: Disambiguation | undefined
645716 } ) : ( self : DateTime ) => Zoned
646717 ( self : DateTime , zoneId : string , options ?: {
647718 readonly adjustForTimeZone ?: boolean | undefined
719+ readonly disambiguation ?: Disambiguation | undefined
648720 } ) : Zoned
649721} = Internal . unsafeSetZoneNamed
650722
@@ -1149,12 +1221,25 @@ export const nowInCurrentZone: Effect.Effect<Zoned, never, CurrentTimeZone> = Ef
11491221 * The `Date` will first have the time zone applied if possible, and then be
11501222 * converted back to a `DateTime` within the same time zone.
11511223 *
1224+ * Supports `disambiguation` when the new wall clock time is ambiguous.
1225+ *
11521226 * @since 3.6.0
11531227 * @category mapping
11541228 */
11551229export const mutate : {
1156- ( f : ( date : Date ) = > void ) : < A extends DateTime > ( self : A ) => A
1157- < A extends DateTime > ( self : A , f : ( date : Date ) => void ) : A
1230+ (
1231+ f : ( date : Date ) = > void ,
1232+ options ?: {
1233+ readonly disambiguation ?: Disambiguation | undefined
1234+ }
1235+ ) : < A extends DateTime > ( self : A ) => A
1236+ < A extends DateTime > (
1237+ self : A ,
1238+ f : ( date : Date ) => void ,
1239+ options ?: {
1240+ readonly disambiguation ?: Disambiguation | undefined
1241+ }
1242+ ) : A
11581243} = Internal . mutate
11591244
11601245/**
0 commit comments