Skip to content

Commit e5e9e40

Browse files
committed
Enable DateTime to be initialized with Offset and ZoneId
1 parent 20c16e5 commit e5e9e40

File tree

3 files changed

+65
-17
lines changed

3 files changed

+65
-17
lines changed

packages/core/src/temporal-types.ts

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,13 @@ export class DateTime<T extends NumberOrInteger = Integer> {
670670
if (this.timeZoneOffsetSeconds === undefined) {
671671
throw new Error('Requires DateTime created with time zone offset')
672672
}
673-
return util.isoStringToStandardDate(this.toString())
673+
return util.isoStringToStandardDate(
674+
// the timezone name should be removed from the
675+
// string, otherwise the javascript parse doesn't
676+
// read the datetime correctly
677+
this.toString().replace(
678+
this.timeZoneId != null ? `[${this.timeZoneId}]` : '', '')
679+
)
674680
}
675681

676682
/**
@@ -686,10 +692,16 @@ export class DateTime<T extends NumberOrInteger = Integer> {
686692
this.second,
687693
this.nanosecond
688694
)
695+
696+
const timeOffset = this.timeZoneOffsetSeconds != null
697+
? util.timeZoneOffsetToIsoString(this.timeZoneOffsetSeconds ?? 0)
698+
: ''
699+
689700
const timeZoneStr = this.timeZoneId != null
690701
? `[${this.timeZoneId}]`
691-
: util.timeZoneOffsetToIsoString(this.timeZoneOffsetSeconds ?? 0)
692-
return localDateTimeStr + timeZoneStr
702+
: ''
703+
704+
return localDateTimeStr + timeOffset + timeZoneStr
693705
}
694706
}
695707

@@ -741,23 +753,25 @@ function verifyTimeZoneArguments (
741753
const offsetDefined = timeZoneOffsetSeconds !== null && timeZoneOffsetSeconds !== undefined
742754
const idDefined = timeZoneId !== null && timeZoneId !== undefined && timeZoneId !== ''
743755

744-
if (offsetDefined && !idDefined) {
745-
assertNumberOrInteger(timeZoneOffsetSeconds, 'Time zone offset in seconds')
746-
return [timeZoneOffsetSeconds, undefined]
747-
} else if (!offsetDefined && idDefined) {
748-
assertString(timeZoneId, 'Time zone ID')
749-
return [undefined, timeZoneId]
750-
} else if (offsetDefined && idDefined) {
751-
throw newError(
752-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
753-
`Unable to create DateTime with both time zone offset and id. Please specify either of them. Given offset: ${timeZoneOffsetSeconds} and id: ${timeZoneId}`
754-
)
755-
} else {
756+
if (!offsetDefined && !idDefined) {
756757
throw newError(
757758
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
758759
`Unable to create DateTime without either time zone offset or id. Please specify either of them. Given offset: ${timeZoneOffsetSeconds} and id: ${timeZoneId}`
759760
)
760761
}
762+
763+
const result: [NumberOrInteger | undefined | null, string | undefined | null] = [undefined, undefined]
764+
if (offsetDefined) {
765+
assertNumberOrInteger(timeZoneOffsetSeconds, 'Time zone offset in seconds')
766+
result[0] = timeZoneOffsetSeconds
767+
}
768+
769+
if (idDefined) {
770+
assertString(timeZoneId, 'Time zone ID')
771+
result[1] = timeZoneId
772+
}
773+
774+
return result
761775
}
762776

763777
/**

packages/core/test/temporal-types.test.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,41 @@ describe('LocalDateTime', () => {
7474
})
7575

7676
describe('DateTime', () => {
77+
describe('constructor', () => {
78+
it('should be able to create a date with zone id and offset', () => {
79+
const datetime = new DateTime(2022, 6, 16, 11, 19, 25, 400004, 2 * 60 * 60, 'Europe/Stockholm')
80+
81+
expect(datetime.year).toEqual(2022)
82+
expect(datetime.month).toEqual(6)
83+
expect(datetime.day).toEqual(16)
84+
expect(datetime.hour).toEqual(11)
85+
expect(datetime.minute).toEqual(19)
86+
expect(datetime.second).toEqual(25)
87+
expect(datetime.nanosecond).toEqual(400004)
88+
expect(datetime.timeZoneOffsetSeconds).toEqual(2 * 60 * 60)
89+
expect(datetime.timeZoneId).toEqual('Europe/Stockholm')
90+
})
91+
})
92+
7793
describe('.toStandardDate()', () => {
94+
it('should convert to a standard date (offset + zone id)', () => {
95+
const datetime = new DateTime(2022, 6, 16, 11, 19, 25, 4000004, 2 * 60 * 60, 'Europe/Stockholm')
96+
97+
const standardDate = datetime.toStandardDate()
98+
99+
expect(standardDate.getFullYear()).toEqual(datetime.year)
100+
expect(standardDate.getMonth()).toEqual(datetime.month - 1)
101+
expect(standardDate.getDate()).toEqual(datetime.day)
102+
const offsetInMinutes = offset(standardDate)
103+
const offsetAdjust = offsetInMinutes - (datetime.timeZoneOffsetSeconds ?? 0) / 60
104+
const hourDiff = Math.abs(offsetAdjust / 60)
105+
const minuteDiff = Math.abs(offsetAdjust % 60)
106+
expect(standardDate.getHours()).toBe(datetime.hour - hourDiff)
107+
expect(standardDate.getMinutes()).toBe(datetime.minute - minuteDiff)
108+
expect(standardDate.getSeconds()).toBe(datetime.second)
109+
expect(standardDate.getMilliseconds()).toBe(Math.round(datetime.nanosecond / 1000000))
110+
})
111+
78112
it('should convert to a standard date (offset)', () => {
79113
const datetime = new DateTime(2020, 12, 15, 12, 2, 3, 4000000, 120 * 60)
80114

@@ -90,7 +124,7 @@ describe('DateTime', () => {
90124
expect(standardDate.getHours()).toBe(datetime.hour - hourDiff)
91125
expect(standardDate.getMinutes()).toBe(datetime.minute - minuteDiff)
92126
expect(standardDate.getSeconds()).toBe(datetime.second)
93-
expect(standardDate.getMilliseconds()).toBe(datetime.nanosecond / 1000000)
127+
expect(standardDate.getMilliseconds()).toBe(Math.round(datetime.nanosecond / 1000000))
94128
})
95129

96130
it('should not convert to a standard date (zoneid)', () => {

packages/testkit-backend/src/cypher-native-binders.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export function cypherToNative (c) {
150150
data.minute,
151151
data.second,
152152
data.nanosecond,
153-
data.timezone_id == null ? data.utc_offset_s : null,
153+
data.utc_offset_s,
154154
data.timezone_id
155155
)
156156
case 'CypherMap':

0 commit comments

Comments
 (0)