effect 3.5.8 → 3.6.0

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.
Files changed (123) hide show
  1. package/DateTime/package.json +6 -0
  2. package/dist/cjs/Context.js.map +1 -1
  3. package/dist/cjs/DateTime.js +1514 -0
  4. package/dist/cjs/DateTime.js.map +1 -0
  5. package/dist/cjs/Effect.js +3 -3
  6. package/dist/cjs/Effect.js.map +1 -1
  7. package/dist/cjs/Either.js +3 -3
  8. package/dist/cjs/List.js.map +1 -1
  9. package/dist/cjs/Metric.js.map +1 -1
  10. package/dist/cjs/Micro.js +93 -41
  11. package/dist/cjs/Micro.js.map +1 -1
  12. package/dist/cjs/Option.js +3 -3
  13. package/dist/cjs/Predicate.js +8 -0
  14. package/dist/cjs/Predicate.js.map +1 -1
  15. package/dist/cjs/Random.js +16 -1
  16. package/dist/cjs/Random.js.map +1 -1
  17. package/dist/cjs/Stream.js +86 -7
  18. package/dist/cjs/Stream.js.map +1 -1
  19. package/dist/cjs/Struct.js +23 -1
  20. package/dist/cjs/Struct.js.map +1 -1
  21. package/dist/cjs/index.js +4 -2
  22. package/dist/cjs/index.js.map +1 -1
  23. package/dist/cjs/internal/configProvider.js.map +1 -1
  24. package/dist/cjs/internal/core.js +1 -1
  25. package/dist/cjs/internal/core.js.map +1 -1
  26. package/dist/cjs/internal/defaultServices.js +9 -2
  27. package/dist/cjs/internal/defaultServices.js.map +1 -1
  28. package/dist/cjs/internal/metric.js.map +1 -1
  29. package/dist/cjs/internal/stream/emit.js +73 -1
  30. package/dist/cjs/internal/stream/emit.js.map +1 -1
  31. package/dist/cjs/internal/stream.js +30 -22
  32. package/dist/cjs/internal/stream.js.map +1 -1
  33. package/dist/cjs/internal/version.js +1 -1
  34. package/dist/dts/ConfigProvider.d.ts +2 -2
  35. package/dist/dts/ConfigProvider.d.ts.map +1 -1
  36. package/dist/dts/Context.d.ts +3 -1
  37. package/dist/dts/Context.d.ts.map +1 -1
  38. package/dist/dts/DateTime.d.ts +1265 -0
  39. package/dist/dts/DateTime.d.ts.map +1 -0
  40. package/dist/dts/Effect.d.ts +18 -4
  41. package/dist/dts/Effect.d.ts.map +1 -1
  42. package/dist/dts/Either.d.ts +4 -4
  43. package/dist/dts/List.d.ts +2 -1
  44. package/dist/dts/List.d.ts.map +1 -1
  45. package/dist/dts/Metric.d.ts +1 -1
  46. package/dist/dts/Metric.d.ts.map +1 -1
  47. package/dist/dts/MetricRegistry.d.ts +1 -1
  48. package/dist/dts/MetricRegistry.d.ts.map +1 -1
  49. package/dist/dts/Micro.d.ts +60 -0
  50. package/dist/dts/Micro.d.ts.map +1 -1
  51. package/dist/dts/Option.d.ts +4 -4
  52. package/dist/dts/Predicate.d.ts +63 -2
  53. package/dist/dts/Predicate.d.ts.map +1 -1
  54. package/dist/dts/Random.d.ts +18 -0
  55. package/dist/dts/Random.d.ts.map +1 -1
  56. package/dist/dts/Stream.d.ts +95 -4
  57. package/dist/dts/Stream.d.ts.map +1 -1
  58. package/dist/dts/StreamEmit.d.ts +44 -0
  59. package/dist/dts/StreamEmit.d.ts.map +1 -1
  60. package/dist/dts/Struct.d.ts +21 -0
  61. package/dist/dts/Struct.d.ts.map +1 -1
  62. package/dist/dts/index.d.ts +4 -0
  63. package/dist/dts/index.d.ts.map +1 -1
  64. package/dist/dts/internal/core.d.ts.map +1 -1
  65. package/dist/dts/internal/defaultServices.d.ts.map +1 -1
  66. package/dist/dts/internal/stream.d.ts.map +1 -1
  67. package/dist/esm/Context.js.map +1 -1
  68. package/dist/esm/DateTime.js +1465 -0
  69. package/dist/esm/DateTime.js.map +1 -0
  70. package/dist/esm/Effect.js +4 -4
  71. package/dist/esm/Effect.js.map +1 -1
  72. package/dist/esm/Either.js +4 -4
  73. package/dist/esm/List.js.map +1 -1
  74. package/dist/esm/Metric.js.map +1 -1
  75. package/dist/esm/Micro.js +88 -38
  76. package/dist/esm/Micro.js.map +1 -1
  77. package/dist/esm/Option.js +4 -4
  78. package/dist/esm/Predicate.js +8 -0
  79. package/dist/esm/Predicate.js.map +1 -1
  80. package/dist/esm/Random.js +15 -0
  81. package/dist/esm/Random.js.map +1 -1
  82. package/dist/esm/Stream.js +84 -5
  83. package/dist/esm/Stream.js.map +1 -1
  84. package/dist/esm/Struct.js +21 -0
  85. package/dist/esm/Struct.js.map +1 -1
  86. package/dist/esm/index.js +4 -0
  87. package/dist/esm/index.js.map +1 -1
  88. package/dist/esm/internal/configProvider.js.map +1 -1
  89. package/dist/esm/internal/core.js +1 -1
  90. package/dist/esm/internal/core.js.map +1 -1
  91. package/dist/esm/internal/defaultServices.js +6 -0
  92. package/dist/esm/internal/defaultServices.js.map +1 -1
  93. package/dist/esm/internal/metric.js.map +1 -1
  94. package/dist/esm/internal/stream/emit.js +71 -0
  95. package/dist/esm/internal/stream/emit.js.map +1 -1
  96. package/dist/esm/internal/stream.js +24 -18
  97. package/dist/esm/internal/stream.js.map +1 -1
  98. package/dist/esm/internal/version.js +1 -1
  99. package/package.json +9 -1
  100. package/src/ConfigProvider.ts +2 -2
  101. package/src/Context.ts +3 -1
  102. package/src/DateTime.ts +2104 -0
  103. package/src/Effect.ts +28 -4
  104. package/src/Either.ts +4 -4
  105. package/src/List.ts +3 -2
  106. package/src/Metric.ts +1 -1
  107. package/src/MetricRegistry.ts +1 -1
  108. package/src/Micro.ts +117 -45
  109. package/src/Option.ts +4 -4
  110. package/src/Predicate.ts +68 -8
  111. package/src/Random.ts +24 -0
  112. package/src/Stream.ts +110 -5
  113. package/src/StreamEmit.ts +53 -0
  114. package/src/Struct.ts +22 -0
  115. package/src/index.ts +5 -0
  116. package/src/internal/configProvider.ts +20 -20
  117. package/src/internal/core.ts +37 -12
  118. package/src/internal/defaultServices.ts +14 -0
  119. package/src/internal/metric/registry.ts +1 -1
  120. package/src/internal/metric.ts +2 -2
  121. package/src/internal/stream/emit.ts +77 -0
  122. package/src/internal/stream.ts +86 -18
  123. package/src/internal/version.ts +1 -1
