Skip to content

Add method for convert driver temporal types to Javascript Date #842

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/core/src/internal/temporal-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,16 @@ export function dateToIsoString (
return `${yearString}-${monthString}-${dayString}`
}

/**
* Convert the given iso date string to a JavaScript Date object
*
* @param {string} isoString The iso date string
* @returns {Date} the date
*/
export function isoStringToStandardDate(isoString: string): Date {
return new Date(isoString)
}

/**
* Get the total number of nanoseconds from the milliseconds of the given standard JavaScript date and optional nanosecond part.
* @param {global.Date} standardDate the standard JavaScript date.
Expand Down
34 changes: 34 additions & 0 deletions packages/core/src/temporal-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,18 @@ export class Date<T extends NumberOrInteger = Integer> {
)
}

/**
* Convert date to standard JavaScript `Date`.
*
* The time component of the returned `Date` is set to midnight
* and the time zone is set to UTC.
*
* @returns {StandardDate} Standard JavaScript `Date` at `00:00:00.000` UTC.
*/
toStandardDate(): StandardDate {
return util.isoStringToStandardDate(this.toString())
}

/**
* @ignore
*/
Expand Down Expand Up @@ -484,6 +496,15 @@ export class LocalDateTime<T extends NumberOrInteger = Integer> {
)
}

/**
* Convert date to standard JavaScript `Date`.
*
* @returns {StandardDate} Standard JavaScript `Date` at the local timezone
*/
toStandardDate(): StandardDate {
return util.isoStringToStandardDate(this.toString())
}

/**
* @ignore
*/
Expand Down Expand Up @@ -639,6 +660,19 @@ export class DateTime<T extends NumberOrInteger = Integer> {
)
}

/**
* Convert date to standard JavaScript `Date`.
*
* @returns {StandardDate} Standard JavaScript `Date` at the defined time zone offset
* @throws {Error} If the time zone offset is not defined in the object.
*/
toStandardDate(): StandardDate {
if (this.timeZoneOffsetSeconds === undefined) {
throw new Error('Requires DateTime created with time zone offset')
}
return util.isoStringToStandardDate(this.toString())
}

/**
* @ignore
*/
Expand Down
126 changes: 126 additions & 0 deletions packages/core/test/temporal-types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/**
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { StandardDate } from '../src/graph-types'
import { LocalDateTime, Date, DateTime } from '../src/temporal-types'

describe('Date', () => {
describe('.toStandardDate()', () => {
it('should convert to a standard date', () => {
const localDatetime = new Date(2020, 3, 2)

const standardDate = localDatetime.toStandardDate()

expect(standardDate.getFullYear()).toEqual(localDatetime.year)
expect(standardDate.getMonth()).toEqual(localDatetime.month - 1)
expect(standardDate.getDate()).toEqual(localDatetime.day)
})

it('should be the reverse operation of fromStandardDate but losing time information', () => {
const standardDate = new global.Date()

const date = Date.fromStandardDate(standardDate)
const receivedDate = date.toStandardDate()

// Setting 00:00:00:000 UTC
standardDate.setHours(0, -1 * standardDate.getTimezoneOffset(), 0, 0)

expect(receivedDate).toEqual(standardDate)
})
})
})

describe('LocalDateTime', () => {
describe('.toStandardDate()', () => {
it('should convert to a standard date', () => {
const localDatetime = new LocalDateTime(2020, 12, 15, 1, 2, 3, 4000000)

const standardDate = localDatetime.toStandardDate()

expect(standardDate.getFullYear()).toEqual(localDatetime.year)
expect(standardDate.getMonth()).toEqual(localDatetime.month - 1)
expect(standardDate.getDate()).toEqual(localDatetime.day)
expect(standardDate.getHours()).toBe(localDatetime.hour)
expect(standardDate.getMinutes()).toBe(localDatetime.minute)
expect(standardDate.getSeconds()).toBe(localDatetime.second)
expect(standardDate.getMilliseconds()).toBe(localDatetime.nanosecond / 1000000)
})

it('should be the reverse operation of fromStandardDate', () => {
const date = new global.Date()

const localDatetime = LocalDateTime.fromStandardDate(date)
const receivedDate = localDatetime.toStandardDate()

expect(receivedDate).toEqual(date)
})
})
})

describe('DateTime', () => {
describe('.toStandardDate()', () => {
it('should convert to a standard date (offset)', () => {
const datetime = new DateTime(2020, 12, 15, 12, 2, 3, 4000000, 120 * 60)

const standardDate = datetime.toStandardDate()


expect(standardDate.getFullYear()).toEqual(datetime.year)
expect(standardDate.getMonth()).toEqual(datetime.month - 1)
expect(standardDate.getDate()).toEqual(datetime.day)
const offsetInMinutes = offset(standardDate)
const offsetAdjust = offsetInMinutes - datetime.timeZoneOffsetSeconds!! / 60
const hourDiff = Math.abs(offsetAdjust / 60)
const minuteDiff = Math.abs(offsetAdjust % 60)
expect(standardDate.getHours()).toBe(datetime.hour - hourDiff)
expect(standardDate.getMinutes()).toBe(datetime.minute - minuteDiff)
expect(standardDate.getSeconds()).toBe(datetime.second)
expect(standardDate.getMilliseconds()).toBe(datetime.nanosecond / 1000000)
})

it('should not convert to a standard date (zoneid)', () => {
const datetime = new DateTime(2020, 12, 15, 12, 2, 3, 4000000, undefined, 'Europe/Stockholm')

expect(() => datetime.toStandardDate())
.toThrow(new Error('Requires DateTime created with time zone offset'))

})

it('should be the reverse operation of fromStandardDate', () => {
const date = new global.Date()

const datetime = DateTime.fromStandardDate(date)
const receivedDate = datetime.toStandardDate()

expect(receivedDate).toEqual(date)
})
})
})

/**
* The offset in StandardDate is the number of minutes
* to sum to the date and time to get the UTC time.
*
* This function change the sign of the offset,
* this way using the most common meaning.
* The time to add to UTC to get the local time.
*/
function offset(date: StandardDate): number {
return date.getTimezoneOffset() * -1
}