Skip to content

Commit c45a6b9

Browse files
authored
Add method for convert driver temporal types to Javascript Date (#842)
The conversion between date types in the javascript driver can be a bit convoluted and have to do conversions like `new Date(driverDate.toString())` doesn't help. This change introduces the method `toStandardDate` to `Date`, `DateTime` and `LocalDateTime` which could avoid the repeating conversion boilerplate in the developer code.
1 parent 34b4750 commit c45a6b9

File tree

3 files changed

+170
-0
lines changed

3 files changed

+170
-0
lines changed

packages/core/src/internal/temporal-util.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,16 @@ export function dateToIsoString (
303303
return `${yearString}-${monthString}-${dayString}`
304304
}
305305

306+
/**
307+
* Convert the given iso date string to a JavaScript Date object
308+
*
309+
* @param {string} isoString The iso date string
310+
* @returns {Date} the date
311+
*/
312+
export function isoStringToStandardDate(isoString: string): Date {
313+
return new Date(isoString)
314+
}
315+
306316
/**
307317
* Get the total number of nanoseconds from the milliseconds of the given standard JavaScript date and optional nanosecond part.
308318
* @param {global.Date} standardDate the standard JavaScript date.

packages/core/src/temporal-types.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,18 @@ export class Date<T extends NumberOrInteger = Integer> {
368368
)
369369
}
370370

371+
/**
372+
* Convert date to standard JavaScript `Date`.
373+
*
374+
* The time component of the returned `Date` is set to midnight
375+
* and the time zone is set to UTC.
376+
*
377+
* @returns {StandardDate} Standard JavaScript `Date` at `00:00:00.000` UTC.
378+
*/
379+
toStandardDate(): StandardDate {
380+
return util.isoStringToStandardDate(this.toString())
381+
}
382+
371383
/**
372384
* @ignore
373385
*/
@@ -484,6 +496,15 @@ export class LocalDateTime<T extends NumberOrInteger = Integer> {
484496
)
485497
}
486498

499+
/**
500+
* Convert date to standard JavaScript `Date`.
501+
*
502+
* @returns {StandardDate} Standard JavaScript `Date` at the local timezone
503+
*/
504+
toStandardDate(): StandardDate {
505+
return util.isoStringToStandardDate(this.toString())
506+
}
507+
487508
/**
488509
* @ignore
489510
*/
@@ -639,6 +660,19 @@ export class DateTime<T extends NumberOrInteger = Integer> {
639660
)
640661
}
641662