@@ -0,0 +1,1465 @@
1
+ /**
2
+ * @since 3.6.0
3
+ */
4
+ import { IllegalArgumentException } from "./Cause.js";
5
+ import * as Clock from "./Clock.js";
6
+ import * as Context from "./Context.js";
7
+ import * as Duration from "./Duration.js";
8
+ import * as Effect from "./Effect.js";
9
+ import * as Either from "./Either.js";
10
+ import * as Equal from "./Equal.js";
11
+ import * as Equivalence_ from "./Equivalence.js";
12
+ import { dual, pipe } from "./Function.js";
13
+ import { globalValue } from "./GlobalValue.js";
14
+ import * as Hash from "./Hash.js";
15
+ import * as Inspectable from "./Inspectable.js";
16
+ import * as Layer from "./Layer.js";
17
+ import * as Option from "./Option.js";
18
+ import * as order from "./Order.js";
19
+ import { pipeArguments } from "./Pipeable.js";
20
+ import * as Predicate from "./Predicate.js";
21
+ /**
22
+ * @since 3.6.0
23
+ * @category type ids
24
+ */
25
+ export const TypeId = /*#__PURE__*/Symbol.for("effect/DateTime");
26
+ /**
27
+ * @since 3.6.0
28
+ * @category type ids
29
+ */
30
+ export const TimeZoneTypeId = /*#__PURE__*/Symbol.for("effect/DateTime/TimeZone");
31
+ const Proto = {
32
+ [TypeId]: TypeId,
33
+ pipe() {
34
+ return pipeArguments(this, arguments);
35
+ },
36
+ [Inspectable.NodeInspectSymbol]() {
37
+ return this.toString();
38
+ },
39
+ toJSON() {
40
+ return toDateUtc(this).toJSON();
41
+ }
42
+ };
43
+ const ProtoUtc = {
44
+ ...Proto,
45
+ _tag: "Utc",
46
+ [Hash.symbol]() {
47
+ return Hash.cached(this, Hash.number(this.epochMillis));
48
+ },
49
+ [Equal.symbol](that) {
50
+ return isDateTime(that) && that._tag === "Utc" && this.epochMillis === that.epochMillis;
51
+ },
52
+ toString() {
53
+ return `DateTime.Utc(${toDateUtc(this).toJSON()})`;
54
+ }
55
+ };
56
+ const ProtoZoned = {
57
+ ...Proto,
58
+ _tag: "Zoned",
59
+ [Hash.symbol]() {
60
+ return pipe(Hash.number(this.epochMillis), Hash.combine(Hash.hash(this.zone)), Hash.cached(this));
61
+ },
62
+ [Equal.symbol](that) {
63
+ return isDateTime(that) && that._tag === "Zoned" && this.epochMillis === that.epochMillis && Equal.equals(this.zone, that.zone);
64
+ },
65
+ toString() {
66
+ return `DateTime.Zoned(${formatIsoZoned(this)})`;
67
+ }
68
+ };
69
+ const ProtoTimeZone = {
70
+ [TimeZoneTypeId]: TimeZoneTypeId,
71
+ [Inspectable.NodeInspectSymbol]() {
72
+ return this.toString();
73
+ }
74
+ };
75
+ const ProtoTimeZoneNamed = {
76
+ ...ProtoTimeZone,
77
+ _tag: "Named",
78
+ [Hash.symbol]() {
79
+ return Hash.cached(this, Hash.string(`Named:${this.id}`));
80
+ },
81
+ [Equal.symbol](that) {
82
+ return isTimeZone(that) && that._tag === "Named" && this.id === that.id;
83
+ },
84
+ toString() {
85
+ return `TimeZone.Named(${this.id})`;
86
+ },
87
+ toJSON() {
88
+ return {
89
+ _id: "TimeZone",
90
+ _tag: "Named",
91
+ id: this.id
92
+ };
93
+ }
94
+ };
95
+ const ProtoTimeZoneOffset = {
96
+ ...ProtoTimeZone,
97
+ _tag: "Offset",
98
+ [Hash.symbol]() {
99
+ return Hash.cached(this, Hash.string(`Offset:${this.offset}`));
100
+ },
101
+ [Equal.symbol](that) {
102
+ return isTimeZone(that) && that._tag === "Offset" && this.offset === that.offset;
103
+ },
104
+ toString() {
105
+ return `TimeZone.Offset(${offsetToString(this.offset)})`;
106
+ },
107
+ toJSON() {
108
+ return {
109
+ _id: "TimeZone",
110
+ _tag: "Offset",
111
+ offset: this.offset
112
+ };
113
+ }
114
+ };
115
+ const makeZonedProto = (epochMillis, zone, partsUtc) => {
116
+ const self = Object.create(ProtoZoned);
117
+ self.epochMillis = epochMillis;
118
+ self.zone = zone;
119
+ self.partsUtc = partsUtc;
120
+ return self;
121
+ };
122
+ // =============================================================================
123
+ // guards
124
+ // =============================================================================
125
+ /**
126
+ * @since 3.6.0
127
+ * @category guards
128
+ */
129
+ export const isDateTime = u => Predicate.hasProperty(u, TypeId);
130
+ const isDateTimeArgs = args => isDateTime(args[0]);
131
+ /**
132
+ * @since 3.6.0
133
+ * @category guards
134
+ */
135
+ export const isTimeZone = u => Predicate.hasProperty(u, TimeZoneTypeId);
136
+ /**
137
+ * @since 3.6.0
138
+ * @category guards
139
+ */
140
+ export const isTimeZoneOffset = u => isTimeZone(u) && u._tag === "Offset";
141
+ /**
142
+ * @since 3.6.0
143
+ * @category guards
144
+ */
145
+ export const isTimeZoneNamed = u => isTimeZone(u) && u._tag === "Named";
146
+ /**
147
+ * @since 3.6.0
148
+ * @category guards
149
+ */
150
+ export const isUtc = self => self._tag === "Utc";
151
+ /**
152
+ * @since 3.6.0
153
+ * @category guards
154
+ */
155
+ export const isZoned = self => self._tag === "Zoned";
156
+ // =============================================================================
157
+ // instances
158
+ // =============================================================================
159
+ /**
160
+ * @since 3.6.0
161
+ * @category instances
162
+ */
163
+ export const Equivalence = /*#__PURE__*/Equivalence_.make((a, b) => a.epochMillis === b.epochMillis);
164
+ /**
165
+ * @since 3.6.0
166
+ * @category instances
167
+ */
168
+ export const Order = /*#__PURE__*/order.make((self, that) => self.epochMillis < that.epochMillis ? -1 : self.epochMillis > that.epochMillis ? 1 : 0);
169
+ /**
170
+ * @since 3.6.0
171
+ */
172
+ export const clamp = /*#__PURE__*/order.clamp(Order);
173
+ // =============================================================================
174
+ // constructors
175
+ // =============================================================================
176
+ const makeUtc = epochMillis => {
177
+ const self = Object.create(ProtoUtc);
178
+ self.epochMillis = epochMillis;
179
+ return self;
180
+ };
181
+ /**
182
+ * Create a `DateTime` from a `Date`.
183
+ *
184
+ * If the `Date` is invalid, an `IllegalArgumentException` will be thrown.
185
+ *
186
+ * @since 3.6.0
187
+ * @category constructors
188
+ */
189
+ export const unsafeFromDate = date => {
190
+ const epochMillis = date.getTime();
191
+ if (Number.isNaN(epochMillis)) {
192
+ throw new IllegalArgumentException("Invalid date");
193
+ }
194
+ return makeUtc(epochMillis);
195
+ };
196
+ /**
197
+ * Create a `DateTime` from one of the following:
198
+ *
199
+ * - A `DateTime`
200
+ * - A `Date` instance (invalid dates will throw an `IllegalArgumentException`)
201
+ * - The `number` of milliseconds since the Unix epoch
202
+ * - An object with the parts of a date
203
+ * - A `string` that can be parsed by `Date.parse`
204
+ *
205
+ * @since 3.6.0
206
+ * @category constructors
207
+ * @example
208
+ * import { DateTime } from "effect"
209
+ *
210
+ * // from Date
211
+ * DateTime.unsafeMake(new Date())
212
+ *
213
+ * // from parts
214
+ * DateTime.unsafeMake({ year: 2024 })
215
+ *
216
+ * // from string
217
+ * DateTime.unsafeMake("2024-01-01")
218
+ */
219
+ export const unsafeMake = input => {
220
+ if (isDateTime(input)) {
221
+ return input;
222
+ } else if (input instanceof Date) {
223
+ return unsafeFromDate(input);
224
+ } else if (typeof input === "object") {
225
+ const date = new Date(0);
226
+ setPartsDate(date, input);
227
+ return unsafeFromDate(date);
228
+ }
229
+ return unsafeFromDate(new Date(input));
230
+ };
231
+ /**
232
+ * Create a `DateTime.Zoned` using `DateTime.unsafeMake` and a time zone.
233
+ *
234
+ * The input is treated as UTC and then the time zone is attached, unless
235
+ * `adjustForTimeZone` is set to `true`. In that case, the input is treated as
236
+ * already in the time zone.
237
+ *
238
+ * @since 3.6.0
239
+ * @category constructors
240
+ * @example
241
+ * import { DateTime } from "effect"
242
+ *
243
+ * DateTime.unsafeMakeZoned(new Date(), { timeZone: "Europe/London" })
244
+ */
245
+ export const unsafeMakeZoned = (input, options) => {
246
+ const self = unsafeMake(input);
247
+ let zone;
248
+ if (isTimeZone(options.timeZone)) {
249
+ zone = options.timeZone;
250
+ } else if (typeof options.timeZone === "number") {
251
+ zone = zoneMakeOffset(options.timeZone);
252
+ } else {
253
+ const parsedZone = zoneFromString(options.timeZone);
254
+ if (Option.isNone(parsedZone)) {
255
+ throw new IllegalArgumentException(`Invalid time zone: ${options.timeZone}`);
256
+ }
257
+ zone = parsedZone.value;
258
+ }
259
+ if (options.adjustForTimeZone !== true) {
260
+ return makeZonedProto(self.epochMillis, zone, self.partsUtc);
261
+ }
262
+ return makeZonedFromAdjusted(self.epochMillis, zone);
263
+ };
264
+ /**
265
+ * Create a `DateTime.Zoned` using `DateTime.make` and a time zone.
266
+ *
267
+ * The input is treated as UTC and then the time zone is attached.
268
+ *
269
+ * If the date time input or time zone is invalid, `None` will be returned.
270
+ *
271
+ * @since 3.6.0
272
+ * @category constructors
273
+ * @example
274
+ * import { DateTime } from "effect"
275
+ *
276
+ * DateTime.makeZoned(new Date(), { timeZone: "Europe/London" })
277
+ */
278
+ export const makeZoned = /*#__PURE__*/Option.liftThrowable(unsafeMakeZoned);
279
+ /**
280
+ * Create a `DateTime` from one of the following:
281
+ *
282
+ * - A `DateTime`
283
+ * - A `Date` instance (invalid dates will throw an `IllegalArgumentException`)
284
+ * - The `number` of milliseconds since the Unix epoch
285
+ * - An object with the parts of a date
286
+ * - A `string` that can be parsed by `Date.parse`
287
+ *
288
+ * If the input is invalid, `None` will be returned.
289
+ *
290
+ * @since 3.6.0
291
+ * @category constructors
292
+ * @example
293
+ * import { DateTime } from "effect"
294
+ *
295
+ * // from Date
296
+ * DateTime.make(new Date())
297
+ *
298
+ * // from parts
299
+ * DateTime.make({ year: 2024 })
300
+ *
301
+ * // from string
302
+ * DateTime.make("2024-01-01")
303
+ */
304
+ export const make = /*#__PURE__*/Option.liftThrowable(unsafeMake);
305
+ const zonedStringRegex = /^(.{17,35})\[(.+)\]$/;
306
+ /**
307
+ * Create a `DateTime.Zoned` from a string.
308
+ *
309
+ * It uses the format: `YYYY-MM-DDTHH:mm:ss.sss+HH:MM[Time/Zone]`.
310
+ *
311
+ * @since 3.6.0
312
+ * @category constructors
313
+ */
314
+ export const makeZonedFromString = input => {
315
+ const match = zonedStringRegex.exec(input);
316
+ if (match === null) {
317
+ const offset = parseOffset(input);
318
+ return offset ? makeZoned(input, {
319
+ timeZone: offset
320
+ }) : Option.none();
321
+ }
322
+ const [, isoString, timeZone] = match;
323
+ return makeZoned(isoString, {
324
+ timeZone
325
+ });
326
+ };
327
+ /**
328
+ * Get the current time using the `Clock` service and convert it to a `DateTime`.
329
+ *
330
+ * @since 3.6.0
331
+ * @category constructors
332
+ * @example
333
+ * import { DateTime, Effect } from "effect"
334
+ *
335
+ * Effect.gen(function* () {
336
+ * const now = yield* DateTime.now
337
+ * })
338
+ */
339
+ export const now = /*#__PURE__*/Effect.map(Clock.currentTimeMillis, makeUtc);
340
+ /**
341
+ * Get the current time using `Date.now`.
342
+ *
343
+ * @since 3.6.0
344
+ * @category constructors
345
+ */
346
+ export const unsafeNow = () => makeUtc(Date.now());
347
+ // =============================================================================
348
+ // time zones
349
+ // =============================================================================
350
+ /**
351
+ * Set the time zone of a `DateTime`, returning a new `DateTime.Zoned`.
352
+ *
353
+ * @since 3.6.0
354
+ * @category time zones
355
+ * @example
356
+ * import { DateTime, Effect } from "effect"
357
+ *
358
+ * Effect.gen(function* () {
359
+ * const now = yield* DateTime.now
360
+ * const zone = DateTime.zoneUnsafeMakeNamed("Europe/London")
361
+ *
362
+ * // set the time zone
363
+ * const zoned: DateTime.Zoned = DateTime.setZone(now, zone)
364
+ * })
365
+ */
366
+ export const setZone = /*#__PURE__*/dual(isDateTimeArgs, (self, zone, options) => options?.adjustForTimeZone === true ? makeZonedFromAdjusted(self.epochMillis, zone) : makeZonedProto(self.epochMillis, zone, self.partsUtc));
367
+ /**
368
+ * Add a fixed offset time zone to a `DateTime`.
369
+ *
370
+ * The offset is in milliseconds.
371
+ *
372
+ * @since 3.6.0
373
+ * @category time zones
374
+ * @example
375
+ * import { DateTime, Effect } from "effect"
376
+ *
377
+ * Effect.gen(function* () {
378
+ * const now = yield* DateTime.now
379
+ *
380
+ * // set the offset time zone in milliseconds
381
+ * const zoned: DateTime.Zoned = DateTime.setZoneOffset(now, 3 * 60 * 60 * 1000)
382
+ * })
383
+ */
384
+ export const setZoneOffset = /*#__PURE__*/dual(isDateTimeArgs, (self, offset, options) => setZone(self, zoneMakeOffset(offset), options));
385
+ const validZoneCache = /*#__PURE__*/globalValue("effect/DateTime/validZoneCache", () => new Map());
386
+ const formatOptions = {
387
+ day: "numeric",
388
+ month: "numeric",
389
+ year: "numeric",
390
+ hour: "numeric",
391
+ minute: "numeric",
392
+ second: "numeric",
393
+ timeZoneName: "longOffset",
394
+ fractionalSecondDigits: 3,
395
+ hourCycle: "h23"
396
+ };
397
+ const zoneMakeIntl = format => {
398
+ const zoneId = format.resolvedOptions().timeZone;
399
+ if (validZoneCache.has(zoneId)) {
400
+ return validZoneCache.get(zoneId);
401
+ }
402
+ const zone = Object.create(ProtoTimeZoneNamed);
403
+ zone.id = zoneId;
404
+ zone.format = format;
405
+ validZoneCache.set(zoneId, zone);
406
+ return zone;
407
+ };
408
+ /**
409
+ * Attempt to create a named time zone from a IANA time zone identifier.
410
+ *
411
+ * If the time zone is invalid, an `IllegalArgumentException` will be thrown.
412
+ *
413
+ * @since 3.6.0
414
+ * @category time zones
415
+ */
416
+ export const zoneUnsafeMakeNamed = zoneId => {
417
+ if (validZoneCache.has(zoneId)) {
418
+ return validZoneCache.get(zoneId);
419
+ }
420
+ try {
421
+ return zoneMakeIntl(new Intl.DateTimeFormat("en-US", {
422
+ ...formatOptions,
423
+ timeZone: zoneId
424
+ }));
425
+ } catch (_) {
426
+ throw new IllegalArgumentException(`Invalid time zone: ${zoneId}`);
427
+ }
428
+ };
429
+ /**
430
+ * Create a fixed offset time zone.
431
+ *
432
+ * @since 3.6.0
433
+ * @category time zones
434
+ */
435
+ export const zoneMakeOffset = offset => {
436
+ const zone = Object.create(ProtoTimeZoneOffset);
437
+ zone.offset = offset;
438
+ return zone;
439
+ };
440
+ /**
441
+ * Create a named time zone from a IANA time zone identifier. If the time zone
442
+ * is invalid, `None` will be returned.
443
+ *
444
+ * @since 3.6.0
445
+ * @category time zones
446
+ */
447
+ export const zoneMakeNamed = /*#__PURE__*/Option.liftThrowable(zoneUnsafeMakeNamed);
448
+ /**
449
+ * Create a named time zone from a IANA time zone identifier. If the time zone
450
+ * is invalid, it will fail with an `IllegalArgumentException`.
451
+ *
452
+ * @since 3.6.0
453
+ * @category time zones
454
+ */
455
+ export const zoneMakeNamedEffect = zoneId => Effect.try({
456
+ try: () => zoneUnsafeMakeNamed(zoneId),
457
+ catch: e => e
458
+ });
459
+ /**
460
+ * Create a named time zone from the system's local time zone.
461
+ *
462
+ * @since 3.6.0
463
+ * @category time zones
464
+ */
465
+ export const zoneMakeLocal = () => zoneMakeIntl(new Intl.DateTimeFormat("en-US", formatOptions));
466
+ const offsetZoneRegex = /^(?:GMT|[+-])/;
467
+ /**
468
+ * Try parse a TimeZone from a string
469
+ *
470
+ * @since 3.6.0
471
+ * @category time zones
472
+ */
473
+ export const zoneFromString = zone => {
474
+ if (offsetZoneRegex.test(zone)) {
475
+ const offset = parseOffset(zone);
476
+ return offset === null ? Option.none() : Option.some(zoneMakeOffset(offset));
477
+ }
478
+ return zoneMakeNamed(zone);
479
+ };
480
+ /**
481
+ * Format a `TimeZone` as a string.
482
+ *
483
+ * @since 3.6.0
484
+ * @category time zones
485
+ * @example
486
+ * import { DateTime, Effect } from "effect"
487
+ *
488
+ * // Outputs "+03:00"
489
+ * DateTime.zoneToString(DateTime.zoneMakeOffset(3 * 60 * 60 * 1000))
490
+ *
491
+ * // Outputs "Europe/London"
492
+ * DateTime.zoneToString(DateTime.zoneUnsafeMakeNamed("Europe/London"))
493
+ */
494
+ export const zoneToString = self => {
495
+ if (self._tag === "Offset") {
496
+ return offsetToString(self.offset);
497
+ }
498
+ return self.id;
499
+ };
500
+ /**
501
+ * Set the time zone of a `DateTime` from an IANA time zone identifier. If the
502
+ * time zone is invalid, `None` will be returned.
503
+ *
504
+ * @since 3.6.0
505
+ * @category time zones
506
+ * @example
507
+ * import { DateTime, Effect } from "effect"
508
+ *
509
+ * Effect.gen(function* () {
510
+ * const now = yield* DateTime.now
511
+ * // set the time zone, returns an Option
512
+ * DateTime.setZoneNamed(now, "Europe/London")
513
+ * })
514
+ */
515
+ export const setZoneNamed = /*#__PURE__*/dual(isDateTimeArgs, (self, zoneId, options) => Option.map(zoneMakeNamed(zoneId), zone => setZone(self, zone, options)));
516
+ /**
517
+ * Set the time zone of a `DateTime` from an IANA time zone identifier. If the
518
+ * time zone is invalid, an `IllegalArgumentException` will be thrown.
519
+ *
520
+ * @since 3.6.0
521
+ * @category time zones
522
+ * @example
523
+ * import { DateTime, Effect } from "effect"
524
+ *
525
+ * Effect.gen(function* () {
526
+ * const now = yield* DateTime.now
527
+ * // set the time zone
528
+ * DateTime.unsafeSetZoneNamed(now, "Europe/London")
529
+ * })
530
+ */
531
+ export const unsafeSetZoneNamed = /*#__PURE__*/dual(isDateTimeArgs, (self, zoneId, options) => setZone(self, zoneUnsafeMakeNamed(zoneId), options));
532
+ // =============================================================================
533
+ // comparisons
534
+ // =============================================================================
535
+ /**
536
+ * Calulate the difference between two `DateTime` values, returning the number
537
+ * of milliseconds the `other` DateTime is from `self`.
538
+ *
539
+ * If `other` is *after* `self`, the result will be a positive number.
540
+ *
541
+ * @since 3.6.0
542
+ * @category comparisons
543
+ * @example
544
+ * import { DateTime, Effect } from "effect"
545
+ *
546
+ * Effect.gen(function* () {
547
+ * const now = yield* DateTime.now
548
+ * const other = DateTime.add(now, { minutes: 1 })
549
+ *
550
+ * // returns 60000
551
+ * DateTime.distance(now, other)
552
+ * })
553
+ */
554
+ export const distance = /*#__PURE__*/dual(2, (self, other) => toEpochMillis(other) - toEpochMillis(self));
555
+ /**
556
+ * Calulate the difference between two `DateTime` values.
557
+ *
558
+ * If the `other` DateTime is before `self`, the result will be a negative
559
+ * `Duration`, returned as a `Left`.
560
+ *
561
+ * If the `other` DateTime is after `self`, the result will be a positive
562
+ * `Duration`, returned as a `Right`.
563
+ *
564
+ * @since 3.6.0
565
+ * @category comparisons
566
+ * @example
567
+ * import { DateTime, Effect } from "effect"
568
+ *
569
+ * Effect.gen(function* () {
570
+ * const now = yield* DateTime.now
571
+ * const other = DateTime.add(now, { minutes: 1 })
572
+ *
573
+ * // returns Either.right(Duration.minutes(1))
574
+ * DateTime.distanceDurationEither(now, other)
575
+ *
576
+ * // returns Either.left(Duration.minutes(1))
577
+ * DateTime.distanceDurationEither(other, now)
578
+ * })
579
+ */
580
+ export const distanceDurationEither = /*#__PURE__*/dual(2, (self, other) => {
581
+ const diffMillis = distance(self, other);
582
+ return diffMillis > 0 ? Either.right(Duration.millis(diffMillis)) : Either.left(Duration.millis(-diffMillis));
583
+ });
584
+ /**
585
+ * Calulate the distance between two `DateTime` values.
586
+ *
587
+ * @since 3.6.0
588
+ * @category comparisons
589
+ * @example
590
+ * import { DateTime, Effect } from "effect"
591
+ *
592
+ * Effect.gen(function* () {
593
+ * const now = yield* DateTime.now
594
+ * const other = DateTime.add(now, { minutes: 1 })
595
+ *
596
+ * // returns Duration.minutes(1)
597
+ * DateTime.distanceDuration(now, other)
598
+ * })
599
+ */
600
+ export const distanceDuration = /*#__PURE__*/dual(2, (self, other) => Duration.millis(Math.abs(distance(self, other))));
601
+ /**
602
+ * @since 3.6.0
603
+ * @category comparisons
604
+ */
605
+ export const min = /*#__PURE__*/order.min(Order);
606
+ /**
607
+ * @since 3.6.0
608
+ * @category comparisons
609
+ */
610
+ export const max = /*#__PURE__*/order.max(Order);
611
+ /**
612
+ * @since 3.6.0
613
+ * @category comparisons
614
+ */
615
+ export const greaterThan = /*#__PURE__*/order.greaterThan(Order);
616
+ /**
617
+ * @since 3.6.0
618
+ * @category comparisons
619
+ */
620
+ export const greaterThanOrEqualTo = /*#__PURE__*/order.greaterThanOrEqualTo(Order);
621
+ /**
622
+ * @since 3.6.0
623
+ * @category comparisons
624
+ */
625
+ export const lessThan = /*#__PURE__*/order.lessThan(Order);
626
+ /**
627
+ * @since 3.6.0
628
+ * @category comparisons
629
+ */
630
+ export const lessThanOrEqualTo = /*#__PURE__*/order.lessThanOrEqualTo(Order);
631
+ /**
632
+ * @since 3.6.0
633
+ * @category comparisons
634
+ */
635
+ export const between = /*#__PURE__*/order.between(Order);
636
+ /**
637
+ * @since 3.6.0
638
+ * @category comparisons
639
+ */
640
+ export const isFuture = self => Effect.map(now, lessThan(self));
641
+ /**
642
+ * @since 3.6.0
643
+ * @category comparisons
644
+ */
645
+ export const unsafeIsFuture = self => lessThan(unsafeNow(), self);
646
+ /**
647
+ * @since 3.6.0
648
+ * @category comparisons
649
+ */
650
+ export const isPast = self => Effect.map(now, greaterThan(self));
651
+ /**
652
+ * @since 3.6.0
653
+ * @category comparisons
654
+ */
655
+ export const unsafeIsPast = self => greaterThan(unsafeNow(), self);
656
+ // =============================================================================
657
+ // conversions
658
+ // =============================================================================
659
+ /**
660
+ * Get the UTC `Date` of a `DateTime`.
661
+ *
662
+ * @since 3.6.0
663
+ * @category conversions
664
+ */
665
+ export const toDateUtc = self => new Date(self.epochMillis);
666
+ /**
667
+ * Convert a `DateTime` to a `Date`, applying the time zone first.
668
+ *
669
+ * @since 3.6.0
670
+ * @category conversions
671
+ */
672
+ export const toDate = self => {
673
+ if (self._tag === "Utc") {
674
+ return new Date(self.epochMillis);
675
+ } else if (self.zone._tag === "Offset") {
676
+ return new Date(self.epochMillis + self.zone.offset);
677
+ } else if (self.adjustedEpochMillis !== undefined) {
678
+ return new Date(self.adjustedEpochMillis);
679
+ }
680
+ const parts = self.zone.format.formatToParts(self.epochMillis).filter(_ => _.type !== "literal");
681
+ const date = new Date(0);
682
+ date.setUTCFullYear(Number(parts[2].value), Number(parts[0].value) - 1, Number(parts[1].value));
683
+ date.setUTCHours(Number(parts[3].value), Number(parts[4].value), Number(parts[5].value), Number(parts[6].value));
684
+ self.adjustedEpochMillis = date.getTime();
685
+ return date;
686
+ };
687
+ /**
688
+ * Calculate the time zone offset of a `DateTime.Zoned` in milliseconds.
689
+ *
690
+ * @since 3.6.0
691
+ * @category conversions
692
+ */
693
+ export const zonedOffset = self => {
694
+ const date = toDate(self);
695
+ return date.getTime() - toEpochMillis(self);
696
+ };
697
+ const offsetToString = offset => {
698
+ const abs = Math.abs(offset);
699
+ const hours = Math.floor(abs / (60 * 60 * 1000));
700
+ const minutes = Math.round(abs % (60 * 60 * 1000) / (60 * 1000));
701
+ return `${offset < 0 ? "-" : "+"}${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
702
+ };
703
+ /**
704
+ * Calculate the time zone offset of a `DateTime` in milliseconds.
705
+ *
706
+ * The offset is formatted as "±HH:MM".
707
+ *
708
+ * @since 3.6.0
709
+ * @category conversions
710
+ */
711
+ export const zonedOffsetIso = self => offsetToString(zonedOffset(self));
712
+ /**
713
+ * Get the milliseconds since the Unix epoch of a `DateTime`.
714
+ *
715
+ * @since 3.6.0
716
+ * @category conversions
717
+ */
718
+ export const toEpochMillis = self => self.epochMillis;
719
+ /**
720
+ * Remove the time aspect of a `DateTime`, first adjusting for the time
721
+ * zone. It will return a `DateTime.Utc` only containing the date.
722
+ *
723
+ * @since 3.6.0
724
+ * @category conversions
725
+ * @example
726
+ * import { DateTime } from "effect"
727
+ *
728
+ * // returns "2024-01-01T00:00:00Z"
729
+ * DateTime.unsafeMakeZoned("2024-01-01T05:00:00Z", {
730
+ * timeZone: "Pacific/Auckland",
731
+ * adjustForTimeZone: true
732
+ * }).pipe(
733
+ * DateTime.removeTime,
734
+ * DateTime.formatIso
735
+ * )
736
+ */
737
+ export const removeTime = self => withDate(self, date => {
738
+ date.setUTCHours(0, 0, 0, 0);
739
+ return makeUtc(date.getTime());
740
+ });
741
+ // =============================================================================
742
+ // parts
743
+ // =============================================================================
744
+ const dateToParts = date => ({
745
+ millis: date.getUTCMilliseconds(),
746
+ seconds: date.getUTCSeconds(),
747
+ minutes: date.getUTCMinutes(),
748
+ hours: date.getUTCHours(),
749
+ day: date.getUTCDate(),
750
+ weekDay: date.getUTCDay(),
751
+ month: date.getUTCMonth() + 1,
752
+ year: date.getUTCFullYear()
753
+ });
754
+ /**
755
+ * Get the different parts of a `DateTime` as an object.
756
+ *
757
+ * The parts will be time zone adjusted.
758
+ *
759
+ * @since 3.6.0
760
+ * @category parts
761
+ */
762
+ export const toParts = self => {
763
+ if (self._tag === "Utc") {
764
+ return toPartsUtc(self);
765
+ } else if (self.partsAdjusted !== undefined) {
766
+ return self.partsAdjusted;
767
+ }
768
+ self.partsAdjusted = withDate(self, dateToParts);
769
+ return self.partsAdjusted;
770
+ };
771
+ /**
772
+ * Get the different parts of a `DateTime` as an object.
773
+ *
774
+ * The parts will be in UTC.
775
+ *
776
+ * @since 3.6.0
777
+ * @category parts
778
+ */
779
+ export const toPartsUtc = self => {
780
+ if (self.partsUtc !== undefined) {
781
+ return self.partsUtc;
782
+ }
783
+ self.partsUtc = withDateUtc(self, dateToParts);
784
+ return self.partsUtc;
785
+ };
786
+ /**
787
+ * Get a part of a `DateTime` as a number.
788
+ *
789
+ * The part will be in the UTC time zone.
790
+ *
791
+ * @since 3.6.0
792
+ * @category parts
793
+ * @example
794
+ * import { DateTime } from "effect"
795
+ *
796
+ * const now = DateTime.unsafeMake({ year: 2024 })
797
+ * const year = DateTime.getPartUtc(now, "year")
798
+ * assert.strictEqual(year, 2024)
799
+ */
800
+ export const getPartUtc = /*#__PURE__*/dual(2, (self, part) => toPartsUtc(self)[part]);
801
+ /**
802
+ * Get a part of a `DateTime` as a number.
803
+ *
804
+ * The part will be time zone adjusted.
805
+ *
806
+ * @since 3.6.0
807
+ * @category parts
808
+ * @example
809
+ * import { DateTime } from "effect"
810
+ *
811
+ * const now = DateTime.unsafeMakeZoned({ year: 2024 }, { timeZone: "Europe/London" })
812
+ * const year = DateTime.getPart(now, "year")
813
+ * assert.strictEqual(year, 2024)
814
+ */
815
+ export const getPart = /*#__PURE__*/dual(2, (self, part) => toParts(self)[part]);
816
+ const setPartsDate = (date, parts) => {
817
+ if (parts.year !== undefined) {
818
+ date.setUTCFullYear(parts.year);
819
+ }
820
+ if (parts.month !== undefined) {
821
+ date.setUTCMonth(parts.month - 1);
822
+ }
823
+ if (parts.day !== undefined) {
824
+ date.setUTCDate(parts.day);
825
+ }
826
+ if (parts.weekDay !== undefined) {
827
+ const diff = parts.weekDay - date.getUTCDay();
828
+ date.setUTCDate(date.getUTCDate() + diff);
829
+ }
830
+ if (parts.hours !== undefined) {
831
+ date.setUTCHours(parts.hours);
832
+ }
833
+ if (parts.minutes !== undefined) {
834
+ date.setUTCMinutes(parts.minutes);
835
+ }
836
+ if (parts.seconds !== undefined) {
837
+ date.setUTCSeconds(parts.seconds);
838
+ }
839
+ if (parts.millis !== undefined) {
840
+ date.setUTCMilliseconds(parts.millis);
841
+ }
842
+ };
843
+ /**
844
+ * Set the different parts of a `DateTime` as an object.
845
+ *
846
+ * The Date will be time zone adjusted.
847
+ *
848
+ * @since 3.6.0
849
+ * @category parts
850
+ */
851
+ export const setParts = /*#__PURE__*/dual(2, (self, parts) => mutate(self, date => setPartsDate(date, parts)));
852
+ /**
853
+ * Set the different parts of a `DateTime` as an object.
854
+ *
855
+ * @since 3.6.0
856
+ * @category parts
857
+ */
858
+ export const setPartsUtc = /*#__PURE__*/dual(2, (self, parts) => mutateUtc(self, date => setPartsDate(date, parts)));
859
+ // =============================================================================
860
+ // current time zone
861
+ // =============================================================================
862
+ /**
863
+ * @since 3.6.0
864
+ * @category current time zone
865
+ */
866
+ export class CurrentTimeZone extends /*#__PURE__*/Context.Tag("effect/DateTime/CurrentTimeZone")() {}
867
+ /**
868
+ * Set the time zone of a `DateTime` to the current time zone, which is
869
+ * determined by the `CurrentTimeZone` service.
870
+ *
871
+ * @since 3.6.0
872
+ * @category current time zone
873
+ * @example
874
+ * import { DateTime, Effect } from "effect"
875
+ *
876
+ * Effect.gen(function* () {
877
+ * const now = yield* DateTime.now
878
+ *
879
+ * // set the time zone to "Europe/London"
880
+ * const zoned = yield* DateTime.setZoneCurrent(now)
881
+ * }).pipe(DateTime.withCurrentZoneNamed("Europe/London"))
882
+ */
883
+ export const setZoneCurrent = self => Effect.map(CurrentTimeZone, zone => setZone(self, zone));
884
+ /**
885
+ * Provide the `CurrentTimeZone` to an effect.
886
+ *
887
+ * @since 3.6.0
888
+ * @category current time zone
889
+ * @example
890
+ * import { DateTime, Effect } from "effect"
891
+ *
892
+ * const zone = DateTime.zoneUnsafeMakeNamed("Europe/London")
893
+ *
894
+ * Effect.gen(function* () {
895
+ * const now = yield* DateTime.nowInCurrentZone
896
+ * }).pipe(DateTime.withCurrentZone(zone))
897
+ */
898
+ export const withCurrentZone = /*#__PURE__*/dual(2, (effect, zone) => Effect.provideService(effect, CurrentTimeZone, zone));
899
+ /**
900
+ * Provide the `CurrentTimeZone` to an effect, using the system's local time
901
+ * zone.
902
+ *
903
+ * @since 3.6.0
904
+ * @category current time zone
905
+ * @example
906
+ * import { DateTime, Effect } from "effect"
907
+ *
908
+ * Effect.gen(function* () {
909
+ * // will use the system's local time zone
910
+ * const now = yield* DateTime.nowInCurrentZone
911
+ * }).pipe(DateTime.withCurrentZoneLocal)
912
+ */
913
+ export const withCurrentZoneLocal = effect => Effect.provideServiceEffect(effect, CurrentTimeZone, Effect.sync(zoneMakeLocal));
914
+ /**
915
+ * Provide the `CurrentTimeZone` to an effect, using a offset.
916
+ *
917
+ * @since 3.6.0
918
+ * @category current time zone
919
+ * @example
920
+ * import { DateTime, Effect } from "effect"
921
+ *
922
+ * Effect.gen(function* () {
923
+ * // will use the system's local time zone
924
+ * const now = yield* DateTime.nowInCurrentZone
925
+ * }).pipe(DateTime.withCurrentZoneOffset(3 * 60 * 60 * 1000))
926
+ */
927
+ export const withCurrentZoneOffset = /*#__PURE__*/dual(2, (effect, offset) => Effect.provideService(effect, CurrentTimeZone, zoneMakeOffset(offset)));
928
+ /**
929
+ * Provide the `CurrentTimeZone` to an effect using an IANA time zone
930
+ * identifier.
931
+ *
932
+ * If the time zone is invalid, it will fail with an `IllegalArgumentException`.
933
+ *
934
+ * @since 3.6.0
935
+ * @category current time zone
936
+ * @example
937
+ * import { DateTime, Effect } from "effect"
938
+ *
939
+ * Effect.gen(function* () {
940
+ * // will use the "Europe/London" time zone
941
+ * const now = yield* DateTime.nowInCurrentZone
942
+ * }).pipe(DateTime.withCurrentZoneNamed("Europe/London"))
943
+ */
944
+ export const withCurrentZoneNamed = /*#__PURE__*/dual(2, (effect, zone) => Effect.provideServiceEffect(effect, CurrentTimeZone, zoneMakeNamedEffect(zone)));
945
+ /**
946
+ * Get the current time as a `DateTime.Zoned`, using the `CurrentTimeZone`.
947
+ *
948
+ * @since 3.6.0
949
+ * @category current time zone
950
+ * @example
951
+ * import { DateTime, Effect } from "effect"
952
+ *
953
+ * Effect.gen(function* () {
954
+ * // will use the "Europe/London" time zone
955
+ * const now = yield* DateTime.nowInCurrentZone
956
+ * }).pipe(DateTime.withCurrentZoneNamed("Europe/London"))
957
+ */
958
+ export const nowInCurrentZone = /*#__PURE__*/Effect.flatMap(now, setZoneCurrent);
959
+ /**
960
+ * Create a Layer from the given time zone.
961
+ *
962
+ * @since 3.6.0
963
+ * @category current time zone
964
+ */
965
+ export const layerCurrentZone = zone => Layer.succeed(CurrentTimeZone, zone);
966
+ /**
967
+ * Create a Layer from the given time zone offset.
968
+ *
969
+ * @since 3.6.0
970
+ * @category current time zone
971
+ */
972
+ export const layerCurrentZoneOffset = offset => Layer.succeed(CurrentTimeZone, zoneMakeOffset(offset));
973
+ /**
974
+ * Create a Layer from the given IANA time zone identifier.
975
+ *
976
+ * @since 3.6.0
977
+ * @category current time zone
978
+ */
979
+ export const layerCurrentZoneNamed = zoneId => Layer.effect(CurrentTimeZone, zoneMakeNamedEffect(zoneId));
980
+ /**
981
+ * Create a Layer from the systems local time zone.
982
+ *
983
+ * @since 3.6.0
984
+ * @category current time zone
985
+ */
986
+ export const layerCurrentZoneLocal = /*#__PURE__*/Layer.sync(CurrentTimeZone, zoneMakeLocal);
987
+ // =============================================================================
988
+ // mapping
989
+ // =============================================================================
990
+ const makeZonedFromAdjusted = (adjustedMillis, zone) => {
991
+ const offset = zone._tag === "Offset" ? zone.offset : calculateNamedOffset(adjustedMillis, zone);
992
+ return makeZonedProto(adjustedMillis - offset, zone);
993
+ };
994
+ const offsetRegex = /([+-])(\d{2}):(\d{2})$/;
995
+ const parseOffset = offset => {
996
+ const match = offsetRegex.exec(offset);
997
+ if (match === null) {
998
+ return null;
999
+ }
1000
+ const [, sign, hours, minutes] = match;
1001
+ return (sign === "+" ? 1 : -1) * (Number(hours) * 60 + Number(minutes)) * 60 * 1000;
1002
+ };
1003
+ const calculateNamedOffset = (adjustedMillis, zone) => {
1004
+ const offset = zone.format.formatToParts(adjustedMillis).find(_ => _.type === "timeZoneName")?.value ?? "";
1005
+ if (offset === "GMT") {
1006
+ return 0;
1007
+ }
1008
+ const result = parseOffset(offset);
1009
+ if (result === null) {
1010
+ // fallback to using the adjusted date
1011
+ return zonedOffset(makeZonedProto(adjustedMillis, zone));
1012
+ }
1013
+ return result;
1014
+ };
1015
+ /**
1016
+ * Modify a `DateTime` by applying a function to a cloned `Date` instance.
1017
+ *
1018
+ * The `Date` will first have the time zone applied if possible, and then be
1019
+ * converted back to a `DateTime` within the same time zone.
1020
+ *
1021
+ * @since 3.6.0
1022
+ * @category mapping
1023
+ */
1024
+ export const mutate = /*#__PURE__*/dual(2, (self, f) => {
1025
+ if (self._tag === "Utc") {
1026
+ const date = toDateUtc(self);
1027
+ f(date);
1028
+ return makeUtc(date.getTime());
1029
+ }
1030
+ const adjustedDate = toDate(self);
1031
+ const newAdjustedDate = new Date(adjustedDate.getTime());
1032
+ f(newAdjustedDate);
1033
+ return makeZonedFromAdjusted(newAdjustedDate.getTime(), self.zone);
1034
+ });
1035
+ /**
1036
+ * Modify a `DateTime` by applying a function to a cloned UTC `Date` instance.
1037
+ *
1038
+ * @since 3.6.0
1039
+ * @category mapping
1040
+ */
1041
+ export const mutateUtc = /*#__PURE__*/dual(2, (self, f) => mapEpochMillis(self, millis => {
1042
+ const date = new Date(millis);
1043
+ f(date);
1044
+ return date.getTime();
1045
+ }));
1046
+ /**
1047
+ * Transform a `DateTime` by applying a function to the number of milliseconds
1048
+ * since the Unix epoch.
1049
+ *
1050
+ * @since 3.6.0
1051
+ * @category mapping
1052
+ * @example
1053
+ * import { DateTime } from "effect"
1054
+ *
1055
+ * // add 10 milliseconds
1056
+ * DateTime.unsafeMake(0).pipe(
1057
+ * DateTime.mapEpochMillis((millis) => millis + 10)
1058
+ * )
1059
+ */
1060
+ export const mapEpochMillis = /*#__PURE__*/dual(2, (self, f) => {
1061
+ const millis = f(toEpochMillis(self));
1062
+ return self._tag === "Utc" ? makeUtc(millis) : makeZonedProto(millis, self.zone);
1063
+ });
1064
+ /**
1065
+ * Using the time zone adjusted `Date`, apply a function to the `Date` and
1066
+ * return the result.
1067
+ *
1068
+ * @since 3.6.0
1069
+ * @category mapping
1070
+ * @example
1071
+ * import { DateTime } from "effect"
1072
+ *
1073
+ * // get the time zone adjusted date in milliseconds
1074
+ * DateTime.unsafeMakeZoned(0, { timeZone: "Europe/London" }).pipe(
1075
+ * DateTime.withDate((date) => date.getTime())
1076
+ * )
1077
+ */
1078
+ export const withDate = /*#__PURE__*/dual(2, (self, f) => f(toDate(self)));
1079
+ /**
1080
+ * Using the time zone adjusted `Date`, apply a function to the `Date` and
1081
+ * return the result.
1082
+ *
1083
+ * @since 3.6.0
1084
+ * @category mapping
1085
+ * @example
1086
+ * import { DateTime } from "effect"
1087
+ *
1088
+ * // get the date in milliseconds
1089
+ * DateTime.unsafeMake(0).pipe(
1090
+ * DateTime.withDateUtc((date) => date.getTime())
1091
+ * )
1092
+ */
1093
+ export const withDateUtc = /*#__PURE__*/dual(2, (self, f) => f(toDateUtc(self)));
1094
+ /**
1095
+ * @since 3.6.0
1096
+ * @category mapping
1097
+ */
1098
+ export const match = /*#__PURE__*/dual(2, (self, options) => self._tag === "Utc" ? options.onUtc(self) : options.onZoned(self));
1099
+ // =============================================================================
1100
+ // math
1101
+ // =============================================================================
1102
+ /**
1103
+ * Add the given `Duration` to a `DateTime`.
1104
+ *
1105
+ * @since 3.6.0
1106
+ * @category math
1107
+ * @example
1108
+ * import { DateTime } from "effect"
1109
+ *
1110
+ * // add 5 minutes
1111
+ * DateTime.unsafeMake(0).pipe(
1112
+ * DateTime.addDuration("5 minutes")
1113
+ * )
1114
+ */
1115
+ export const addDuration = /*#__PURE__*/dual(2, (self, duration) => mapEpochMillis(self, millis => millis + Duration.toMillis(duration)));
1116
+ /**
1117
+ * Subtract the given `Duration` from a `DateTime`.
1118
+ *
1119
+ * @since 3.6.0
1120
+ * @category math
1121
+ * @example
1122
+ * import { DateTime } from "effect"
1123
+ *
1124
+ * // subtract 5 minutes
1125
+ * DateTime.unsafeMake(0).pipe(
1126
+ * DateTime.subtractDuration("5 minutes")
1127
+ * )
1128
+ */
1129
+ export const subtractDuration = /*#__PURE__*/dual(2, (self, duration) => mapEpochMillis(self, millis => millis - Duration.toMillis(duration)));
1130
+ const addMillis = (date, amount) => {
1131
+ date.setTime(date.getTime() + amount);
1132
+ };
1133
+ /**
1134
+ * Add the given `amount` of `unit`'s to a `DateTime`.
1135
+ *
1136
+ * The time zone is taken into account when adding days, weeks, months, and
1137
+ * years.
1138
+ *
1139
+ * @since 3.6.0
1140
+ * @category math
1141
+ * @example
1142
+ * import { DateTime } from "effect"
1143
+ *
1144
+ * // add 5 minutes
1145
+ * DateTime.unsafeMake(0).pipe(
1146
+ * DateTime.add({ minutes: 5 })
1147
+ * )
1148
+ */
1149
+ export const add = /*#__PURE__*/dual(2, (self, parts) => mutate(self, date => {
1150
+ if (parts.millis) {
1151
+ addMillis(date, parts.millis);
1152
+ }
1153
+ if (parts.seconds) {
1154
+ addMillis(date, parts.seconds * 1000);
1155
+ }
1156
+ if (parts.minutes) {
1157
+ addMillis(date, parts.minutes * 60 * 1000);
1158
+ }
1159
+ if (parts.hours) {
1160
+ addMillis(date, parts.hours * 60 * 60 * 1000);
1161
+ }
1162
+ if (parts.days) {
1163
+ date.setUTCDate(date.getUTCDate() + parts.days);
1164
+ }
1165
+ if (parts.weeks) {
1166
+ date.setUTCDate(date.getUTCDate() + parts.weeks * 7);
1167
+ }
1168
+ if (parts.months) {
1169
+ const day = date.getUTCDate();
1170
+ date.setUTCMonth(date.getUTCMonth() + parts.months + 1, 0);
1171
+ if (day < date.getUTCDate()) {
1172
+ date.setUTCDate(day);
1173
+ }
1174
+ }
1175
+ if (parts.years) {
1176
+ const day = date.getUTCDate();
1177
+ const month = date.getUTCMonth();
1178
+ date.setUTCFullYear(date.getUTCFullYear() + parts.years, month + 1, 0);
1179
+ if (day < date.getUTCDate()) {
1180
+ date.setUTCDate(day);
1181
+ }
1182
+ }
1183
+ }));
1184
+ /**
1185
+ * Subtract the given `amount` of `unit`'s from a `DateTime`.
1186
+ *
1187
+ * @since 3.6.0
1188
+ * @category math
1189
+ * @example
1190
+ * import { DateTime } from "effect"
1191
+ *
1192
+ * // subtract 5 minutes
1193
+ * DateTime.unsafeMake(0).pipe(
1194
+ * DateTime.subtract({ minutes: 5 })
1195
+ * )
1196
+ */
1197
+ export const subtract = /*#__PURE__*/dual(2, (self, parts) => {
1198
+ const newParts = {};
1199
+ for (const key in parts) {
1200
+ newParts[key] = -1 * parts[key];
1201
+ }
1202
+ return add(self, newParts);
1203
+ });
1204
+ function startOfDate(date, part, options) {
1205
+ switch (part) {
1206
+ case "second":
1207
+ {
1208
+ date.setUTCMilliseconds(0);
1209
+ break;
1210
+ }
1211
+ case "minute":
1212
+ {
1213
+ date.setUTCSeconds(0, 0);
1214
+ break;
1215
+ }
1216
+ case "hour":
1217
+ {
1218
+ date.setUTCMinutes(0, 0, 0);
1219
+ break;
1220
+ }
1221
+ case "day":
1222
+ {
1223
+ date.setUTCHours(0, 0, 0, 0);
1224
+ break;
1225
+ }
1226
+ case "week":
1227
+ {
1228
+ const weekStartsOn = options?.weekStartsOn ?? 0;
1229
+ const day = date.getUTCDay();
1230
+ const diff = (day - weekStartsOn + 7) % 7;
1231
+ date.setUTCDate(date.getUTCDate() - diff);
1232
+ date.setUTCHours(0, 0, 0, 0);
1233
+ break;
1234
+ }
1235
+ case "month":
1236
+ {
1237
+ date.setUTCDate(1);
1238
+ date.setUTCHours(0, 0, 0, 0);
1239
+ break;
1240
+ }
1241
+ case "year":
1242
+ {
1243
+ date.setUTCMonth(0, 1);
1244
+ date.setUTCHours(0, 0, 0, 0);
1245
+ break;
1246
+ }
1247
+ }
1248
+ }
1249
+ /**
1250
+ * Converts a `DateTime` to the start of the given `part`.
1251
+ *
1252
+ * If the part is `week`, the `weekStartsOn` option can be used to specify the
1253
+ * day of the week that the week starts on. The default is 0 (Sunday).
1254
+ *
1255
+ * @since 3.6.0
1256
+ * @category math
1257
+ * @example
1258
+ * import { DateTime } from "effect"
1259
+ *
1260
+ * // returns "2024-01-01T00:00:00Z"
1261
+ * DateTime.unsafeMake("2024-01-01T12:00:00Z").pipe(
1262
+ * DateTime.startOf("day"),
1263
+ * DateTime.formatIso
1264
+ * )
1265
+ */
1266
+ export const startOf = /*#__PURE__*/dual(isDateTimeArgs, (self, part, options) => mutate(self, date => startOfDate(date, part, options)));
1267
+ function endOfDate(date, part, options) {
1268
+ switch (part) {
1269
+ case "second":
1270
+ {
1271
+ date.setUTCMilliseconds(999);
1272
+ break;
1273
+ }
1274
+ case "minute":
1275
+ {
1276
+ date.setUTCSeconds(59, 999);
1277
+ break;
1278
+ }
1279
+ case "hour":
1280
+ {
1281
+ date.setUTCMinutes(59, 59, 999);
1282
+ break;
1283
+ }
1284
+ case "day":
1285
+ {
1286
+ date.setUTCHours(23, 59, 59, 999);
1287
+ break;
1288
+ }
1289
+ case "week":
1290
+ {
1291
+ const weekStartsOn = options?.weekStartsOn ?? 0;
1292
+ const day = date.getUTCDay();
1293
+ const diff = (day - weekStartsOn + 7) % 7;
1294
+ date.setUTCDate(date.getUTCDate() - diff + 6);
1295
+ date.setUTCHours(23, 59, 59, 999);
1296
+ break;
1297
+ }
1298
+ case "month":
1299
+ {
1300
+ date.setUTCMonth(date.getUTCMonth() + 1, 0);
1301
+ date.setUTCHours(23, 59, 59, 999);
1302
+ break;
1303
+ }
1304
+ case "year":
1305
+ {
1306
+ date.setUTCMonth(11, 31);
1307
+ date.setUTCHours(23, 59, 59, 999);
1308
+ break;
1309
+ }
1310
+ }
1311
+ }
1312
+ /**
1313
+ * Converts a `DateTime` to the end of the given `part`.
1314
+ *
1315
+ * If the part is `week`, the `weekStartsOn` option can be used to specify the
1316
+ * day of the week that the week starts on. The default is 0 (Sunday).
1317
+ *
1318
+ * @since 3.6.0
1319
+ * @category math
1320
+ * @example
1321
+ * import { DateTime } from "effect"
1322
+ *
1323
+ * // returns "2024-01-01T23:59:59.999Z"
1324
+ * DateTime.unsafeMake("2024-01-01T12:00:00Z").pipe(
1325
+ * DateTime.endOf("day"),
1326
+ * DateTime.formatIso
1327
+ * )
1328
+ */
1329
+ export const endOf = /*#__PURE__*/dual(isDateTimeArgs, (self, part, options) => mutate(self, date => endOfDate(date, part, options)));
1330
+ /**
1331
+ * Converts a `DateTime` to the nearest given `part`.
1332
+ *
1333
+ * If the part is `week`, the `weekStartsOn` option can be used to specify the
1334
+ * day of the week that the week starts on. The default is 0 (Sunday).
1335
+ *
1336
+ * @since 3.6.0
1337
+ * @category math
1338
+ * @example
1339
+ * import { DateTime } from "effect"
1340
+ *
1341
+ * // returns "2024-01-02T00:00:00Z"
1342
+ * DateTime.unsafeMake("2024-01-01T12:01:00Z").pipe(
1343
+ * DateTime.nearest("day"),
1344
+ * DateTime.formatIso
1345
+ * )
1346
+ */
1347
+ export const nearest = /*#__PURE__*/dual(isDateTimeArgs, (self, part, options) => mutate(self, date => {
1348
+ if (part === "milli") return;
1349
+ const millis = date.getTime();
1350
+ const start = new Date(millis);
1351
+ startOfDate(start, part, options);
1352
+ const startMillis = start.getTime();
1353
+ const end = new Date(millis);
1354
+ endOfDate(end, part, options);
1355
+ const endMillis = end.getTime() + 1;
1356
+ const diffStart = millis - startMillis;
1357
+ const diffEnd = endMillis - millis;
1358
+ if (diffStart < diffEnd) {
1359
+ date.setTime(startMillis);
1360
+ } else {
1361
+ date.setTime(endMillis);
1362
+ }
1363
+ }));
1364
+ // =============================================================================
1365
+ // formatting
1366
+ // =============================================================================
1367
+ const intlTimeZone = self => {
1368
+ if (self._tag === "Named") {
1369
+ return self.id;
1370
+ }
1371
+ return offsetToString(self.offset);
1372
+ };
1373
+ /**
1374
+ * Format a `DateTime` as a string using the `DateTimeFormat` API.
1375
+ *
1376
+ * The `timeZone` option is set to the offset of the time zone.
1377
+ *
1378
+ * Note: On Node versions < 22, fixed "Offset" zones will set the time zone to
1379
+ * "UTC" and use the adjusted `Date`.
1380
+ *
1381
+ * @since 3.6.0
1382
+ * @category formatting
1383
+ */
1384
+ export const format = /*#__PURE__*/dual(isDateTimeArgs, (self, options) => {
1385
+ try {
1386
+ return new Intl.DateTimeFormat(options?.locale, {
1387
+ timeZone: self._tag === "Utc" ? "UTC" : intlTimeZone(self.zone),
1388
+ ...options
1389
+ }).format(self.epochMillis);
1390
+ } catch (_) {
1391
+ return new Intl.DateTimeFormat(options?.locale, {
1392
+ timeZone: "UTC",
1393
+ ...options
1394
+ }).format(toDate(self));
1395
+ }
1396
+ });
1397
+ /**
1398
+ * Format a `DateTime` as a string using the `DateTimeFormat` API.
1399
+ *
1400
+ * It will use the system's local time zone.
1401
+ *
1402
+ * @since 3.6.0
1403
+ * @category formatting
1404
+ */
1405
+ export const formatLocal = /*#__PURE__*/dual(isDateTimeArgs, (self, options) => new Intl.DateTimeFormat(options?.locale, options).format(self.epochMillis));
1406
+ /**
1407
+ * Format a `DateTime` as a string using the `DateTimeFormat` API.
1408
+ *
1409
+ * This forces the time zone to be UTC.
1410
+ *
1411
+ * @since 3.6.0
1412
+ * @category formatting
1413
+ */
1414
+ export const formatUtc = /*#__PURE__*/dual(isDateTimeArgs, (self, options) => new Intl.DateTimeFormat(options?.locale, {
1415
+ ...options,
1416
+ timeZone: "UTC"
1417
+ }).format(self.epochMillis));
1418
+ /**
1419
+ * Format a `DateTime` as a string using the `DateTimeFormat` API.
1420
+ *
1421
+ * @since 3.6.0
1422
+ * @category formatting
1423
+ */
1424
+ export const formatIntl = /*#__PURE__*/dual(2, (self, format) => format.format(self.epochMillis));
1425
+ /**
1426
+ * Format a `DateTime` as a UTC ISO string.
1427
+ *
1428
+ * @since 3.6.0
1429
+ * @category formatting
1430
+ */
1431
+ export const formatIso = self => toDateUtc(self).toISOString();
1432
+ /**
1433
+ * Format a `DateTime` as a time zone adjusted ISO date string.
1434
+ *
1435
+ * @since 3.6.0
1436
+ * @category formatting
1437
+ */
1438
+ export const formatIsoDate = self => toDate(self).toISOString().slice(0, 10);
1439
+ /**
1440
+ * Format a `DateTime` as a UTC ISO date string.
1441
+ *
1442
+ * @since 3.6.0
1443
+ * @category formatting
1444
+ */
1445
+ export const formatIsoDateUtc = self => toDateUtc(self).toISOString().slice(0, 10);
1446
+ /**
1447
+ * Format a `DateTime.Zoned` as a ISO string with an offset.
1448
+ *
1449
+ * @since 3.6.0
1450
+ * @category formatting
1451
+ */
1452
+ export const formatIsoOffset = self => {
1453
+ const date = toDate(self);
1454
+ return self._tag === "Utc" ? date.toISOString() : `${date.toISOString().slice(0, -1)}${zonedOffsetIso(self)}`;
1455
+ };
1456
+ /**
1457
+ * Format a `DateTime.Zoned` as a string.
1458
+ *
1459
+ * It uses the format: `YYYY-MM-DDTHH:mm:ss.sss+HH:MM[Time/Zone]`.
1460
+ *
1461
+ * @since 3.6.0
1462
+ * @category formatting
1463
+ */
1464
+ export const formatIsoZoned = self => self.zone._tag === "Offset" ? formatIsoOffset(self) : `${formatIsoOffset(self)}[${self.zone.id}]`;
1465
+ //# sourceMappingURL=DateTime.js.map