@@ -248,33 +248,32 @@ FP_Quantity._yearMonthConversionFactor = {
248
248
} ;
249
249
250
250
/**
251
- * Defines a map from FHIRPath time units to UCUM.
251
+ * Defines a map from time units that are supported for arithmetic (including
252
+ * some UCUM time based units) to FHIRPath time units.
252
253
*/
253
- FP_Quantity . timeUnitsToUCUM = {
254
- 'years' : "'a'" ,
255
- 'months' : "'mo'" ,
256
- 'weeks' : "'wk'" ,
257
- 'days' : "'d'" ,
258
- 'hours' : "'h'" ,
259
- 'minutes' : "'min'" ,
260
- 'seconds' : "'s'" ,
261
- 'milliseconds' : "'ms'" ,
262
- 'year' : "'a'" ,
263
- 'month' : "'mo'" ,
264
- 'week' : "'wk'" ,
265
- 'day' : "'d'" ,
266
- 'hour' : "'h'" ,
267
- 'minute' : "'min'" ,
268
- 'second' : "'s'" ,
269
- 'millisecond' : "'ms'" ,
270
- "'a'" : "'a'" ,
271
- "'mo'" : "'mo'" ,
272
- "'wk'" : "'wk'" ,
273
- "'d'" : "'d'" ,
274
- "'h'" : "'h'" ,
275
- "'min'" : "'min'" ,
276
- "'s'" : "'s'" ,
277
- "'ms'" : "'ms'"
254
+ FP_Quantity . arithmeticDurationUnits = {
255
+ 'years' : "year" ,
256
+ 'months' : "month" ,
257
+ 'weeks' : "week" ,
258
+ 'days' : "day" ,
259
+ 'hours' : "hour" ,
260
+ 'minutes' : "minute" ,
261
+ 'seconds' : "second" ,
262
+ 'milliseconds' : "millisecond" ,
263
+ 'year' : "year" ,
264
+ 'month' : "month" ,
265
+ 'week' : "week" ,
266
+ 'day' : "day" ,
267
+ 'hour' : "hour" ,
268
+ 'minute' : "minute" ,
269
+ 'second' : "second" ,
270
+ 'millisecond' : "millisecond" ,
271
+ "'wk'" : "week" ,
272
+ "'d'" : "day" ,
273
+ "'h'" : "hour" ,
274
+ "'min'" : "minute" ,
275
+ "'s'" : "second" ,
276
+ "'ms'" : "millisecond"
278
277
} ;
279
278
280
279
/**
@@ -301,20 +300,6 @@ FP_Quantity.mapTimeUnitsToUCUMCode = Object.keys(FP_Quantity.mapUCUMCodeToTimeUn
301
300
return res ;
302
301
} , { } ) ;
303
302
304
- /**
305
- * A map of the UCUM units that must be paired with integer values when doing
306
- * arithmetic.
307
- */
308
- FP_Quantity . integerUnits = {
309
- "'a'" : true ,
310
- "'mo'" : true ,
311
- "'wk'" : true ,
312
- "'d'" : true ,
313
- "'h'" : true ,
314
- "'min'" : true
315
- } ;
316
-
317
-
318
303
class FP_TimeBase extends FP_Type {
319
304
constructor ( timeStr ) {
320
305
super ( ) ;
@@ -327,45 +312,46 @@ class FP_TimeBase extends FP_Type {
327
312
* FHIRPath specification for supported units.
328
313
*/
329
314
plus ( timeQuantity ) {
330
- var unit = timeQuantity . unit ;
331
- var ucumUnit = FP_Quantity . timeUnitsToUCUM [ unit ] ;
332
- if ( ! ucumUnit ) {
333
- throw new Error ( 'For date/time arithmetic, the unit of the quantity ' +
334
- 'must be a recognized time-based unit' ) ;
315
+ const unit = timeQuantity . unit ;
316
+ let timeUnit = FP_Quantity . arithmeticDurationUnits [ unit ] ;
317
+ if ( ! timeUnit ) {
318
+ throw new Error ( 'For date/time arithmetic, the unit of the quantity ' +
319
+ 'must be one of the following time-based units: ' +
320
+ Object . keys ( FP_Quantity . arithmeticDurationUnits ) ) ;
335
321
}
336
- var cls = this . constructor ;
337
- var unitPrecision = cls . _ucumToDatePrecision [ ucumUnit ] ;
322
+ const cls = this . constructor ;
323
+ const unitPrecision = cls . _timeUnitToDatePrecision [ timeUnit ] ;
338
324
if ( unitPrecision === undefined ) {
339
- throw new Error ( 'Unsupported unit for +. The unit should be one of ' +
340
- Object . keys ( cls . _ucumToDatePrecision ) . join ( ', ' ) + '.' ) ;
325
+ throw new Error ( 'Unsupported unit for +. The unit should be one of ' +
326
+ Object . keys ( cls . _timeUnitToDatePrecision ) . join ( ', ' ) + '.' ) ;
341
327
}
342
- var isIntUnit = FP_Quantity . integerUnits [ ucumUnit ] ;
343
- var qVal = timeQuantity . value ;
344
- if ( isIntUnit && ! Number . isInteger ( qVal ) ) {
345
- throw new Error ( 'When adding a quantity of unit ' + unit + ' to a date/time,' +
346
- ' the value must be an integer.' ) ;
328
+ let qVal = timeQuantity . value ;
329
+ const isTime = ( cls === FP_Time ) ;
330
+
331
+ // From the FHIRPath specification: "For precisions above seconds, the
332
+ // decimal portion of the time-valued quantity is ignored, since date/time
333
+ // arithmetic above seconds is performed with calendar duration semantics."
334
+ if ( isTime ? unitPrecision < 2 : unitPrecision < 5 ) {
335
+ qVal = Math . trunc ( qVal ) ;
347
336
}
348
337
349
338
// If the precision of the time quantity is higher than the precision of the
350
339
// date, we need to convert the time quantity to the precision of the date.
351
340
if ( this . _getPrecision ( ) < unitPrecision ) {
352
- var unquotedUnit = ucumUnit . slice ( 1 , ucumUnit . length - 1 ) ;
353
- var neededUnit = cls . _datePrecisionToUnquotedUcum [
341
+ const neededUnit = cls . _datePrecisionToTimeUnit [
354
342
this . _getPrecision ( ) ] ;
355
- var convResult = ucumUtils . convertUnitTo ( unquotedUnit , qVal , neededUnit ) ;
356
- if ( convResult . status != 'succeeded' ) {
357
- throw new Error ( convResult . msg . join ( "\n" ) ) ;
343
+ if ( neededUnit !== 'second' ) {
344
+ const newQuantity = FP_Quantity . convUnitTo ( timeUnit , qVal , neededUnit ) ;
345
+ timeUnit = newQuantity . unit ;
346
+ qVal = Math . trunc ( newQuantity . value ) ;
358
347
}
359
- ucumUnit = "'" + neededUnit + "'" ;
360
- qVal = Math . floor ( convResult . toVal ) ;
361
348
}
362
- var newDate = FP_TimeBase . timeUnitToAddFn [ ucumUnit ] ( this . _getDateObj ( ) , qVal ) ;
349
+ const newDate = FP_TimeBase . timeUnitToAddFn [ timeUnit ] ( this . _getDateObj ( ) , qVal ) ;
363
350
// newDate is a Date. We need to make a string with the correct precision.
364
- var isTime = ( cls === FP_Time ) ;
365
- var precision = this . _getPrecision ( ) ;
351
+ let precision = this . _getPrecision ( ) ;
366
352
if ( isTime )
367
353
precision += 3 ; // based on dateTimeRE, not timeRE
368
- var newDateStr = FP_DateTime . isoDateTime ( newDate , precision ) ;
354
+ let newDateStr = FP_DateTime . isoDateTime ( newDate , precision ) ;
369
355
if ( isTime ) {
370
356
// FP_Time just needs the time part of the string
371
357
newDateStr = newDateStr . slice ( newDateStr . indexOf ( 'T' ) + 1 ) ;
@@ -604,18 +590,18 @@ class FP_TimeBase extends FP_Type {
604
590
}
605
591
606
592
/**
607
- * A map from a UCUM time based unit to a function used to add that quantity to
608
- * a date/time.
593
+ * A map from a FHIRPath time units to a function used to add that
594
+ * quantity to a date/time.
609
595
*/
610
596
FP_TimeBase . timeUnitToAddFn = {
611
- "'a' " : require ( 'date-fns/add_years' ) ,
612
- "'mo' " : require ( 'date-fns/add_months' ) ,
613
- "'wk' " : require ( 'date-fns/add_weeks' ) ,
614
- "'d' " : require ( 'date-fns/add_days' ) ,
615
- "'h' " : require ( 'date-fns/add_hours' ) ,
616
- "'min' " : require ( 'date-fns/add_minutes' ) ,
617
- "'s' " : require ( 'date-fns/add_seconds' ) ,
618
- "'ms' " : require ( 'date-fns/add_milliseconds' )
597
+ "year " : require ( 'date-fns/add_years' ) ,
598
+ "month " : require ( 'date-fns/add_months' ) ,
599
+ "week " : require ( 'date-fns/add_weeks' ) ,
600
+ "day " : require ( 'date-fns/add_days' ) ,
601
+ "hour " : require ( 'date-fns/add_hours' ) ,
602
+ "minute " : require ( 'date-fns/add_minutes' ) ,
603
+ "second " : require ( 'date-fns/add_seconds' ) ,
604
+ "millisecond " : require ( 'date-fns/add_milliseconds' )
619
605
} ;
620
606
621
607
@@ -733,25 +719,25 @@ FP_DateTime.checkString = function(str) {
733
719
} ;
734
720
735
721
/**
736
- * A map from UCUM units (in quotation marks, which is the FHIRPath syntax for
737
- * UCUM) to the internal DateTime "precision" number.
722
+ * A map from FHIRPath time units to the internal DateTime "precision" number.
738
723
*/
739
- FP_DateTime . _ucumToDatePrecision = {
740
- "'a' " : 0 ,
741
- "'mo' " : 1 ,
742
- "'wk' " : 2 , // wk is just 7*d
743
- "'d' " : 2 ,
744
- "'h' " : 3 ,
745
- "'min' " : 4 ,
746
- "'s' " : 5 ,
747
- "'ms' " : 6
724
+ FP_DateTime . _timeUnitToDatePrecision = {
725
+ "year " : 0 ,
726
+ "month " : 1 ,
727
+ "week " : 2 , // wk is just 7*d
728
+ "day " : 2 ,
729
+ "hour " : 3 ,
730
+ "minute " : 4 ,
731
+ "second " : 5 ,
732
+ "millisecond " : 6
748
733
} ;
749
734
750
735
/**
751
- * The inverse of _ucumToDatePrecision, except with unquoted UCUM units .
736
+ * The inverse of _timeUnitToDatePrecision .
752
737
*/
753
- FP_DateTime . _datePrecisionToUnquotedUcum = [ "a" , "mo" , "d" , "h" , "min" , "s" ,
754
- "ms" ] ;
738
+ FP_DateTime . _datePrecisionToTimeUnit = [
739
+ "year" , "month" , "day" , "hour" , "minute" , "second" , "millisecond"
740
+ ] ;
755
741
756
742
757
743
@@ -857,20 +843,19 @@ FP_Time.checkString = function(str) {
857
843
} ;
858
844
859
845
/**
860
- * A map from UCUM units (in quotation marks, which is the FHIRPath syntax for
861
- * UCUM) to the internal DateTime "precision" number.
846
+ * A map from FHIRPath time units to the internal DateTime "precision" number.
862
847
*/
863
- FP_Time . _ucumToDatePrecision = {
864
- "'h' " : 0 ,
865
- "'min' " : 1 ,
866
- "'s' " : 2 ,
867
- "'ms' " : 3
848
+ FP_Time . _timeUnitToDatePrecision = {
849
+ "hour " : 0 ,
850
+ "minute " : 1 ,
851
+ "second " : 2 ,
852
+ "millisecond " : 3
868
853
} ;
869
854
870
855
/**
871
- * The inverse of _ucumToDatePrecision, except with unquoted UCUM units .
856
+ * The inverse of _timeUnitToDatePrecision .
872
857
*/
873
- FP_Time . _datePrecisionToUnquotedUcum = [ "h " , "min " , "s " , "ms " ] ;
858
+ FP_Time . _datePrecisionToTimeUnit = [ "hour " , "minute " , "second " , "millisecond " ] ;
874
859
875
860
876
861
/**
@@ -920,8 +905,8 @@ FP_DateTime.isoDateTime = function(date, precision) {
920
905
if ( precision > 3 ) {
921
906
rtn += ':' + formatNum ( date . getMinutes ( ) ) ;
922
907
if ( precision > 4 ) {
923
- rtn += ':' + formatNum ( date . getSeconds ( ) ) ;
924
- if ( precision > 5 )
908
+ rtn += ':' + formatNum ( date . getSeconds ( ) ) ;
909
+ if ( date . getMilliseconds ( ) )
925
910
rtn += '.' + formatNum ( date . getMilliseconds ( ) , 3 ) ;
926
911
}
927
912
}
0 commit comments