effect 3.17.2 → 3.17.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/DateTime.js +19 -1
- package/dist/cjs/DateTime.js.map +1 -1
- package/dist/cjs/Struct.js +1 -1
- package/dist/cjs/internal/dateTime.js +67 -10
- package/dist/cjs/internal/dateTime.js.map +1 -1
- package/dist/cjs/internal/version.js +1 -1
- package/dist/dts/DateTime.d.ts +84 -3
- package/dist/dts/DateTime.d.ts.map +1 -1
- package/dist/dts/Metric.d.ts +2 -2
- package/dist/dts/Metric.d.ts.map +1 -1
- package/dist/dts/Struct.d.ts +3 -3
- package/dist/esm/DateTime.js +19 -1
- package/dist/esm/DateTime.js.map +1 -1
- package/dist/esm/Struct.js +1 -1
- package/dist/esm/internal/dateTime.js +67 -10
- package/dist/esm/internal/dateTime.js.map +1 -1
- package/dist/esm/internal/version.js +1 -1
- package/package.json +1 -1
- package/src/DateTime.ts +92 -3
- package/src/Metric.ts +3 -3
- package/src/Struct.ts +3 -3
- package/src/internal/dateTime.ts +119 -12
- package/src/internal/version.ts +1 -1
package/src/internal/dateTime.ts
CHANGED
|
@@ -245,13 +245,14 @@ const maxEpochMillis = 8640000000000000 - (14 * 60 * 60 * 1000)
|
|
|
245
245
|
export const unsafeMakeZoned = (input: DateTime.DateTime.Input, options?: {
|
|
246
246
|
readonly timeZone?: number | string | DateTime.TimeZone | undefined
|
|
247
247
|
readonly adjustForTimeZone?: boolean | undefined
|
|
248
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
248
249
|
}): DateTime.Zoned => {
|
|
249
250
|
if (options?.timeZone === undefined && isDateTime(input) && isZoned(input)) {
|
|
250
251
|
return input
|
|
251
252
|
}
|
|
252
253
|
const self = unsafeMake(input)
|
|
253
254
|
if (self.epochMillis < minEpochMillis || self.epochMillis > maxEpochMillis) {
|
|
254
|
-
throw new
|
|
255
|
+
throw new RangeError(`Epoch millis out of range: ${self.epochMillis}`)
|
|
255
256
|
}
|
|
256
257
|
let zone: DateTime.TimeZone
|
|
257
258
|
if (options?.timeZone === undefined) {
|
|
@@ -271,7 +272,7 @@ export const unsafeMakeZoned = (input: DateTime.DateTime.Input, options?: {
|
|
|
271
272
|
if (options?.adjustForTimeZone !== true) {
|
|
272
273
|
return makeZonedProto(self.epochMillis, zone, self.partsUtc)
|
|
273
274
|
}
|
|
274
|
-
return makeZonedFromAdjusted(self.epochMillis, zone)
|
|
275
|
+
return makeZonedFromAdjusted(self.epochMillis, zone, options?.disambiguation ?? "compatible")
|
|
275
276
|
}
|
|
276
277
|
|
|
277
278
|
/** @internal */
|
|
@@ -280,6 +281,7 @@ export const makeZoned: (
|
|
|
280
281
|
options?: {
|
|
281
282
|
readonly timeZone?: number | string | DateTime.TimeZone | undefined
|
|
282
283
|
readonly adjustForTimeZone?: boolean | undefined
|
|
284
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
283
285
|
}
|
|
284
286
|
) => Option.Option<DateTime.Zoned> = Option.liftThrowable(unsafeMakeZoned)
|
|
285
287
|
|
|
@@ -320,27 +322,33 @@ export const toUtc = (self: DateTime.DateTime): DateTime.Utc => makeUtc(self.epo
|
|
|
320
322
|
export const setZone: {
|
|
321
323
|
(zone: DateTime.TimeZone, options?: {
|
|
322
324
|
readonly adjustForTimeZone?: boolean | undefined
|
|
325
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
323
326
|
}): (self: DateTime.DateTime) => DateTime.Zoned
|
|
324
327
|
(self: DateTime.DateTime, zone: DateTime.TimeZone, options?: {
|
|
325
328
|
readonly adjustForTimeZone?: boolean | undefined
|
|
329
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
326
330
|
}): DateTime.Zoned
|
|
327
331
|
} = dual(isDateTimeArgs, (self: DateTime.DateTime, zone: DateTime.TimeZone, options?: {
|
|
328
332
|
readonly adjustForTimeZone?: boolean | undefined
|
|
333
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
329
334
|
}): DateTime.Zoned =>
|
|
330
335
|
options?.adjustForTimeZone === true
|
|
331
|
-
? makeZonedFromAdjusted(self.epochMillis, zone)
|
|
336
|
+
? makeZonedFromAdjusted(self.epochMillis, zone, options?.disambiguation ?? "compatible")
|
|
332
337
|
: makeZonedProto(self.epochMillis, zone, self.partsUtc))
|
|
333
338
|
|
|
334
339
|
/** @internal */
|
|
335
340
|
export const setZoneOffset: {
|
|
336
341
|
(offset: number, options?: {
|
|
337
342
|
readonly adjustForTimeZone?: boolean | undefined
|
|
343
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
338
344
|
}): (self: DateTime.DateTime) => DateTime.Zoned
|
|
339
345
|
(self: DateTime.DateTime, offset: number, options?: {
|
|
340
346
|
readonly adjustForTimeZone?: boolean | undefined
|
|
347
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
341
348
|
}): DateTime.Zoned
|
|
342
349
|
} = dual(isDateTimeArgs, (self: DateTime.DateTime, offset: number, options?: {
|
|
343
350
|
readonly adjustForTimeZone?: boolean | undefined
|
|
351
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
344
352
|
}): DateTime.Zoned => setZone(self, zoneMakeOffset(offset), options))
|
|
345
353
|
|
|
346
354
|
const validZoneCache = globalValue("effect/DateTime/validZoneCache", () => new Map<string, DateTime.TimeZone.Named>())
|
|
@@ -432,14 +440,17 @@ export const zoneToString = (self: DateTime.TimeZone): string => {
|
|
|
432
440
|
export const setZoneNamed: {
|
|
433
441
|
(zoneId: string, options?: {
|
|
434
442
|
readonly adjustForTimeZone?: boolean | undefined
|
|
443
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
435
444
|
}): (self: DateTime.DateTime) => Option.Option<DateTime.Zoned>
|
|
436
445
|
(self: DateTime.DateTime, zoneId: string, options?: {
|
|
437
446
|
readonly adjustForTimeZone?: boolean | undefined
|
|
447
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
438
448
|
}): Option.Option<DateTime.Zoned>
|
|
439
449
|
} = dual(
|
|
440
450
|
isDateTimeArgs,
|
|
441
451
|
(self: DateTime.DateTime, zoneId: string, options?: {
|
|
442
452
|
readonly adjustForTimeZone?: boolean | undefined
|
|
453
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
443
454
|
}): Option.Option<DateTime.Zoned> => Option.map(zoneMakeNamed(zoneId), (zone) => setZone(self, zone, options))
|
|
444
455
|
)
|
|
445
456
|
|
|
@@ -447,12 +458,15 @@ export const setZoneNamed: {
|
|
|
447
458
|
export const unsafeSetZoneNamed: {
|
|
448
459
|
(zoneId: string, options?: {
|
|
449
460
|
readonly adjustForTimeZone?: boolean | undefined
|
|
461
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
450
462
|
}): (self: DateTime.DateTime) => DateTime.Zoned
|
|
451
463
|
(self: DateTime.DateTime, zoneId: string, options?: {
|
|
452
464
|
readonly adjustForTimeZone?: boolean | undefined
|
|
465
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
453
466
|
}): DateTime.Zoned
|
|
454
467
|
} = dual(isDateTimeArgs, (self: DateTime.DateTime, zoneId: string, options?: {
|
|
455
468
|
readonly adjustForTimeZone?: boolean | undefined
|
|
469
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
456
470
|
}): DateTime.Zoned => setZone(self, zoneUnsafeMakeNamed(zoneId), options))
|
|
457
471
|
|
|
458
472
|
// =============================================================================
|
|
@@ -715,9 +729,92 @@ export const setPartsUtc: {
|
|
|
715
729
|
// mapping
|
|
716
730
|
// =============================================================================
|
|
717
731
|
|
|
718
|
-
const
|
|
719
|
-
|
|
720
|
-
|
|
732
|
+
const constDayMillis = 24 * 60 * 60 * 1000
|
|
733
|
+
|
|
734
|
+
const makeZonedFromAdjusted = (
|
|
735
|
+
adjustedMillis: number,
|
|
736
|
+
zone: DateTime.TimeZone,
|
|
737
|
+
disambiguation: DateTime.Disambiguation
|
|
738
|
+
): DateTime.Zoned => {
|
|
739
|
+
if (zone._tag === "Offset") {
|
|
740
|
+
return makeZonedProto(adjustedMillis - zone.offset, zone)
|
|
741
|
+
}
|
|
742
|
+
const beforeOffset = calculateNamedOffset(
|
|
743
|
+
adjustedMillis - constDayMillis,
|
|
744
|
+
adjustedMillis,
|
|
745
|
+
zone
|
|
746
|
+
)
|
|
747
|
+
const afterOffset = calculateNamedOffset(
|
|
748
|
+
adjustedMillis + constDayMillis,
|
|
749
|
+
adjustedMillis,
|
|
750
|
+
zone
|
|
751
|
+
)
|
|
752
|
+
// If there is no transition, we can return early
|
|
753
|
+
if (beforeOffset === afterOffset) {
|
|
754
|
+
return makeZonedProto(adjustedMillis - beforeOffset, zone)
|
|
755
|
+
}
|
|
756
|
+
const isForwards = beforeOffset < afterOffset
|
|
757
|
+
const transitionMillis = beforeOffset - afterOffset
|
|
758
|
+
// If the transition is forwards, we only need to check if we should move the
|
|
759
|
+
// local wall clock time forward if it is inside the gap
|
|
760
|
+
if (isForwards) {
|
|
761
|
+
const currentAfterOffset = calculateNamedOffset(
|
|
762
|
+
adjustedMillis - afterOffset,
|
|
763
|
+
adjustedMillis,
|
|
764
|
+
zone
|
|
765
|
+
)
|
|
766
|
+
if (currentAfterOffset === afterOffset) {
|
|
767
|
+
return makeZonedProto(adjustedMillis - afterOffset, zone)
|
|
768
|
+
}
|
|
769
|
+
const before = makeZonedProto(adjustedMillis - beforeOffset, zone)
|
|
770
|
+
const beforeAdjustedMillis = toDate(before).getTime()
|
|
771
|
+
// If the wall clock time has changed, we are inside the gap
|
|
772
|
+
if (adjustedMillis !== beforeAdjustedMillis) {
|
|
773
|
+
switch (disambiguation) {
|
|
774
|
+
case "reject": {
|
|
775
|
+
const formatted = new Date(adjustedMillis).toISOString()
|
|
776
|
+
throw new RangeError(`Gap time: ${formatted} does not exist in time zone ${zone.id}`)
|
|
777
|
+
}
|
|
778
|
+
case "earlier":
|
|
779
|
+
return makeZonedProto(adjustedMillis - afterOffset, zone)
|
|
780
|
+
|
|
781
|
+
case "compatible":
|
|
782
|
+
case "later":
|
|
783
|
+
return before
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
// The wall clock time is in the earlier offset, so we use that
|
|
787
|
+
return before
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
const currentBeforeOffset = calculateNamedOffset(
|
|
791
|
+
adjustedMillis - beforeOffset,
|
|
792
|
+
adjustedMillis,
|
|
793
|
+
zone
|
|
794
|
+
)
|
|
795
|
+
// The wall clock time is in the earlier offset, so we use that
|
|
796
|
+
if (currentBeforeOffset === beforeOffset) {
|
|
797
|
+
if (disambiguation === "earlier" || disambiguation === "compatible") {
|
|
798
|
+
return makeZonedProto(adjustedMillis - beforeOffset, zone)
|
|
799
|
+
}
|
|
800
|
+
const laterOffset = calculateNamedOffset(
|
|
801
|
+
adjustedMillis - beforeOffset + transitionMillis,
|
|
802
|
+
adjustedMillis + transitionMillis,
|
|
803
|
+
zone
|
|
804
|
+
)
|
|
805
|
+
if (laterOffset === beforeOffset) {
|
|
806
|
+
return makeZonedProto(adjustedMillis - beforeOffset, zone)
|
|
807
|
+
}
|
|
808
|
+
// If the offset changed in this period, then we are inside the period where
|
|
809
|
+
// the wall clock time occurs twice, once in the earlier offset and once in
|
|
810
|
+
// the later offset.
|
|
811
|
+
if (disambiguation === "reject") {
|
|
812
|
+
const formatted = new Date(adjustedMillis).toISOString()
|
|
813
|
+
throw new RangeError(`Ambiguous time: ${formatted} occurs twice in time zone ${zone.id}`)
|
|
814
|
+
}
|
|
815
|
+
// If the disambiguation is "later", we return the later offset below
|
|
816
|
+
}
|
|
817
|
+
return makeZonedProto(adjustedMillis - afterOffset, zone)
|
|
721
818
|
}
|
|
722
819
|
|
|
723
820
|
const offsetRegex = /([+-])(\d{2}):(\d{2})$/
|
|
@@ -730,8 +827,12 @@ const parseOffset = (offset: string): number | null => {
|
|
|
730
827
|
return (sign === "+" ? 1 : -1) * (Number(hours) * 60 + Number(minutes)) * 60 * 1000
|
|
731
828
|
}
|
|
732
829
|
|
|
733
|
-
const calculateNamedOffset = (
|
|
734
|
-
|
|
830
|
+
const calculateNamedOffset = (
|
|
831
|
+
utcMillis: number,
|
|
832
|
+
adjustedMillis: number,
|
|
833
|
+
zone: DateTime.TimeZone.Named
|
|
834
|
+
): number => {
|
|
835
|
+
const offset = zone.format.formatToParts(utcMillis).find((_) => _.type === "timeZoneName")?.value ?? ""
|
|
735
836
|
if (offset === "GMT") {
|
|
736
837
|
return 0
|
|
737
838
|
}
|
|
@@ -745,9 +846,15 @@ const calculateNamedOffset = (adjustedMillis: number, zone: DateTime.TimeZone.Na
|
|
|
745
846
|
|
|
746
847
|
/** @internal */
|
|
747
848
|
export const mutate: {
|
|
748
|
-
(f: (date: Date) => void
|
|
749
|
-
|
|
750
|
-
}
|
|
849
|
+
(f: (date: Date) => void, options?: {
|
|
850
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
851
|
+
}): <A extends DateTime.DateTime>(self: A) => A
|
|
852
|
+
<A extends DateTime.DateTime>(self: A, f: (date: Date) => void, options?: {
|
|
853
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
854
|
+
}): A
|
|
855
|
+
} = dual(isDateTimeArgs, (self: DateTime.DateTime, f: (date: Date) => void, options?: {
|
|
856
|
+
readonly disambiguation?: DateTime.Disambiguation | undefined
|
|
857
|
+
}): DateTime.DateTime => {
|
|
751
858
|
if (self._tag === "Utc") {
|
|
752
859
|
const date = toDateUtc(self)
|
|
753
860
|
f(date)
|
|
@@ -756,7 +863,7 @@ export const mutate: {
|
|
|
756
863
|
const adjustedDate = toDate(self)
|
|
757
864
|
const newAdjustedDate = new Date(adjustedDate.getTime())
|
|
758
865
|
f(newAdjustedDate)
|
|
759
|
-
return makeZonedFromAdjusted(newAdjustedDate.getTime(), self.zone)
|
|
866
|
+
return makeZonedFromAdjusted(newAdjustedDate.getTime(), self.zone, options?.disambiguation ?? "compatible")
|
|
760
867
|
})
|
|
761
868
|
|
|
762
869
|
/** @internal */
|
package/src/internal/version.ts
CHANGED