@rvoh/dream 2.3.0-alpha.4 → 2.3.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/src/utils/datetime/CalendarDate.js +32 -0
- package/dist/cjs/src/utils/datetime/DateTime.js +112 -61
- package/dist/cjs/src/utils/datetime/helpers/isoTimeDecimalString.js +8 -4
- package/dist/cjs/src/utils/datetime/helpers/replaceISOMicroseconds.js +4 -1
- package/dist/esm/src/utils/datetime/CalendarDate.js +32 -0
- package/dist/esm/src/utils/datetime/DateTime.js +112 -61
- package/dist/esm/src/utils/datetime/helpers/isoTimeDecimalString.js +8 -4
- package/dist/esm/src/utils/datetime/helpers/replaceISOMicroseconds.js +4 -1
- package/dist/types/src/types/datetime.d.ts +2 -0
- package/dist/types/src/types/datetime.ts +2 -0
- package/dist/types/src/utils/datetime/CalendarDate.d.ts +19 -0
- package/dist/types/src/utils/datetime/DateTime.d.ts +46 -11
- package/dist/types/src/utils/datetime/helpers/isoTimeDecimalString.d.ts +3 -2
- package/dist/types/src/utils/datetime/helpers/replaceISOMicroseconds.d.ts +4 -2
- package/docs/assets/search.js +1 -1
- package/docs/classes/db.DreamMigrationHelpers.html +9 -9
- package/docs/classes/db.KyselyQueryDriver.html +32 -32
- package/docs/classes/db.PostgresQueryDriver.html +33 -33
- package/docs/classes/db.QueryDriverBase.html +31 -31
- package/docs/classes/errors.CheckConstraintViolation.html +3 -3
- package/docs/classes/errors.ColumnOverflow.html +3 -3
- package/docs/classes/errors.CreateOrFindByFailedToCreateAndFind.html +3 -3
- package/docs/classes/errors.DataIncompatibleWithDatabaseField.html +3 -3
- package/docs/classes/errors.DataTypeColumnTypeMismatch.html +3 -3
- package/docs/classes/errors.GlobalNameNotSet.html +3 -3
- package/docs/classes/errors.InvalidCalendarDate.html +2 -2
- package/docs/classes/errors.InvalidDateTime.html +2 -2
- package/docs/classes/errors.MissingSerializersDefinition.html +3 -3
- package/docs/classes/errors.NonLoadedAssociation.html +3 -3
- package/docs/classes/errors.NotNullViolation.html +3 -3
- package/docs/classes/errors.RecordNotFound.html +3 -3
- package/docs/classes/errors.ValidationError.html +3 -3
- package/docs/classes/index.CalendarDate.html +56 -45
- package/docs/classes/index.DateTime.html +165 -145
- package/docs/classes/index.Decorators.html +19 -19
- package/docs/classes/index.Dream.html +116 -116
- package/docs/classes/index.DreamApp.html +5 -5
- package/docs/classes/index.DreamTransaction.html +2 -2
- package/docs/classes/index.Env.html +2 -2
- package/docs/classes/index.Query.html +56 -56
- package/docs/classes/system.CliFileWriter.html +2 -2
- package/docs/classes/system.DreamBin.html +2 -2
- package/docs/classes/system.DreamCLI.html +5 -5
- package/docs/classes/system.DreamImporter.html +2 -2
- package/docs/classes/system.DreamLogos.html +2 -2
- package/docs/classes/system.DreamSerializerBuilder.html +8 -8
- package/docs/classes/system.ObjectSerializerBuilder.html +8 -8
- package/docs/classes/system.PathHelpers.html +3 -3
- package/docs/classes/utils.Encrypt.html +2 -2
- package/docs/classes/utils.Range.html +2 -2
- package/docs/functions/db.closeAllDbConnections.html +1 -1
- package/docs/functions/db.dreamDbConnections.html +1 -1
- package/docs/functions/db.untypedDb.html +1 -1
- package/docs/functions/db.validateColumn.html +1 -1
- package/docs/functions/db.validateTable.html +1 -1
- package/docs/functions/errors.pgErrorType.html +1 -1
- package/docs/functions/index.DreamSerializer.html +1 -1
- package/docs/functions/index.ObjectSerializer.html +1 -1
- package/docs/functions/index.ReplicaSafe.html +1 -1
- package/docs/functions/index.STI.html +1 -1
- package/docs/functions/index.SoftDelete.html +1 -1
- package/docs/functions/utils.camelize.html +1 -1
- package/docs/functions/utils.capitalize.html +1 -1
- package/docs/functions/utils.cloneDeepSafe.html +1 -1
- package/docs/functions/utils.compact.html +1 -1
- package/docs/functions/utils.groupBy.html +1 -1
- package/docs/functions/utils.hyphenize.html +1 -1
- package/docs/functions/utils.intersection.html +1 -1
- package/docs/functions/utils.isEmpty.html +1 -1
- package/docs/functions/utils.normalizeUnicode.html +1 -1
- package/docs/functions/utils.pascalize.html +1 -1
- package/docs/functions/utils.percent.html +1 -1
- package/docs/functions/utils.range-1.html +1 -1
- package/docs/functions/utils.round.html +1 -1
- package/docs/functions/utils.sanitizeString.html +1 -1
- package/docs/functions/utils.snakeify.html +1 -1
- package/docs/functions/utils.sort.html +1 -1
- package/docs/functions/utils.sortBy.html +1 -1
- package/docs/functions/utils.sortObjectByKey.html +1 -1
- package/docs/functions/utils.sortObjectByValue.html +1 -1
- package/docs/functions/utils.uncapitalize.html +1 -1
- package/docs/functions/utils.uniq.html +1 -1
- package/docs/interfaces/openapi.OpenapiDescription.html +2 -2
- package/docs/interfaces/openapi.OpenapiSchemaProperties.html +1 -1
- package/docs/interfaces/openapi.OpenapiSchemaPropertiesShorthand.html +1 -1
- package/docs/interfaces/openapi.OpenapiTypeFieldObject.html +1 -1
- package/docs/interfaces/types.BelongsToStatement.html +2 -2
- package/docs/interfaces/types.DecoratorContext.html +2 -2
- package/docs/interfaces/types.DreamAppInitOptions.html +2 -2
- package/docs/interfaces/types.DreamAppOpts.html +2 -2
- package/docs/interfaces/types.DurationObject.html +2 -2
- package/docs/interfaces/types.EncryptOptions.html +2 -2
- package/docs/interfaces/types.InternalAnyTypedSerializerRendersMany.html +2 -2
- package/docs/interfaces/types.InternalAnyTypedSerializerRendersOne.html +2 -2
- package/docs/interfaces/types.SerializerRendererOpts.html +2 -2
- package/docs/modules/db.html +1 -1
- package/docs/modules/errors.html +1 -1
- package/docs/modules/index.html +1 -1
- package/docs/modules/openapi.html +1 -1
- package/docs/modules/system.html +1 -1
- package/docs/modules/types.html +1 -1
- package/docs/modules/utils.html +1 -1
- package/docs/types/openapi.CommonOpenapiSchemaObjectFields.html +1 -1
- package/docs/types/openapi.OpenapiAllTypes.html +1 -1
- package/docs/types/openapi.OpenapiFormats.html +1 -1
- package/docs/types/openapi.OpenapiNumberFormats.html +1 -1
- package/docs/types/openapi.OpenapiPrimitiveBaseTypes.html +1 -1
- package/docs/types/openapi.OpenapiPrimitiveTypes.html +1 -1
- package/docs/types/openapi.OpenapiSchemaArray.html +1 -1
- package/docs/types/openapi.OpenapiSchemaArrayShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaBase.html +1 -1
- package/docs/types/openapi.OpenapiSchemaBody.html +1 -1
- package/docs/types/openapi.OpenapiSchemaBodyShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaCommonFields.html +1 -1
- package/docs/types/openapi.OpenapiSchemaExpressionAllOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaExpressionAnyOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaExpressionOneOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaExpressionRef.html +1 -1
- package/docs/types/openapi.OpenapiSchemaExpressionRefSchemaShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaInteger.html +1 -1
- package/docs/types/openapi.OpenapiSchemaNull.html +1 -1
- package/docs/types/openapi.OpenapiSchemaNumber.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObject.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAllOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAllOfShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAnyOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectAnyOfShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectBase.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectBaseShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectOneOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectOneOfShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaObjectShorthand.html +1 -1
- package/docs/types/openapi.OpenapiSchemaPrimitiveGeneric.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionAllOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionAnyOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionOneOf.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializableRef.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandExpressionSerializerRef.html +1 -1
- package/docs/types/openapi.OpenapiSchemaShorthandPrimitiveGeneric.html +1 -1
- package/docs/types/openapi.OpenapiSchemaString.html +1 -1
- package/docs/types/openapi.OpenapiShorthandAllTypes.html +1 -1
- package/docs/types/openapi.OpenapiShorthandPrimitiveBaseTypes.html +1 -1
- package/docs/types/openapi.OpenapiShorthandPrimitiveTypes.html +1 -1
- package/docs/types/openapi.OpenapiTypeField.html +1 -1
- package/docs/types/system.DreamAppAllowedPackageManagersEnum.html +1 -1
- package/docs/types/types.CalendarDateDurationUnit.html +1 -1
- package/docs/types/types.Camelized.html +1 -1
- package/docs/types/types.DbConnectionType.html +1 -1
- package/docs/types/types.DbTypes.html +1 -1
- package/docs/types/types.DreamAssociationMetadata.html +1 -1
- package/docs/types/types.DreamAttributes.html +1 -1
- package/docs/types/types.DreamClassAssociationAndStatement.html +1 -1
- package/docs/types/types.DreamClassColumn.html +1 -1
- package/docs/types/types.DreamColumn.html +1 -1
- package/docs/types/types.DreamColumnNames.html +1 -1
- package/docs/types/types.DreamLogLevel.html +1 -1
- package/docs/types/types.DreamLogger.html +1 -1
- package/docs/types/types.DreamModelSerializerType.html +1 -1
- package/docs/types/types.DreamOrViewModelClassSerializerKey.html +1 -1
- package/docs/types/types.DreamOrViewModelSerializerKey.html +1 -1
- package/docs/types/types.DreamParamSafeAttributes.html +1 -1
- package/docs/types/types.DreamParamSafeColumnNames.html +1 -1
- package/docs/types/types.DreamSerializable.html +1 -1
- package/docs/types/types.DreamSerializableArray.html +1 -1
- package/docs/types/types.DreamSerializerKey.html +1 -1
- package/docs/types/types.DreamSerializers.html +1 -1
- package/docs/types/types.DreamVirtualColumns.html +1 -1
- package/docs/types/types.DurationUnit.html +1 -1
- package/docs/types/types.EncryptAlgorithm.html +1 -1
- package/docs/types/types.HasManyStatement.html +1 -1
- package/docs/types/types.HasOneStatement.html +1 -1
- package/docs/types/types.Hyphenized.html +1 -1
- package/docs/types/types.Pascalized.html +1 -1
- package/docs/types/types.PrimaryKeyType.html +1 -1
- package/docs/types/types.RoundingPrecision.html +1 -1
- package/docs/types/types.SerializerCasing.html +1 -1
- package/docs/types/types.SimpleObjectSerializerType.html +1 -1
- package/docs/types/types.Snakeified.html +1 -1
- package/docs/types/types.StrictInterface.html +1 -1
- package/docs/types/types.UpdateableAssociationProperties.html +1 -1
- package/docs/types/types.UpdateableProperties.html +1 -1
- package/docs/types/types.ValidationType.html +1 -1
- package/docs/types/types.ViewModel.html +1 -1
- package/docs/types/types.ViewModelClass.html +1 -1
- package/docs/types/types.WeekdayName.html +1 -1
- package/docs/types/types.WhereStatementForDream.html +1 -1
- package/docs/types/types.WhereStatementForDreamClass.html +1 -1
- package/docs/variables/index.DreamConst.html +1 -1
- package/docs/variables/index.ops.html +1 -1
- package/docs/variables/openapi.openapiPrimitiveTypes-1.html +1 -1
- package/docs/variables/openapi.openapiShorthandPrimitiveTypes-1.html +1 -1
- package/docs/variables/system.DreamAppAllowedPackageManagersEnumValues.html +1 -1
- package/docs/variables/system.primaryKeyTypes.html +1 -1
- package/package.json +1 -1
|
@@ -107,6 +107,38 @@ export default class CalendarDate {
|
|
|
107
107
|
}
|
|
108
108
|
return new CalendarDate(dateTime);
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Create a CalendarDate from a custom format string.
|
|
112
|
+
* Uses Luxon format tokens (e.g., 'MM/dd/yyyy', 'MMMM dd, yyyy').
|
|
113
|
+
* @param text - The string to parse
|
|
114
|
+
* @param format - Format string using Luxon tokens
|
|
115
|
+
* @param options - Optional zone and locale options
|
|
116
|
+
* @returns A CalendarDate for the parsed date
|
|
117
|
+
* @throws {InvalidCalendarDate} When the string doesn't match the format or is invalid
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* CalendarDate.fromFormat('12/15/2017', 'MM/dd/yyyy')
|
|
121
|
+
* CalendarDate.fromFormat('May 25, 1982', 'MMMM dd, yyyy')
|
|
122
|
+
* CalendarDate.fromFormat('mai 25, 1982', 'MMMM dd, yyyy', { locale: 'fr' })
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
static fromFormat(text, format, { zone, locale } = {}) {
|
|
126
|
+
let dateTime;
|
|
127
|
+
try {
|
|
128
|
+
const opts = {};
|
|
129
|
+
if (zone)
|
|
130
|
+
opts.zone = zone;
|
|
131
|
+
if (locale)
|
|
132
|
+
opts.locale = locale;
|
|
133
|
+
dateTime = DateTime.fromFormat(text, format, opts);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (error instanceof Error)
|
|
137
|
+
throw new InvalidCalendarDate(error);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
return new CalendarDate(dateTime);
|
|
141
|
+
}
|
|
110
142
|
/**
|
|
111
143
|
* Create a CalendarDate from an object with date units.
|
|
112
144
|
* @param obj - Object with year, month, day properties
|
|
@@ -381,17 +381,20 @@ export class DateTime {
|
|
|
381
381
|
}
|
|
382
382
|
/**
|
|
383
383
|
* Create a DateTime from epoch milliseconds.
|
|
384
|
-
* @param
|
|
384
|
+
* @param millisecondInput - Unix timestamp in milliseconds (fractional part becomes microseconds)
|
|
385
385
|
* @param options - Optional zone/locale options
|
|
386
386
|
* @returns A DateTime for the given instant
|
|
387
387
|
* @example
|
|
388
388
|
* ```ts
|
|
389
389
|
* DateTime.fromMillis(1707234567890)
|
|
390
|
+
* DateTime.fromMillis(1707234567890.123) // .123 ms = 123 microseconds
|
|
390
391
|
* ```
|
|
391
392
|
*/
|
|
392
|
-
static fromMillis(
|
|
393
|
-
const
|
|
394
|
-
|
|
393
|
+
static fromMillis(millisecondInput, options) {
|
|
394
|
+
const { milliseconds, microseconds } = microsecondParts(millisecondInput * 1000, {
|
|
395
|
+
errorIfNegative: false,
|
|
396
|
+
});
|
|
397
|
+
return new DateTime(LuxonDateTime.fromMillis(milliseconds, options), microseconds);
|
|
395
398
|
}
|
|
396
399
|
/**
|
|
397
400
|
* Create a DateTime from epoch microseconds.
|
|
@@ -410,17 +413,22 @@ export class DateTime {
|
|
|
410
413
|
}
|
|
411
414
|
/**
|
|
412
415
|
* Create a DateTime from epoch seconds.
|
|
413
|
-
*
|
|
416
|
+
* Fractional seconds are converted to milliseconds and microseconds.
|
|
417
|
+
* @param seconds - Unix timestamp in seconds (fractional part becomes ms + µs)
|
|
414
418
|
* @param options - Optional zone/locale options
|
|
415
419
|
* @returns A DateTime for the given instant
|
|
416
420
|
* @example
|
|
417
421
|
* ```ts
|
|
418
422
|
* DateTime.fromSeconds(1707234567)
|
|
423
|
+
* DateTime.fromSeconds(1707234567.123456) // .123456 seconds = 123ms + 456µs
|
|
419
424
|
* ```
|
|
420
425
|
*/
|
|
421
426
|
static fromSeconds(seconds, options) {
|
|
422
|
-
|
|
423
|
-
|
|
427
|
+
// Convert seconds to microseconds to preserve full precision
|
|
428
|
+
const totalMicroseconds = seconds * 1_000_000;
|
|
429
|
+
const { milliseconds, microseconds } = microsecondParts(totalMicroseconds, { errorIfNegative: false });
|
|
430
|
+
const luxonDatetime = LuxonDateTime.fromMillis(milliseconds, options);
|
|
431
|
+
return new DateTime(luxonDatetime, microseconds);
|
|
424
432
|
}
|
|
425
433
|
/**
|
|
426
434
|
* Create a DateTime from an object with date/time units.
|
|
@@ -481,6 +489,46 @@ export class DateTime {
|
|
|
481
489
|
const luxonDatetime = wrapLuxonError(() => LuxonDateTime.fromSQL(textForLuxon, opts));
|
|
482
490
|
return new DateTime(luxonDatetime, microsecond);
|
|
483
491
|
}
|
|
492
|
+
/**
|
|
493
|
+
* Create a DateTime from a custom format string.
|
|
494
|
+
* Supports standard Luxon format tokens plus 'u' or 'SSSSSS' for microseconds (6 decimal places).
|
|
495
|
+
* @param text - The string to parse
|
|
496
|
+
* @param format - Format string using Luxon tokens (e.g., 'MM/dd/yyyy HH:mm:ss.u')
|
|
497
|
+
* @param opts - Optional parsing options (zone, locale, etc.)
|
|
498
|
+
* @returns A DateTime for the parsed instant
|
|
499
|
+
* @throws {InvalidDateTime} When the string doesn't match the format or is invalid
|
|
500
|
+
* @example
|
|
501
|
+
* ```ts
|
|
502
|
+
* DateTime.fromFormat('12/15/2017', 'MM/dd/yyyy')
|
|
503
|
+
* DateTime.fromFormat('12/15/2017 10:30:45', 'MM/dd/yyyy HH:mm:ss')
|
|
504
|
+
* DateTime.fromFormat('12/15/2017 10:30:45.123456', 'MM/dd/yyyy HH:mm:ss.u')
|
|
505
|
+
* DateTime.fromFormat('12/15/2017 10:30:45.123456', 'MM/dd/yyyy HH:mm:ss.SSSSSS')
|
|
506
|
+
* DateTime.fromFormat('mai 25, 1982', 'MMMM dd, yyyy', { locale: 'fr' })
|
|
507
|
+
* ```
|
|
508
|
+
*/
|
|
509
|
+
static fromFormat(text, format, opts) {
|
|
510
|
+
// Check if format includes microsecond token ('u' or 'SSSSSS')
|
|
511
|
+
const hasMicrosecondToken = format.includes('.u') || format.includes('.SSSSSS');
|
|
512
|
+
let microsecond = 0;
|
|
513
|
+
if (hasMicrosecondToken) {
|
|
514
|
+
// Extract microseconds from the text
|
|
515
|
+
const { microsecond: extractedMicrosecond } = parseFractionalPart(text);
|
|
516
|
+
microsecond = extractedMicrosecond;
|
|
517
|
+
// Replace microsecond token with millisecond token for Luxon
|
|
518
|
+
// 'u' -> 'SSS' (Luxon only supports milliseconds)
|
|
519
|
+
// 'SSSSSS' -> 'SSS'
|
|
520
|
+
const formatForLuxon = format.replace(/\.u\b/, '.SSS').replace(/\.SSSSSS\b/, '.SSS');
|
|
521
|
+
// Truncate fractional part to 3 digits for Luxon
|
|
522
|
+
const textForLuxon = toThreeDecimalFraction(text);
|
|
523
|
+
const luxonDatetime = wrapLuxonError(() => LuxonDateTime.fromFormat(textForLuxon, formatForLuxon, opts));
|
|
524
|
+
return new DateTime(luxonDatetime, microsecond);
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
// No microsecond token, use Luxon directly
|
|
528
|
+
const luxonDatetime = wrapLuxonError(() => LuxonDateTime.fromFormat(text, format, opts));
|
|
529
|
+
return new DateTime(luxonDatetime, 0);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
484
532
|
/**
|
|
485
533
|
* Returns an ISO 8601 string with 6 fractional second digits (milliseconds + microseconds).
|
|
486
534
|
* @param opts - Optional format options (includeOffset, suppressMilliseconds, etc.)
|
|
@@ -813,20 +861,38 @@ export class DateTime {
|
|
|
813
861
|
return luxonSeconds + additionalMicroseconds;
|
|
814
862
|
}
|
|
815
863
|
/**
|
|
816
|
-
* Returns the epoch time in seconds as an integer
|
|
817
|
-
* Truncates any fractional seconds, returning only the whole seconds portion.
|
|
818
|
-
* Equivalent to Math.floor(toSeconds()).
|
|
819
|
-
* @returns Unix timestamp in seconds (integer only, no fractional part)
|
|
864
|
+
* Returns the epoch time in seconds as an integer, truncating any fractional part.
|
|
820
865
|
* @example
|
|
821
866
|
* ```ts
|
|
822
|
-
* DateTime.
|
|
823
|
-
* DateTime.fromISO('2026-02-07T09:03:44.
|
|
824
|
-
* DateTime.fromISO('2026-02-07T09:03:44.999999Z').toUnixInteger() // 1770455024 (not rounded up)
|
|
867
|
+
* DateTime.fromISO('2026-02-07T09:03:44.123456Z').unixIntegerSeconds // 1770455024
|
|
868
|
+
* DateTime.fromISO('2026-02-07T09:03:44.999999Z').unixIntegerSeconds // 1770455024 (not rounded up)
|
|
825
869
|
* ```
|
|
826
870
|
*/
|
|
827
|
-
|
|
871
|
+
get unixIntegerSeconds() {
|
|
828
872
|
return Math.floor(this.toSeconds());
|
|
829
873
|
}
|
|
874
|
+
/**
|
|
875
|
+
* Returns the epoch time in milliseconds as an integer, truncating any fractional part.
|
|
876
|
+
* @example
|
|
877
|
+
* ```ts
|
|
878
|
+
* DateTime.fromISO('2026-02-07T09:03:44.123456Z').unixIntegerMilliseconds // 1770455024123
|
|
879
|
+
* DateTime.fromISO('2026-02-07T09:03:44.123999Z').unixIntegerMilliseconds // 1770455024123 (not rounded up)
|
|
880
|
+
* ```
|
|
881
|
+
*/
|
|
882
|
+
get unixIntegerMilliseconds() {
|
|
883
|
+
return Math.floor(this.toMillis());
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Returns the epoch time in microseconds as an integer.
|
|
887
|
+
* Equivalent to `toMicroseconds()` since microseconds are always whole numbers.
|
|
888
|
+
* @example
|
|
889
|
+
* ```ts
|
|
890
|
+
* DateTime.fromISO('2026-02-07T09:03:44.123456Z').unixIntegerMicroseconds // 1770455024123456
|
|
891
|
+
* ```
|
|
892
|
+
*/
|
|
893
|
+
get unixIntegerMicroseconds() {
|
|
894
|
+
return this.toMicroseconds();
|
|
895
|
+
}
|
|
830
896
|
/**
|
|
831
897
|
* Returns the earliest DateTime from the given arguments.
|
|
832
898
|
* @param dateTimes - DateTimes to compare
|
|
@@ -985,58 +1051,43 @@ export class DateTime {
|
|
|
985
1051
|
* ```
|
|
986
1052
|
*/
|
|
987
1053
|
diff(other, unit) {
|
|
988
|
-
|
|
989
|
-
const needsMicroseconds =
|
|
990
|
-
|
|
991
|
-
//
|
|
992
|
-
const
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
if (Array.isArray(unit)) {
|
|
997
|
-
const filtered = unit.filter(u => u !== 'microseconds');
|
|
998
|
-
luxonUnits = filtered.length > 0 ? filtered : undefined;
|
|
999
|
-
}
|
|
1000
|
-
else if (unit === 'microseconds') {
|
|
1001
|
-
luxonUnits = undefined;
|
|
1002
|
-
}
|
|
1003
|
-
// Get Luxon's diff (which handles all units except microseconds)
|
|
1004
|
-
const luxonDuration = this.luxonDatetime.diff(other.toLuxon(), luxonUnits);
|
|
1005
|
-
const fullObject = luxonDuration.toObject();
|
|
1006
|
-
// Calculate microsecond difference if needed
|
|
1007
|
-
if (needsMicroseconds || unit === undefined) {
|
|
1008
|
-
// When microseconds is the ONLY unit requested, return total microseconds
|
|
1054
|
+
const unitArray = unit === undefined ? undefined : typeof unit === 'string' ? [unit] : unit;
|
|
1055
|
+
const needsMicroseconds = !unitArray || unitArray.includes('microseconds');
|
|
1056
|
+
const needsMilliseconds = !unitArray || unitArray.includes('milliseconds');
|
|
1057
|
+
// Strip 'microseconds' before passing to Luxon (it doesn't support it)
|
|
1058
|
+
const luxonUnits = unitArray?.filter(u => u !== 'microseconds');
|
|
1059
|
+
const luxonDuration = this.luxonDatetime.diff(other.toLuxon(), luxonUnits && luxonUnits.length > 0 ? luxonUnits : undefined);
|
|
1060
|
+
const result = luxonDuration.toObject();
|
|
1061
|
+
if (needsMicroseconds) {
|
|
1009
1062
|
if (unit === 'microseconds') {
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
fullObject.microseconds = thisTotalMicroseconds - otherTotalMicroseconds;
|
|
1063
|
+
// Only microseconds requested: return total difference
|
|
1064
|
+
result.microseconds = this.toMicroseconds() - other.toMicroseconds();
|
|
1013
1065
|
}
|
|
1014
|
-
else {
|
|
1015
|
-
//
|
|
1016
|
-
|
|
1017
|
-
const
|
|
1018
|
-
|
|
1066
|
+
else if (needsMilliseconds && result.milliseconds !== undefined) {
|
|
1067
|
+
// Both ms + µs requested: combine Luxon's ms with µs field diff, then re-split.
|
|
1068
|
+
// Example: Luxon says -1ms, µs fields are 999-0=+999 → total=-1µs → 0ms, -1µs
|
|
1069
|
+
const totalMicroDiff = Math.round(result.milliseconds * 1000) + (this.microsecond - other.microsecond);
|
|
1070
|
+
result.milliseconds = Math.trunc(totalMicroDiff / 1000) || 0; // || 0 normalizes -0
|
|
1071
|
+
result.microseconds = totalMicroDiff - result.milliseconds * 1000;
|
|
1019
1072
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
fullObject.milliseconds = Math.trunc(fullObject.milliseconds);
|
|
1073
|
+
else {
|
|
1074
|
+
// µs without ms: just the field difference
|
|
1075
|
+
result.microseconds = this.microsecond - other.microsecond;
|
|
1024
1076
|
}
|
|
1025
1077
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
}
|
|
1030
|
-
// If unit is a single string, return only that unit
|
|
1031
|
-
if (typeof unit === 'string') {
|
|
1032
|
-
return { [unit]: fullObject[unit] ?? 0 };
|
|
1033
|
-
}
|
|
1034
|
-
// If unit is an array, return only those units
|
|
1035
|
-
const result = {};
|
|
1036
|
-
for (const u of unit) {
|
|
1037
|
-
result[u] = fullObject[u] ?? 0;
|
|
1078
|
+
else if (needsMilliseconds && result.milliseconds !== undefined) {
|
|
1079
|
+
// ms without µs: truncate fractional part
|
|
1080
|
+
result.milliseconds = Math.trunc(result.milliseconds);
|
|
1038
1081
|
}
|
|
1039
|
-
|
|
1082
|
+
// Return only the requested units
|
|
1083
|
+
if (unit === undefined)
|
|
1084
|
+
return result;
|
|
1085
|
+
if (typeof unit === 'string')
|
|
1086
|
+
return { [unit]: result[unit] ?? 0 };
|
|
1087
|
+
const filtered = {};
|
|
1088
|
+
for (const u of unit)
|
|
1089
|
+
filtered[u] = result[u] ?? 0;
|
|
1090
|
+
return filtered;
|
|
1040
1091
|
}
|
|
1041
1092
|
/**
|
|
1042
1093
|
* Returns the difference between this DateTime and now.
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
export default function isoTimeDecimalString(datetime, { nullIfZero }) {
|
|
1
|
+
export default function isoTimeDecimalString(datetime, { nullIfZero, truncateMicroseconds }) {
|
|
2
2
|
const milliseconds = datetime.millisecond;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
if (truncateMicroseconds) {
|
|
4
|
+
if (nullIfZero && milliseconds === 0)
|
|
5
|
+
return null;
|
|
6
|
+
return milliseconds.toString().padStart(3, '0');
|
|
7
|
+
}
|
|
8
|
+
const totalMicroseconds = milliseconds * 1000 + datetime.microsecond;
|
|
9
|
+
if (nullIfZero && totalMicroseconds === 0)
|
|
6
10
|
return null;
|
|
7
11
|
return totalMicroseconds.toString().padStart(6, '0');
|
|
8
12
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import isoTimeDecimalString from './isoTimeDecimalString.js';
|
|
2
2
|
export default function replaceISOMicroseconds(timeObj, isoString, opts) {
|
|
3
|
-
const decimalString = isoTimeDecimalString(timeObj, {
|
|
3
|
+
const decimalString = isoTimeDecimalString(timeObj, {
|
|
4
|
+
nullIfZero: opts?.suppressMilliseconds,
|
|
5
|
+
truncateMicroseconds: opts?.truncateMicroseconds,
|
|
6
|
+
});
|
|
4
7
|
if (decimalString === null)
|
|
5
8
|
return isoString;
|
|
6
9
|
// Match time in both ISO format (with T) and SQL format (with space)
|
|
@@ -107,6 +107,38 @@ export default class CalendarDate {
|
|
|
107
107
|
}
|
|
108
108
|
return new CalendarDate(dateTime);
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Create a CalendarDate from a custom format string.
|
|
112
|
+
* Uses Luxon format tokens (e.g., 'MM/dd/yyyy', 'MMMM dd, yyyy').
|
|
113
|
+
* @param text - The string to parse
|
|
114
|
+
* @param format - Format string using Luxon tokens
|
|
115
|
+
* @param options - Optional zone and locale options
|
|
116
|
+
* @returns A CalendarDate for the parsed date
|
|
117
|
+
* @throws {InvalidCalendarDate} When the string doesn't match the format or is invalid
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* CalendarDate.fromFormat('12/15/2017', 'MM/dd/yyyy')
|
|
121
|
+
* CalendarDate.fromFormat('May 25, 1982', 'MMMM dd, yyyy')
|
|
122
|
+
* CalendarDate.fromFormat('mai 25, 1982', 'MMMM dd, yyyy', { locale: 'fr' })
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
static fromFormat(text, format, { zone, locale } = {}) {
|
|
126
|
+
let dateTime;
|
|
127
|
+
try {
|
|
128
|
+
const opts = {};
|
|
129
|
+
if (zone)
|
|
130
|
+
opts.zone = zone;
|
|
131
|
+
if (locale)
|
|
132
|
+
opts.locale = locale;
|
|
133
|
+
dateTime = DateTime.fromFormat(text, format, opts);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (error instanceof Error)
|
|
137
|
+
throw new InvalidCalendarDate(error);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
return new CalendarDate(dateTime);
|
|
141
|
+
}
|
|
110
142
|
/**
|
|
111
143
|
* Create a CalendarDate from an object with date units.
|
|
112
144
|
* @param obj - Object with year, month, day properties
|
|
@@ -381,17 +381,20 @@ export class DateTime {
|
|
|
381
381
|
}
|
|
382
382
|
/**
|
|
383
383
|
* Create a DateTime from epoch milliseconds.
|
|
384
|
-
* @param
|
|
384
|
+
* @param millisecondInput - Unix timestamp in milliseconds (fractional part becomes microseconds)
|
|
385
385
|
* @param options - Optional zone/locale options
|
|
386
386
|
* @returns A DateTime for the given instant
|
|
387
387
|
* @example
|
|
388
388
|
* ```ts
|
|
389
389
|
* DateTime.fromMillis(1707234567890)
|
|
390
|
+
* DateTime.fromMillis(1707234567890.123) // .123 ms = 123 microseconds
|
|
390
391
|
* ```
|
|
391
392
|
*/
|
|
392
|
-
static fromMillis(
|
|
393
|
-
const
|
|
394
|
-
|
|
393
|
+
static fromMillis(millisecondInput, options) {
|
|
394
|
+
const { milliseconds, microseconds } = microsecondParts(millisecondInput * 1000, {
|
|
395
|
+
errorIfNegative: false,
|
|
396
|
+
});
|
|
397
|
+
return new DateTime(LuxonDateTime.fromMillis(milliseconds, options), microseconds);
|
|
395
398
|
}
|
|
396
399
|
/**
|
|
397
400
|
* Create a DateTime from epoch microseconds.
|
|
@@ -410,17 +413,22 @@ export class DateTime {
|
|
|
410
413
|
}
|
|
411
414
|
/**
|
|
412
415
|
* Create a DateTime from epoch seconds.
|
|
413
|
-
*
|
|
416
|
+
* Fractional seconds are converted to milliseconds and microseconds.
|
|
417
|
+
* @param seconds - Unix timestamp in seconds (fractional part becomes ms + µs)
|
|
414
418
|
* @param options - Optional zone/locale options
|
|
415
419
|
* @returns A DateTime for the given instant
|
|
416
420
|
* @example
|
|
417
421
|
* ```ts
|
|
418
422
|
* DateTime.fromSeconds(1707234567)
|
|
423
|
+
* DateTime.fromSeconds(1707234567.123456) // .123456 seconds = 123ms + 456µs
|
|
419
424
|
* ```
|
|
420
425
|
*/
|
|
421
426
|
static fromSeconds(seconds, options) {
|
|
422
|
-
|
|
423
|
-
|
|
427
|
+
// Convert seconds to microseconds to preserve full precision
|
|
428
|
+
const totalMicroseconds = seconds * 1_000_000;
|
|
429
|
+
const { milliseconds, microseconds } = microsecondParts(totalMicroseconds, { errorIfNegative: false });
|
|
430
|
+
const luxonDatetime = LuxonDateTime.fromMillis(milliseconds, options);
|
|
431
|
+
return new DateTime(luxonDatetime, microseconds);
|
|
424
432
|
}
|
|
425
433
|
/**
|
|
426
434
|
* Create a DateTime from an object with date/time units.
|
|
@@ -481,6 +489,46 @@ export class DateTime {
|
|
|
481
489
|
const luxonDatetime = wrapLuxonError(() => LuxonDateTime.fromSQL(textForLuxon, opts));
|
|
482
490
|
return new DateTime(luxonDatetime, microsecond);
|
|
483
491
|
}
|
|
492
|
+
/**
|
|
493
|
+
* Create a DateTime from a custom format string.
|
|
494
|
+
* Supports standard Luxon format tokens plus 'u' or 'SSSSSS' for microseconds (6 decimal places).
|
|
495
|
+
* @param text - The string to parse
|
|
496
|
+
* @param format - Format string using Luxon tokens (e.g., 'MM/dd/yyyy HH:mm:ss.u')
|
|
497
|
+
* @param opts - Optional parsing options (zone, locale, etc.)
|
|
498
|
+
* @returns A DateTime for the parsed instant
|
|
499
|
+
* @throws {InvalidDateTime} When the string doesn't match the format or is invalid
|
|
500
|
+
* @example
|
|
501
|
+
* ```ts
|
|
502
|
+
* DateTime.fromFormat('12/15/2017', 'MM/dd/yyyy')
|
|
503
|
+
* DateTime.fromFormat('12/15/2017 10:30:45', 'MM/dd/yyyy HH:mm:ss')
|
|
504
|
+
* DateTime.fromFormat('12/15/2017 10:30:45.123456', 'MM/dd/yyyy HH:mm:ss.u')
|
|
505
|
+
* DateTime.fromFormat('12/15/2017 10:30:45.123456', 'MM/dd/yyyy HH:mm:ss.SSSSSS')
|
|
506
|
+
* DateTime.fromFormat('mai 25, 1982', 'MMMM dd, yyyy', { locale: 'fr' })
|
|
507
|
+
* ```
|
|
508
|
+
*/
|
|
509
|
+
static fromFormat(text, format, opts) {
|
|
510
|
+
// Check if format includes microsecond token ('u' or 'SSSSSS')
|
|
511
|
+
const hasMicrosecondToken = format.includes('.u') || format.includes('.SSSSSS');
|
|
512
|
+
let microsecond = 0;
|
|
513
|
+
if (hasMicrosecondToken) {
|
|
514
|
+
// Extract microseconds from the text
|
|
515
|
+
const { microsecond: extractedMicrosecond } = parseFractionalPart(text);
|
|
516
|
+
microsecond = extractedMicrosecond;
|
|
517
|
+
// Replace microsecond token with millisecond token for Luxon
|
|
518
|
+
// 'u' -> 'SSS' (Luxon only supports milliseconds)
|
|
519
|
+
// 'SSSSSS' -> 'SSS'
|
|
520
|
+
const formatForLuxon = format.replace(/\.u\b/, '.SSS').replace(/\.SSSSSS\b/, '.SSS');
|
|
521
|
+
// Truncate fractional part to 3 digits for Luxon
|
|
522
|
+
const textForLuxon = toThreeDecimalFraction(text);
|
|
523
|
+
const luxonDatetime = wrapLuxonError(() => LuxonDateTime.fromFormat(textForLuxon, formatForLuxon, opts));
|
|
524
|
+
return new DateTime(luxonDatetime, microsecond);
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
// No microsecond token, use Luxon directly
|
|
528
|
+
const luxonDatetime = wrapLuxonError(() => LuxonDateTime.fromFormat(text, format, opts));
|
|
529
|
+
return new DateTime(luxonDatetime, 0);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
484
532
|
/**
|
|
485
533
|
* Returns an ISO 8601 string with 6 fractional second digits (milliseconds + microseconds).
|
|
486
534
|
* @param opts - Optional format options (includeOffset, suppressMilliseconds, etc.)
|
|
@@ -813,20 +861,38 @@ export class DateTime {
|
|
|
813
861
|
return luxonSeconds + additionalMicroseconds;
|
|
814
862
|
}
|
|
815
863
|
/**
|
|
816
|
-
* Returns the epoch time in seconds as an integer
|
|
817
|
-
* Truncates any fractional seconds, returning only the whole seconds portion.
|
|
818
|
-
* Equivalent to Math.floor(toSeconds()).
|
|
819
|
-
* @returns Unix timestamp in seconds (integer only, no fractional part)
|
|
864
|
+
* Returns the epoch time in seconds as an integer, truncating any fractional part.
|
|
820
865
|
* @example
|
|
821
866
|
* ```ts
|
|
822
|
-
* DateTime.
|
|
823
|
-
* DateTime.fromISO('2026-02-07T09:03:44.
|
|
824
|
-
* DateTime.fromISO('2026-02-07T09:03:44.999999Z').toUnixInteger() // 1770455024 (not rounded up)
|
|
867
|
+
* DateTime.fromISO('2026-02-07T09:03:44.123456Z').unixIntegerSeconds // 1770455024
|
|
868
|
+
* DateTime.fromISO('2026-02-07T09:03:44.999999Z').unixIntegerSeconds // 1770455024 (not rounded up)
|
|
825
869
|
* ```
|
|
826
870
|
*/
|
|
827
|
-
|
|
871
|
+
get unixIntegerSeconds() {
|
|
828
872
|
return Math.floor(this.toSeconds());
|
|
829
873
|
}
|
|
874
|
+
/**
|
|
875
|
+
* Returns the epoch time in milliseconds as an integer, truncating any fractional part.
|
|
876
|
+
* @example
|
|
877
|
+
* ```ts
|
|
878
|
+
* DateTime.fromISO('2026-02-07T09:03:44.123456Z').unixIntegerMilliseconds // 1770455024123
|
|
879
|
+
* DateTime.fromISO('2026-02-07T09:03:44.123999Z').unixIntegerMilliseconds // 1770455024123 (not rounded up)
|
|
880
|
+
* ```
|
|
881
|
+
*/
|
|
882
|
+
get unixIntegerMilliseconds() {
|
|
883
|
+
return Math.floor(this.toMillis());
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Returns the epoch time in microseconds as an integer.
|
|
887
|
+
* Equivalent to `toMicroseconds()` since microseconds are always whole numbers.
|
|
888
|
+
* @example
|
|
889
|
+
* ```ts
|
|
890
|
+
* DateTime.fromISO('2026-02-07T09:03:44.123456Z').unixIntegerMicroseconds // 1770455024123456
|
|
891
|
+
* ```
|
|
892
|
+
*/
|
|
893
|
+
get unixIntegerMicroseconds() {
|
|
894
|
+
return this.toMicroseconds();
|
|
895
|
+
}
|
|
830
896
|
/**
|
|
831
897
|
* Returns the earliest DateTime from the given arguments.
|
|
832
898
|
* @param dateTimes - DateTimes to compare
|
|
@@ -985,58 +1051,43 @@ export class DateTime {
|
|
|
985
1051
|
* ```
|
|
986
1052
|
*/
|
|
987
1053
|
diff(other, unit) {
|
|
988
|
-
|
|
989
|
-
const needsMicroseconds =
|
|
990
|
-
|
|
991
|
-
//
|
|
992
|
-
const
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
if (Array.isArray(unit)) {
|
|
997
|
-
const filtered = unit.filter(u => u !== 'microseconds');
|
|
998
|
-
luxonUnits = filtered.length > 0 ? filtered : undefined;
|
|
999
|
-
}
|
|
1000
|
-
else if (unit === 'microseconds') {
|
|
1001
|
-
luxonUnits = undefined;
|
|
1002
|
-
}
|
|
1003
|
-
// Get Luxon's diff (which handles all units except microseconds)
|
|
1004
|
-
const luxonDuration = this.luxonDatetime.diff(other.toLuxon(), luxonUnits);
|
|
1005
|
-
const fullObject = luxonDuration.toObject();
|
|
1006
|
-
// Calculate microsecond difference if needed
|
|
1007
|
-
if (needsMicroseconds || unit === undefined) {
|
|
1008
|
-
// When microseconds is the ONLY unit requested, return total microseconds
|
|
1054
|
+
const unitArray = unit === undefined ? undefined : typeof unit === 'string' ? [unit] : unit;
|
|
1055
|
+
const needsMicroseconds = !unitArray || unitArray.includes('microseconds');
|
|
1056
|
+
const needsMilliseconds = !unitArray || unitArray.includes('milliseconds');
|
|
1057
|
+
// Strip 'microseconds' before passing to Luxon (it doesn't support it)
|
|
1058
|
+
const luxonUnits = unitArray?.filter(u => u !== 'microseconds');
|
|
1059
|
+
const luxonDuration = this.luxonDatetime.diff(other.toLuxon(), luxonUnits && luxonUnits.length > 0 ? luxonUnits : undefined);
|
|
1060
|
+
const result = luxonDuration.toObject();
|
|
1061
|
+
if (needsMicroseconds) {
|
|
1009
1062
|
if (unit === 'microseconds') {
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
fullObject.microseconds = thisTotalMicroseconds - otherTotalMicroseconds;
|
|
1063
|
+
// Only microseconds requested: return total difference
|
|
1064
|
+
result.microseconds = this.toMicroseconds() - other.toMicroseconds();
|
|
1013
1065
|
}
|
|
1014
|
-
else {
|
|
1015
|
-
//
|
|
1016
|
-
|
|
1017
|
-
const
|
|
1018
|
-
|
|
1066
|
+
else if (needsMilliseconds && result.milliseconds !== undefined) {
|
|
1067
|
+
// Both ms + µs requested: combine Luxon's ms with µs field diff, then re-split.
|
|
1068
|
+
// Example: Luxon says -1ms, µs fields are 999-0=+999 → total=-1µs → 0ms, -1µs
|
|
1069
|
+
const totalMicroDiff = Math.round(result.milliseconds * 1000) + (this.microsecond - other.microsecond);
|
|
1070
|
+
result.milliseconds = Math.trunc(totalMicroDiff / 1000) || 0; // || 0 normalizes -0
|
|
1071
|
+
result.microseconds = totalMicroDiff - result.milliseconds * 1000;
|
|
1019
1072
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
fullObject.milliseconds = Math.trunc(fullObject.milliseconds);
|
|
1073
|
+
else {
|
|
1074
|
+
// µs without ms: just the field difference
|
|
1075
|
+
result.microseconds = this.microsecond - other.microsecond;
|
|
1024
1076
|
}
|
|
1025
1077
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
}
|
|
1030
|
-
// If unit is a single string, return only that unit
|
|
1031
|
-
if (typeof unit === 'string') {
|
|
1032
|
-
return { [unit]: fullObject[unit] ?? 0 };
|
|
1033
|
-
}
|
|
1034
|
-
// If unit is an array, return only those units
|
|
1035
|
-
const result = {};
|
|
1036
|
-
for (const u of unit) {
|
|
1037
|
-
result[u] = fullObject[u] ?? 0;
|
|
1078
|
+
else if (needsMilliseconds && result.milliseconds !== undefined) {
|
|
1079
|
+
// ms without µs: truncate fractional part
|
|
1080
|
+
result.milliseconds = Math.trunc(result.milliseconds);
|
|
1038
1081
|
}
|
|
1039
|
-
|
|
1082
|
+
// Return only the requested units
|
|
1083
|
+
if (unit === undefined)
|
|
1084
|
+
return result;
|
|
1085
|
+
if (typeof unit === 'string')
|
|
1086
|
+
return { [unit]: result[unit] ?? 0 };
|
|
1087
|
+
const filtered = {};
|
|
1088
|
+
for (const u of unit)
|
|
1089
|
+
filtered[u] = result[u] ?? 0;
|
|
1090
|
+
return filtered;
|
|
1040
1091
|
}
|
|
1041
1092
|
/**
|
|
1042
1093
|
* Returns the difference between this DateTime and now.
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
export default function isoTimeDecimalString(datetime, { nullIfZero }) {
|
|
1
|
+
export default function isoTimeDecimalString(datetime, { nullIfZero, truncateMicroseconds }) {
|
|
2
2
|
const milliseconds = datetime.millisecond;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
if (truncateMicroseconds) {
|
|
4
|
+
if (nullIfZero && milliseconds === 0)
|
|
5
|
+
return null;
|
|
6
|
+
return milliseconds.toString().padStart(3, '0');
|
|
7
|
+
}
|
|
8
|
+
const totalMicroseconds = milliseconds * 1000 + datetime.microsecond;
|
|
9
|
+
if (nullIfZero && totalMicroseconds === 0)
|
|
6
10
|
return null;
|
|
7
11
|
return totalMicroseconds.toString().padStart(6, '0');
|
|
8
12
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import isoTimeDecimalString from './isoTimeDecimalString.js';
|
|
2
2
|
export default function replaceISOMicroseconds(timeObj, isoString, opts) {
|
|
3
|
-
const decimalString = isoTimeDecimalString(timeObj, {
|
|
3
|
+
const decimalString = isoTimeDecimalString(timeObj, {
|
|
4
|
+
nullIfZero: opts?.suppressMilliseconds,
|
|
5
|
+
truncateMicroseconds: opts?.truncateMicroseconds,
|
|
6
|
+
});
|
|
4
7
|
if (decimalString === null)
|
|
5
8
|
return isoString;
|
|
6
9
|
// Match time in both ISO format (with T) and SQL format (with space)
|
|
@@ -34,11 +34,13 @@ export interface ToISOTimeOptions {
|
|
|
34
34
|
includeOffset?: boolean;
|
|
35
35
|
includePrefix?: boolean;
|
|
36
36
|
format?: 'basic' | 'extended';
|
|
37
|
+
truncateMicroseconds?: boolean;
|
|
37
38
|
}
|
|
38
39
|
export interface ToSQLOptions {
|
|
39
40
|
includeZone?: boolean;
|
|
40
41
|
includeOffset?: boolean;
|
|
41
42
|
includeOffsetSpace?: boolean;
|
|
43
|
+
truncateMicroseconds?: boolean;
|
|
42
44
|
}
|
|
43
45
|
export type DateTimeUnit = 'year' | 'quarter' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond';
|
|
44
46
|
/**
|
|
@@ -40,12 +40,14 @@ export interface ToISOTimeOptions {
|
|
|
40
40
|
includeOffset?: boolean
|
|
41
41
|
includePrefix?: boolean
|
|
42
42
|
format?: 'basic' | 'extended'
|
|
43
|
+
truncateMicroseconds?: boolean
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export interface ToSQLOptions {
|
|
46
47
|
includeZone?: boolean
|
|
47
48
|
includeOffset?: boolean
|
|
48
49
|
includeOffsetSpace?: boolean
|
|
50
|
+
truncateMicroseconds?: boolean
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
export type DateTimeUnit =
|