@@ -16,9 +16,10 @@ const time = require('@js-joda/core');
16
16
17
17
const log = require ( './log' ) ( 'time' ) ;
18
18
const osgi = require ( './osgi' ) ;
19
- const { _isItem, _isZonedDateTime, _isDuration, _isQuantity } = require ( './helpers' ) ;
19
+ const { _isItem, _isZonedDateTime, _isInstant , _isDuration, _isQuantity } = require ( './helpers' ) ;
20
20
21
21
const javaZDT = Java . type ( 'java.time.ZonedDateTime' ) ;
22
+ const javaInstant = Java . type ( 'java.time.Instant' ) ;
22
23
const javaDuration = Java . type ( 'java.time.Duration' ) ;
23
24
const javaString = Java . type ( 'java.lang.String' ) ;
24
25
const javaNumber = Java . type ( 'java.lang.Number' ) ;
@@ -41,28 +42,30 @@ time.ZonedDateTime.prototype.parse = function (text, formatter = rfcFormatter) {
41
42
} ;
42
43
43
44
/**
44
- * Adds millis to the passed in ZDT as milliseconds. The millis is rounded first.
45
+ * Adds millis to the passed in Temporal as milliseconds. The millis are rounded first.
45
46
* If millis is negative they will be subtracted.
46
47
* @private
48
+ * @param {time.Temporal } temporal temporal to add milleseconds to
47
49
* @param {number|bigint } millis number of milliseconds to add
48
50
*/
49
- function _addMillisToNow ( millis ) {
50
- return time . ZonedDateTime . now ( ) . plus ( Math . round ( millis ) , time . ChronoUnit . MILLIS ) ;
51
+ function _addMillis ( temporal , millis ) {
52
+ return temporal . plus ( Math . round ( millis ) , time . ChronoUnit . MILLIS ) ;
51
53
}
52
54
53
55
/**
54
- * Adds the passed in QuantityType<Time> to now .
56
+ * Adds the passed in QuantityType<Time> to the passed Temporal .
55
57
* @private
58
+ * @param {time.Temporal } temporal temporal to add seconds to
56
59
* @param {QuantityType } quantityType an Item's QuantityType
57
60
* @returns now plus the time length in the quantityType
58
61
* @throws error when the units for the quantity type are not one of the Time units
59
62
*/
60
- function _addQuantityType ( quantityType ) {
63
+ function _addQuantityType ( temporal , quantityType ) {
61
64
const secs = quantityType . toUnit ( 's' ) ;
62
65
if ( secs ) {
63
- return time . ZonedDateTime . now ( ) . plusSeconds ( secs . doubleValue ( ) ) ;
66
+ return temporal . plus ( secs . doubleValue ( ) , time . ChronoUnit . SECONDS ) ;
64
67
} else {
65
- throw Error ( 'Only Time units are supported to convert QuantityTypes to a ZonedDateTime : ' + quantityType . toString ( ) ) ;
68
+ throw Error ( 'Only Time units are supported to add QuantityTypes to a Temporal : ' + quantityType . toString ( ) ) ;
66
69
}
67
70
}
68
71
@@ -180,20 +183,41 @@ function _parseString (str) {
180
183
* @returns {time.ZonedDateTime }
181
184
* @throws error if the Item's state is not supported or the Item itself is not supported
182
185
*/
183
- function _convertItemRawState ( rawState ) {
186
+ function _convertItemRawStateToZonedDateTime ( rawState ) {
184
187
if ( rawState instanceof DecimalType ) { // Number type Items
185
- return _addMillisToNow ( rawState . floatValue ( ) ) ;
188
+ return _addMillis ( time . ZonedDateTime . now ( ) , rawState . floatValue ( ) ) ;
186
189
} else if ( rawState instanceof StringType ) { // String type Items
187
190
return _parseString ( rawState . toString ( ) ) ;
188
191
} else if ( rawState instanceof DateTimeType ) { // DateTime Items
189
192
return javaInstantToJsInstant ( rawState . getInstant ( ) ) . atZone ( time . ZoneId . systemDefault ( ) ) ;
190
193
} else if ( rawState instanceof QuantityType ) { // Number:Time type Items
191
- return _addQuantityType ( rawState ) ;
194
+ return _addQuantityType ( time . ZonedDateTime . now ( ) , rawState ) ;
192
195
} else {
193
196
throw Error ( rawState . toString ( ) + ' is not supported for conversion to time.ZonedDateTime' ) ;
194
197
}
195
198
}
196
199
200
+ /**
201
+ * Converts the state of the passed in Item to a time.Instant
202
+ * @private
203
+ * @param {HostState } rawState
204
+ * @returns {time.Instant }
205
+ * @throws error if the Item's state is not supported or the Item itself is not supported
206
+ */
207
+ function _convertItemRawStateToInstant ( rawState ) {
208
+ if ( rawState instanceof DecimalType ) { // Number type Items
209
+ return _addMillis ( time . Instant . now ( ) , rawState . floatValue ( ) ) ;
210
+ } else if ( rawState instanceof StringType ) { // String type Items
211
+ return time . Instant . parse ( rawState . toString ( ) ) ;
212
+ } else if ( rawState instanceof DateTimeType ) { // DateTime Items
213
+ return javaInstantToJsInstant ( rawState . getInstant ( ) ) ;
214
+ } else if ( rawState instanceof QuantityType ) { // Number:Time type Items
215
+ return _addQuantityType ( time . Instant . now ( ) , rawState ) ;
216
+ } else {
217
+ throw Error ( rawState . toString ( ) + ' is not supported for conversion to time.Instant' ) ;
218
+ }
219
+ }
220
+
197
221
/**
198
222
* Convert Java Instant to JS-Joda Instant.
199
223
*
@@ -255,7 +279,7 @@ function toZDT (when) {
255
279
}
256
280
// Convert Java ZonedDateTime
257
281
if ( when instanceof javaZDT ) {
258
- log . debug ( 'toZTD : Converting Java ZonedDateTime ' + when . toString ( ) ) ;
282
+ log . debug ( 'toZDT : Converting Java ZonedDateTime ' + when . toString ( ) ) ;
259
283
return javaZDTToJsZDT ( when ) ;
260
284
}
261
285
@@ -282,10 +306,10 @@ function toZDT (when) {
282
306
// Add JavaScript's number or JavaScript BigInt or Java Number or Java DecimalType as milliseconds to now
283
307
if ( typeof when === 'number' || typeof when === 'bigint' ) {
284
308
log . debug ( 'toZDT: Adding milliseconds ' + when + ' to now' ) ;
285
- return _addMillisToNow ( when ) ;
309
+ return _addMillis ( time . ZonedDateTime . now ( ) , when ) ;
286
310
} else if ( when instanceof javaNumber || when instanceof DecimalType ) {
287
311
log . debug ( 'toZDT: Adding Java number or DecimalType ' + when . floatValue ( ) + ' to now' ) ;
288
- return _addMillisToNow ( when . floatValue ( ) ) ;
312
+ return _addMillis ( time . ZonedDateTime . now ( ) , when . floatValue ( ) ) ;
289
313
}
290
314
291
315
// DateTimeType, extract the javaInstant and convert to time.ZDT, use the configured timezone
@@ -297,10 +321,10 @@ function toZDT (when) {
297
321
// Add Quantity or QuantityType<Time> to now
298
322
if ( _isQuantity ( when ) ) {
299
323
log . debug ( 'toZDT: Adding Quantity ' + when + ' to now' ) ;
300
- return _addQuantityType ( when . rawQtyType ) ;
324
+ return _addQuantityType ( time . ZonedDateTime . now ( ) , when . rawQtyType ) ;
301
325
} else if ( when instanceof QuantityType ) {
302
326
log . debug ( 'toZDT: Adding QuantityType ' + when + ' to now' ) ;
303
- return _addQuantityType ( when ) ;
327
+ return _addQuantityType ( time . ZonedDateTime . now ( ) , when ) ;
304
328
}
305
329
306
330
// Convert items.Item or raw Item
@@ -309,10 +333,10 @@ function toZDT (when) {
309
333
if ( when . isUninitialized ) {
310
334
throw Error ( 'Item ' + when . name + ' is NULL or UNDEF, cannot convert to a time.ZonedDateTime' ) ;
311
335
}
312
- return _convertItemRawState ( when . rawState ) ;
336
+ return _convertItemRawStateToZonedDateTime ( when . rawState ) ;
313
337
} else if ( when instanceof ohItem ) {
314
338
log . debug ( 'toZDT: Converting raw Item ' + when ) ;
315
- return _convertItemRawState ( when . getState ( ) ) ;
339
+ return _convertItemRawStateToZonedDateTime ( when . getState ( ) ) ;
316
340
}
317
341
318
342
// Unsupported
@@ -331,6 +355,95 @@ time.ZonedDateTime.prototype.toToday = function () {
331
355
. withDayOfMonth ( now . dayOfMonth ( ) ) ;
332
356
} ;
333
357
358
+ /**
359
+ * Converts the passed in when to a time.Instant based on the following
360
+ * set of rules.
361
+ *
362
+ * - null, undefined: time.Instant.now()
363
+ * - time.Instant: unmodified
364
+ * - time.ZonedDateTime: converted to the time.Instant equivalent
365
+ * - Java Instant, DateTimeType: converted to time.Instant equivalent
366
+ * - JavaScript native {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date Date}: converted to a `time.Instant`
367
+ * - Item: converts the state of the Item based on the *Type rules described here
368
+ * - String, Java String, StringType: parsed ISO Instant
369
+ * - RFC (output from a Java Instant.toString()): parsed to time.ZonedDateTime
370
+ * @memberof time
371
+ * @param {* } [when] any of the types discussed above
372
+ * @returns {time.Instant }
373
+ * @throws error if the type, format, or contents of when are not supported
374
+ */
375
+ function toInstant ( when ) {
376
+ // If when is not supplied or null, return now
377
+ if ( when === undefined || when === null ) {
378
+ log . debug ( 'toInstant: Returning Instant.now()' ) ;
379
+ return time . Instant . now ( ) ;
380
+ }
381
+
382
+ // Pass through if already a time.Instant
383
+ if ( _isInstant ( when ) ) {
384
+ log . debug ( 'toInstant: Passing trough ' + when ) ;
385
+ return when ;
386
+ }
387
+
388
+ // Convert time.ZonedDateTime
389
+ if ( _isZonedDateTime ( when ) ) {
390
+ log . debug ( 'toInstant: Converting time.ZonedDateTime ' + when . toString ( ) ) ;
391
+ return when . toInstant ( ) ;
392
+ }
393
+
394
+ // Convert Java Instant
395
+ if ( when instanceof javaInstant ) {
396
+ log . debug ( 'toInstant: Converting Java Instant ' + when . toString ( ) ) ;
397
+ return javaInstantToJsInstant ( when ) ;
398
+ }
399
+
400
+ // String or StringType
401
+ if ( typeof when === 'string' || when instanceof javaString || when instanceof StringType ) {
402
+ log . debug ( 'toInstant: Parsing string ' + when ) ;
403
+ return time . Instant . parse ( when . toString ( ) ) ;
404
+ }
405
+
406
+ // JavaScript Native Date
407
+ if ( when instanceof Date ) {
408
+ log . debug ( 'toInstant: Converting JS native Date ' + when ) ;
409
+ const native = time . nativeJs ( when ) ;
410
+ return time . Instant . from ( native ) ;
411
+ }
412
+
413
+ // DateTimeType, extract the javaInstant and convert to time.Instant
414
+ if ( when instanceof DateTimeType ) {
415
+ log . debug ( 'toInstant: Converting DateTimeType ' + when ) ;
416
+ return javaInstantToJsInstant ( when . getInstant ( ) ) ;
417
+ }
418
+
419
+ // Convert items.Item or raw Item
420
+ if ( _isItem ( when ) ) {
421
+ log . debug ( 'toInstant: Converting Item ' + when ) ;
422
+ if ( when . isUninitialized ) {
423
+ throw Error ( 'Item ' + when . name + ' is NULL or UNDEF, cannot convert to a time.Instant' ) ;
424
+ }
425
+ return _convertItemRawStateToInstant ( when . rawState ) ;
426
+ } else if ( when instanceof ohItem ) {
427
+ log . debug ( 'toInstant: Converting raw Item ' + when ) ;
428
+ return _convertItemRawStateToInstant ( when . getState ( ) ) ;
429
+ }
430
+
431
+ // Unsupported
432
+ throw Error ( '"' + when + '" is an unsupported type for conversion to time.Instant' ) ;
433
+ }
434
+
435
+ /**
436
+ * Moves the date portion of the date time to today, accounting for DST
437
+ *
438
+ * @returns {time.ZonedDateTime } a new {@link time.ZonedDateTime} with today's date
439
+ */
440
+ time . ZonedDateTime . prototype . toToday = function ( ) {
441
+ const now = time . ZonedDateTime . now ( ) ;
442
+ return this . withYear ( now . year ( ) )
443
+ . withMonth ( now . month ( ) )
444
+ . withDayOfMonth ( now . dayOfMonth ( ) ) ;
445
+ } ;
446
+
334
447
/**
335
448
* Tests whether `this` time.ZonedDateTime is before the passed in timestamp.
336
449
* However, the function only compares the time portion of both, ignoring the date portion.
@@ -497,6 +610,7 @@ module.exports = {
497
610
javaInstantToJsInstant,
498
611
javaZDTToJsZDT,
499
612
toZDT,
613
+ toInstant,
500
614
_parseString,
501
615
_parseISO8601
502
616
} ;
0 commit comments