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.
- package/DateTime/package.json +6 -0
- package/dist/cjs/Context.js.map +1 -1
- package/dist/cjs/DateTime.js +1514 -0
- package/dist/cjs/DateTime.js.map +1 -0
- package/dist/cjs/Effect.js +3 -3
- package/dist/cjs/Effect.js.map +1 -1
- package/dist/cjs/Either.js +3 -3
- package/dist/cjs/List.js.map +1 -1
- package/dist/cjs/Metric.js.map +1 -1
- package/dist/cjs/Micro.js +93 -41
- package/dist/cjs/Micro.js.map +1 -1
- package/dist/cjs/Option.js +3 -3
- package/dist/cjs/Predicate.js +8 -0
- package/dist/cjs/Predicate.js.map +1 -1
- package/dist/cjs/Random.js +16 -1
- package/dist/cjs/Random.js.map +1 -1
- package/dist/cjs/Stream.js +86 -7
- package/dist/cjs/Stream.js.map +1 -1
- package/dist/cjs/Struct.js +23 -1
- package/dist/cjs/Struct.js.map +1 -1
- package/dist/cjs/index.js +4 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/configProvider.js.map +1 -1
- package/dist/cjs/internal/core.js +1 -1
- package/dist/cjs/internal/core.js.map +1 -1
- package/dist/cjs/internal/defaultServices.js +9 -2
- package/dist/cjs/internal/defaultServices.js.map +1 -1
- package/dist/cjs/internal/metric.js.map +1 -1
- package/dist/cjs/internal/stream/emit.js +73 -1
- package/dist/cjs/internal/stream/emit.js.map +1 -1
- package/dist/cjs/internal/stream.js +30 -22
- package/dist/cjs/internal/stream.js.map +1 -1
- package/dist/cjs/internal/version.js +1 -1
- package/dist/dts/ConfigProvider.d.ts +2 -2
- package/dist/dts/ConfigProvider.d.ts.map +1 -1
- package/dist/dts/Context.d.ts +3 -1
- package/dist/dts/Context.d.ts.map +1 -1
- package/dist/dts/DateTime.d.ts +1265 -0
- package/dist/dts/DateTime.d.ts.map +1 -0
- package/dist/dts/Effect.d.ts +18 -4
- package/dist/dts/Effect.d.ts.map +1 -1
- package/dist/dts/Either.d.ts +4 -4
- package/dist/dts/List.d.ts +2 -1
- package/dist/dts/List.d.ts.map +1 -1
- package/dist/dts/Metric.d.ts +1 -1
- package/dist/dts/Metric.d.ts.map +1 -1
- package/dist/dts/MetricRegistry.d.ts +1 -1
- package/dist/dts/MetricRegistry.d.ts.map +1 -1
- package/dist/dts/Micro.d.ts +60 -0
- package/dist/dts/Micro.d.ts.map +1 -1
- package/dist/dts/Option.d.ts +4 -4
- package/dist/dts/Predicate.d.ts +63 -2
- package/dist/dts/Predicate.d.ts.map +1 -1
- package/dist/dts/Random.d.ts +18 -0
- package/dist/dts/Random.d.ts.map +1 -1
- package/dist/dts/Stream.d.ts +95 -4
- package/dist/dts/Stream.d.ts.map +1 -1
- package/dist/dts/StreamEmit.d.ts +44 -0
- package/dist/dts/StreamEmit.d.ts.map +1 -1
- package/dist/dts/Struct.d.ts +21 -0
- package/dist/dts/Struct.d.ts.map +1 -1
- package/dist/dts/index.d.ts +4 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/core.d.ts.map +1 -1
- package/dist/dts/internal/defaultServices.d.ts.map +1 -1
- package/dist/dts/internal/stream.d.ts.map +1 -1
- package/dist/esm/Context.js.map +1 -1
- package/dist/esm/DateTime.js +1465 -0
- package/dist/esm/DateTime.js.map +1 -0
- package/dist/esm/Effect.js +4 -4
- package/dist/esm/Effect.js.map +1 -1
- package/dist/esm/Either.js +4 -4
- package/dist/esm/List.js.map +1 -1
- package/dist/esm/Metric.js.map +1 -1
- package/dist/esm/Micro.js +88 -38
- package/dist/esm/Micro.js.map +1 -1
- package/dist/esm/Option.js +4 -4
- package/dist/esm/Predicate.js +8 -0
- package/dist/esm/Predicate.js.map +1 -1
- package/dist/esm/Random.js +15 -0
- package/dist/esm/Random.js.map +1 -1
- package/dist/esm/Stream.js +84 -5
- package/dist/esm/Stream.js.map +1 -1
- package/dist/esm/Struct.js +21 -0
- package/dist/esm/Struct.js.map +1 -1
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/configProvider.js.map +1 -1
- package/dist/esm/internal/core.js +1 -1
- package/dist/esm/internal/core.js.map +1 -1
- package/dist/esm/internal/defaultServices.js +6 -0
- package/dist/esm/internal/defaultServices.js.map +1 -1
- package/dist/esm/internal/metric.js.map +1 -1
- package/dist/esm/internal/stream/emit.js +71 -0
- package/dist/esm/internal/stream/emit.js.map +1 -1
- package/dist/esm/internal/stream.js +24 -18
- package/dist/esm/internal/stream.js.map +1 -1
- package/dist/esm/internal/version.js +1 -1
- package/package.json +9 -1
- package/src/ConfigProvider.ts +2 -2
- package/src/Context.ts +3 -1
- package/src/DateTime.ts +2104 -0
- package/src/Effect.ts +28 -4
- package/src/Either.ts +4 -4
- package/src/List.ts +3 -2
- package/src/Metric.ts +1 -1
- package/src/MetricRegistry.ts +1 -1
- package/src/Micro.ts +117 -45
- package/src/Option.ts +4 -4
- package/src/Predicate.ts +68 -8
- package/src/Random.ts +24 -0
- package/src/Stream.ts +110 -5
- package/src/StreamEmit.ts +53 -0
- package/src/Struct.ts +22 -0
- package/src/index.ts +5 -0
- package/src/internal/configProvider.ts +20 -20
- package/src/internal/core.ts +37 -12
- package/src/internal/defaultServices.ts +14 -0
- package/src/internal/metric/registry.ts +1 -1
- package/src/internal/metric.ts +2 -2
- package/src/internal/stream/emit.ts +77 -0
- package/src/internal/stream.ts +86 -18
- 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
|