663+
/**
664+
* Convert date to standard JavaScript `Date`.
665+
*
666+
* @returns {StandardDate} Standard JavaScript `Date` at the defined time zone offset
667+
* @throws {Error} If the time zone offset is not defined in the object.
668+
*/
669+
toStandardDate(): StandardDate {
670+
if (this.timeZoneOffsetSeconds === undefined) {
671+
throw new Error('Requires DateTime created with time zone offset')
672+
}
673+
return util.isoStringToStandardDate(this.toString())
674+
}
675+
642676
/**
643677
* @ignore
644678
*/
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/**
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import { StandardDate } from '../src/graph-types'
21+
import { LocalDateTime, Date, DateTime } from '../src/temporal-types'
22+
23+
describe('Date', () => {
24+
describe('.toStandardDate()', () => {
25+
it('should convert to a standard date', () => {
26+
const localDatetime = new Date(2020, 3, 2)
27+
28+
const standardDate = localDatetime.toStandardDate()
29+
30+
expect(standardDate.getFullYear()).toEqual(localDatetime.year)
31+
expect(standardDate.getMonth()).toEqual(localDatetime.month - 1)
32+
expect(standardDate.getDate()).toEqual(localDatetime.day)
33+
})
34+
35+
it('should be the reverse operation of fromStandardDate but losing time information', () => {
36+
const standardDate = new global.Date()
37+
38+
const date = Date.fromStandardDate(standardDate)
39+
const receivedDate = date.toStandardDate()
40+
41+
// Setting 00:00:00:000 UTC
42+
standardDate.setHours(0, -1 * standardDate.getTimezoneOffset(), 0, 0)
43+
44+
expect(receivedDate).toEqual(standardDate)
45+
})
46+
})
47+
})
48+
49+
describe('LocalDateTime', () => {
50+
describe('.toStandardDate()', () => {
51+
it('should convert to a standard date', () => {
52+
const localDatetime = new LocalDateTime(2020, 12, 15, 1, 2, 3, 4000000)
53+
54+
const standardDate = localDatetime.toStandardDate()
55+
56+
expect(standardDate.getFullYear()).toEqual(localDatetime.year)
57+
expect(standardDate.getMonth()).toEqual(localDatetime.month - 1)
58+
expect(standardDate.getDate()).toEqual(localDatetime.day)
59+
expect(standardDate.getHours()).toBe(localDatetime.hour)
60+
expect(standardDate.getMinutes()).toBe(localDatetime.minute)
61+
expect(standardDate.getSeconds()).toBe(localDatetime.second)
62+
expect(standardDate.getMilliseconds()).toBe(localDatetime.nanosecond / 1000000)
63+
})
64+
65+
it('should be the reverse operation of fromStandardDate', () => {
66+
const date = new global.Date()
67+
68+
const localDatetime = LocalDateTime.fromStandardDate(date)
69+
const receivedDate = localDatetime.toStandardDate()
70+
71+
expect(receivedDate).toEqual(date)
72+
})
73+
})
74+
})
75+
76+
describe('DateTime', () => {
77+
describe('.toStandardDate()', () => {
78+
it('should convert to a standard date (offset)', () => {
79+
const datetime = new DateTime(2020, 12, 15, 12, 2, 3, 4000000, 120 * 60)
80+
81+
const standardDate = datetime.toStandardDate()
82+
83+
84+
expect(standardDate.getFullYear()).toEqual(datetime.year)
85+
expect(standardDate.getMonth()).toEqual(datetime.month - 1)
86+
expect(standardDate.getDate()).toEqual(datetime.day)
87+
const offsetInMinutes = offset(standardDate)
88+
const offsetAdjust = offsetInMinutes - datetime.timeZoneOffsetSeconds!! / 60
89+
const hourDiff = Math.abs(offsetAdjust / 60)
90+
const minuteDiff = Math.abs(offsetAdjust % 60)
91+
expect(standardDate.getHours()).toBe(datetime.hour - hourDiff)
92+
expect(standardDate.getMinutes()).toBe(datetime.minute - minuteDiff)
93+
expect(standardDate.getSeconds()).toBe(datetime.second)
94+
expect(standardDate.getMilliseconds()).toBe(datetime.nanosecond / 1000000)
95+
})
96+
97+
it('should not convert to a standard date (zoneid)', () => {
98+
const datetime = new DateTime(2020, 12, 15, 12, 2, 3, 4000000, undefined, 'Europe/Stockholm')
99+
100+
expect(() => datetime.toStandardDate())
101+
.toThrow(new Error('Requires DateTime created with time zone offset'))
102+
103+
})
104+
105+
it('should be the reverse operation of fromStandardDate', () => {
106+
const date = new global.Date()
107+
108+
const datetime = DateTime.fromStandardDate(date)
109+
const receivedDate = datetime.toStandardDate()
110+
111+
expect(receivedDate).toEqual(date)
112+
})
113+
})
114+
})
115+
116+
/**
117+
* The offset in StandardDate is the number of minutes
118+
* to sum to the date and time to get the UTC time.
119+
*
120+
* This function change the sign of the offset,
121+
* this way using the most common meaning.
122+
* The time to add to UTC to get the local time.
123+
*/
124+
function offset(date: StandardDate): number {
125+
return date.getTimezoneOffset() * -1
126+
}

0 commit comments

Comments
 (0)