1414 * limitations under the License.
1515 */
1616
17- const FULL_ISO_REG = / \d { 4 } - [ 0 1 ] \d - [ 0 - 3 ] \d T [ 0 - 2 ] \d : [ 0 - 5 ] \d : [ 0 - 5 ] \d \. \d { 4 , 9 } Z / ;
17+ const FULL_ISO_REG = / \d { 4 } - [ 0 1 ] \d - [ 0 - 3 ] \d T [ 0 - 2 ] \d : [ 0 - 5 ] \d : [ 0 - 5 ] \d \. \d { 4 , 12 } Z / ;
1818const NO_BIG_INT =
1919 'BigInt only available in Node >= v10.7. Consider using getFullTimeString instead.' ;
2020
@@ -101,6 +101,7 @@ enum Sign {
101101export class PreciseDate extends Date {
102102 private _micros = 0 ;
103103 private _nanos = 0 ;
104+ private _picos = 0 ;
104105 constructor ( time ?: number | Date ) ;
105106 constructor ( preciseTime : string | bigint | DateTuple | ProtobufDate ) ;
106107 constructor (
@@ -113,13 +114,20 @@ export class PreciseDate extends Date {
113114 milliseconds ?: number ,
114115 microseconds ?: number ,
115116 nanoseconds ?: number ,
117+ picoseconds ?: number ,
116118 ) ;
117119 constructor (
118120 time ?: number | string | bigint | Date | DateTuple | ProtobufDate ,
119121 ) {
120122 super ( ) ;
121123
122124 if ( time && typeof time !== 'number' && ! ( time instanceof Date ) ) {
125+ if ( typeof time === 'string' && isFullISOString ( time ) ) {
126+ const pd = parseFullISO ( time as string ) ;
127+ this . setFullTime ( pd . getFullTimeString ( ) ) ;
128+ this . setPicoseconds ( pd . getPicoseconds ( ) ) ;
129+ return ;
130+ }
123131 this . setFullTime ( PreciseDate . parseFull ( time ) ) ;
124132 return ;
125133 }
@@ -128,12 +136,17 @@ export class PreciseDate extends Date {
128136 const args : number [ ] = Array . from ( arguments ) ;
129137 const dateFields = args . slice ( 0 , 7 ) as DateFields ;
130138 const date = new Date ( ...dateFields ) ;
139+ const picos = args . length === 10 ? args . pop ( ) ! : 0 ;
131140 const nanos = args . length === 9 ? args . pop ( ) ! : 0 ;
132141 const micros = args . length === 8 ? args . pop ( ) ! : 0 ;
133142
134143 this . setTime ( date . getTime ( ) ) ;
135144 this . setMicroseconds ( micros ) ;
136145 this . setNanoseconds ( nanos ) ;
146+
147+ if ( picos !== 0 ) {
148+ this . setPicoseconds ( picos ) ;
149+ }
137150 }
138151 /**
139152 * Returns the specified date represented in nanoseconds according to
@@ -210,6 +223,20 @@ export class PreciseDate extends Date {
210223 getNanoseconds ( ) : number {
211224 return this . _nanos ;
212225 }
226+ /**
227+ * Returns the picoseconds in the specified date according to universal time.
228+ *
229+ * @returns {number }
230+ *
231+ * @example
232+ * const date = new PreciseDate('2019-02-08T10:34:29.481145231123Z');
233+ *
234+ * console.log(date.getPicoseconds());
235+ * // expected output: 123
236+ */
237+ getPicoseconds ( ) : number {
238+ return this . _picos ;
239+ }
213240 /**
214241 * Sets the microseconds for a specified date according to universal time.
215242 *
@@ -277,6 +304,39 @@ export class PreciseDate extends Date {
277304
278305 return this . setMicroseconds ( micros ) ;
279306 }
307+ /**
308+ * Sets the picoseconds for a specified date according to universal time.
309+ *
310+ * @param {number } picoseconds A number representing the picoseconds.
311+ * @returns {string } Returns a string representing the nanoseconds in the
312+ * specified date according to universal time.
313+ *
314+ * @example
315+ * const date = new PreciseDate();
316+ *
317+ * date.setPicoseconds(123);
318+ *
319+ * console.log(date.getPicoseconds());
320+ * // expected output: 123
321+ */
322+ setPicoseconds ( picos : number ) : string {
323+ const abs = Math . abs ( picos ) ;
324+ let nanos = this . _nanos ;
325+
326+ if ( abs >= 1000 ) {
327+ nanos += Math . floor ( abs / 1000 ) * Math . sign ( picos ) ;
328+ picos %= 1000 ;
329+ }
330+
331+ if ( Math . sign ( picos ) === Sign . NEGATIVE ) {
332+ nanos -= 1 ;
333+ picos += 1000 ;
334+ }
335+
336+ this . _picos = picos ;
337+
338+ return this . setNanoseconds ( nanos ) ;
339+ }
280340 /**
281341 * Sets the PreciseDate object to the time represented by a number of
282342 * nanoseconds since January 1, 1970, 00:00:00 UTC.
@@ -327,6 +387,7 @@ export class PreciseDate extends Date {
327387 setTime ( time : number ) : number {
328388 this . _micros = 0 ;
329389 this . _nanos = 0 ;
390+ this . _picos = 0 ;
330391 return super . setTime ( time ) ;
331392 }
332393 /**
@@ -346,7 +407,15 @@ export class PreciseDate extends Date {
346407 toISOString ( ) : string {
347408 const micros = padLeft ( this . _micros , 3 ) ;
348409 const nanos = padLeft ( this . _nanos , 3 ) ;
349- return super . toISOString ( ) . replace ( / z $ / i, `${ micros } ${ nanos } Z` ) ;
410+ let picos = '' ;
411+
412+ if ( this . _picos > 0 ) {
413+ // only include picoseconds if they are non-zero to avoid
414+ // breaking existing consumers of this method.
415+ picos = padLeft ( this . _picos , 3 ) ;
416+ }
417+
418+ return super . toISOString ( ) . replace ( / z $ / i, `${ micros } ${ nanos } ${ picos } Z` ) ;
350419 }
351420 /**
352421 * Returns an object representing the specified date according to universal
@@ -464,7 +533,9 @@ export class PreciseDate extends Date {
464533 date . setTime ( seconds * 1000 ) ;
465534 date . setNanoseconds ( nanos ) ;
466535 } else if ( isFullISOString ( time ) ) {
467- date . setFullTime ( parseFullISO ( time as string ) ) ;
536+ const pd = parseFullISO ( time as string ) ;
537+ date . setFullTime ( pd . getFullTimeString ( ) ) ;
538+ date . setPicoseconds ( pd . getPicoseconds ( ) ) ;
468539 } else {
469540 date . setTime ( new Date ( time as string ) . getTime ( ) ) ;
470541 }
@@ -516,6 +587,10 @@ export class PreciseDate extends Date {
516587 const milliseconds = Date . UTC ( ...( args . slice ( 0 , 7 ) as DateFields ) ) ;
517588 const date = new PreciseDate ( milliseconds ) ;
518589
590+ if ( args . length === 10 ) {
591+ date . setPicoseconds ( args . pop ( ) ! ) ;
592+ }
593+
519594 if ( args . length === 9 ) {
520595 date . setNanoseconds ( args . pop ( ) ! ) ;
521596 }
@@ -530,25 +605,27 @@ export class PreciseDate extends Date {
530605
531606/**
532607 * Parses a RFC 3339 formatted string representation of the date, and returns
533- * a string representing the nanoseconds since January 1, 1970, 00:00:00 .
608+ * a { @link PreciseDate} object .
534609 *
535610 * @private
536611 *
537612 * @param {string } time The RFC 3339 formatted string.
538- * @returns {string }
613+ * @returns {PreciseDate }
539614 */
540- function parseFullISO ( time : string ) : string {
615+ function parseFullISO ( time : string ) : PreciseDate {
541616 let digits = '0' ;
542617
543618 time = time . replace ( / \. ( \d + ) / , ( $0 , $1 ) => {
544619 digits = $1 ;
545620 return '.000' ;
546621 } ) ;
547622
548- const nanos = Number ( padRight ( digits , 9 ) ) ;
623+ const picos = Number ( padRight ( digits , 12 ) ) ;
549624 const date = new PreciseDate ( time ) ;
550625
551- return date . setNanoseconds ( nanos ) ;
626+ date . setPicoseconds ( picos ) ;
627+
628+ return date ;
552629}
553630
554631/**
0 commit comments