From b5f6ab34707b57767b54f55845ae97ebb77b248f Mon Sep 17 00:00:00 2001 From: Khushboo <68757952+desaikd@users.noreply.github.com> Date: Mon, 12 Apr 2021 09:05:11 -0700 Subject: [PATCH] added changes for creating Timestamp from date (#686) --- src/IonTimestamp.ts | 156 +++++++++++++++++++++++++++---------------- test/IonTimestamp.ts | 14 ++++ 2 files changed, 114 insertions(+), 56 deletions(-) diff --git a/src/IonTimestamp.ts b/src/IonTimestamp.ts index 76a16eb5..193cedfa 100644 --- a/src/IonTimestamp.ts +++ b/src/IonTimestamp.ts @@ -52,6 +52,12 @@ export class Timestamp { private _precision: TimestampPrecision; private readonly _secondsDecimal: Decimal; + /** Creates a new Ion Timestamp with millisecond precision from a JavaScript Date. + * + * @param date a valid JavaScript date object + */ + constructor(date: Date); + /** * Creates a new Timestamp, with precision determined by which parameters * are provided. If a parameter is not specified, it defaults to its lowest @@ -73,71 +79,110 @@ export class Timestamp { constructor( localOffset: number, year: number, + month?: number | null, + day?: number | null, + hour?: number | null, + minutes?: number | null, + seconds?: number | Decimal | null + ); + + constructor( + dateOrLocalOffset: number | Date | null = null, + year: number | null = null, month: number | null = null, day: number | null = null, hour: number | null = null, minutes: number | null = null, seconds: number | Decimal | null = null ) { - this._localOffset = localOffset; - this._year = year; - - this._precision = TimestampPrecision.YEAR; - this._checkRequiredField( - "Offset", - this._localOffset, - Timestamp._MIN_OFFSET, - Timestamp._MAX_OFFSET - ); - this._checkRequiredField( - "Year", - this._year, - Timestamp._MIN_YEAR, - Timestamp._MAX_YEAR - ); - this._month = this._checkOptionalField( - "Month", - month, - Timestamp._MIN_MONTH, - Timestamp._MAX_MONTH, - 1, - TimestampPrecision.MONTH - ); - this._day = this._checkOptionalField( - "Day", - day, - Timestamp._MIN_DAY, - Timestamp._MAX_DAY, - 1, - TimestampPrecision.DAY - ); - this._hour = this._checkOptionalField( - "Hour", - hour, - Timestamp._MIN_HOUR, - Timestamp._MAX_HOUR, - 0, - TimestampPrecision.HOUR_AND_MINUTE - ); - this._minutes = this._checkOptionalField( - "Minutes", - minutes, - Timestamp._MIN_MINUTE, - Timestamp._MAX_MINUTE, - 0, - TimestampPrecision.HOUR_AND_MINUTE - ); + if (dateOrLocalOffset instanceof Date) { + const date = dateOrLocalOffset; + const seconds = new Decimal( + // The coefficient is the total number of milliseconds as an integer + date.getSeconds() + date.getMilliseconds(), + // And the exponent is 0 to indicate the scale of that integer + 0 + ); + + this._localOffset = date.getTimezoneOffset() * -1; + this._year = date.getFullYear(); + this._month = date.getMonth() + 1; + this._day = date.getDate(); + this._hour = date.getHours(); + this._minutes = date.getMinutes(); + this._secondsDecimal = seconds; + this._precision = TimestampPrecision.YEAR; + } else { + const localOffset = dateOrLocalOffset; - if (typeof seconds === "number") { - if (!Number.isInteger(seconds)) { + if (localOffset === null) { throw new Error( - "The provided seconds number was not an integer (" + seconds + ")" + "Timestamp's constructor was called without localOffset" ); + } else if (year === null) { + throw new Error("Timestamp's constructor was called without year"); + } else { + this._localOffset = localOffset; + this._year = year; } - this._secondsDecimal = new Decimal(seconds, 0); - } else { - if (seconds !== null) { - this._secondsDecimal = seconds; + + this._precision = TimestampPrecision.YEAR; + this._checkRequiredField( + "Offset", + this._localOffset, + Timestamp._MIN_OFFSET, + Timestamp._MAX_OFFSET + ); + this._checkRequiredField( + "Year", + this._year, + Timestamp._MIN_YEAR, + Timestamp._MAX_YEAR + ); + this._month = this._checkOptionalField( + "Month", + month, + Timestamp._MIN_MONTH, + Timestamp._MAX_MONTH, + 1, + TimestampPrecision.MONTH + ); + this._day = this._checkOptionalField( + "Day", + day, + Timestamp._MIN_DAY, + Timestamp._MAX_DAY, + 1, + TimestampPrecision.DAY + ); + this._hour = this._checkOptionalField( + "Hour", + hour, + Timestamp._MIN_HOUR, + Timestamp._MAX_HOUR, + 0, + TimestampPrecision.HOUR_AND_MINUTE + ); + this._minutes = this._checkOptionalField( + "Minutes", + minutes, + Timestamp._MIN_MINUTE, + Timestamp._MAX_MINUTE, + 0, + TimestampPrecision.HOUR_AND_MINUTE + ); + + if (typeof seconds === "number") { + if (!Number.isInteger(seconds)) { + throw new Error( + "The provided seconds number was not an integer (" + seconds + ")" + ); + } + this._secondsDecimal = new Decimal(seconds, 0); + } else { + if (seconds !== null) { + this._secondsDecimal = seconds; + } } } if (this._secondsDecimal === null || this._secondsDecimal === undefined) { @@ -184,7 +229,6 @@ export class Timestamp { Timestamp._MAX_YEAR ); } - /** * Parses a string and returns a corresponding Timestamp object. * The provided string must be a text-encoded Timestamp as specified diff --git a/test/IonTimestamp.ts b/test/IonTimestamp.ts index 56a43aa2..e94a700b 100644 --- a/test/IonTimestamp.ts +++ b/test/IonTimestamp.ts @@ -242,4 +242,18 @@ describe("Timestamp", () => { assert.deepEqual(ts.getSecondsDecimal(), ion.Decimal.parse('45')); assert.deepEqual(ts._getFractionalSeconds(), ion.Decimal.ZERO); }); + it('constructor with Date', () => { + const date = new Date(2000, 0, 1, 12, 30, 45); + let timestamp1 = new ion.Timestamp(date.getTimezoneOffset() * -1, 2000, 1, 1, 12, 30, 45); + let timestamp2 = new ion.Timestamp(date); + assert.isTrue(timestamp1!.equals(timestamp2!)); + + const date2 = new Date(2000, 0, 1, 12, 30, 20, 20); + let timestamp3 = new ion.Timestamp(date2.getTimezoneOffset() * -1, 2000, 1, 1, 12, 30, new ion.Decimal( + 40, + 0 + )); + let timestamp4 = new ion.Timestamp(date2); + assert.isTrue(timestamp3!.equals(timestamp4!)); + }); }); \ No newline at end of file