Skip to content

Commit 3447791

Browse files
authored
Fix Zoned DateTime support for dates before common era (#986)
Years previous the common era were being treated as positive numbers causing the dates appear as positive numbers and breaking the auto-zone offset detection for zoned date times which were not created with the offset.
1 parent edde4fc commit 3447791

File tree

5 files changed

+50
-5
lines changed

5 files changed

+50
-5
lines changed

packages/bolt-connection/src/bolt/bolt-protocol-v5x0.utc.transformer.js

+13-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import v4x4 from './bolt-protocol-v4x4.transformer'
3030
import {
3131
epochSecondAndNanoToLocalDateTime
3232
} from './temporal-factory'
33+
import { identity } from '../lang/functional'
3334

3435
const {
3536
temporalUtil: {
@@ -89,8 +90,8 @@ function createDateTimeWithZoneIdTransformer (config, logger) {
8990

9091
if (value.timeZoneOffsetSeconds == null) {
9192
logger.warn('DateTime objects without "timeZoneOffsetSeconds" property ' +
92-
'are prune to bugs related to ambiguous times. For instance, ' +
93-
'2022-10-30T2:30:00[Europe/Berlin] could be GMT+1 or GMT+2.')
93+
'are prune to bugs related to ambiguous times. For instance, ' +
94+
'2022-10-30T2:30:00[Europe/Berlin] could be GMT+1 or GMT+2.')
9495
}
9596
const utc = epochSecond.subtract(offset)
9697

@@ -167,7 +168,8 @@ function getTimeInZoneId (timeZoneId, epochSecond, nano) {
167168
hour: 'numeric',
168169
minute: 'numeric',
169170
second: 'numeric',
170-
hour12: false
171+
hour12: false,
172+
era: 'narrow'
171173
})
172174

173175
const l = epochSecondAndNanoToLocalDateTime(epochSecond, nano)
@@ -183,12 +185,19 @@ function getTimeInZoneId (timeZoneId, epochSecond, nano) {
183185
const formattedUtcParts = formatter.formatToParts(utc)
184186

185187
const localDateTime = formattedUtcParts.reduce((obj, currentValue) => {
186-
if (currentValue.type !== 'literal') {
188+
if (currentValue.type === 'era') {
189+
obj.adjustEra =
190+
currentValue.value.toLocaleUpperCase() === 'B'
191+
? year => year.subtract(1).negate() // 1BC equals to year 0 in astronomical year numbering
192+
: identity
193+
} else if (currentValue.type !== 'literal') {
187194
obj[currentValue.type] = int(currentValue.value)
188195
}
189196
return obj
190197
}, {})
191198

199+
localDateTime.year = localDateTime.adjustEra(localDateTime.year)
200+
192201
const epochInTimeZone = localDateTimeToEpochSecond(
193202
localDateTime.year,
194203
localDateTime.month,

packages/bolt-connection/test/bolt/bolt-protocol-v4x3.test.js

+12
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,18 @@ describe('#unit BoltProtocolV4x3', () => {
801801
[
802802
'DateTimeWithZoneId / Sao Paulo just 1 after turn winter time',
803803
new DateTime(2019, 2, 18, 1, 0, 0, 183_000_000, undefined, 'America/Sao_Paulo')
804+
],
805+
[
806+
'DateWithWithZoneId / Berlin before common era',
807+
new DateTime(-2020, 6, 15, 4, 30, 0, 183_000_000, undefined, 'Europe/Berlin')
808+
],
809+
[
810+
'DateWithWithZoneId / Max Date',
811+
new DateTime(99_999, 12, 31, 23, 59, 59, 999_999_999, undefined, 'Pacific/Kiritimati')
812+
],
813+
[
814+
'DateWithWithZoneId / Min Date',
815+
new DateTime(-99_999, 12, 31, 23, 59, 59, 999_999_999, undefined, 'Pacific/Samoa')
804816
]
805817
])('should pack and unpack DateTimeWithZoneId and without offset (%s)', (_, object) => {
806818
const packable = protocol.packable(object)

packages/bolt-connection/test/bolt/bolt-protocol-v4x4.test.js

+12
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,18 @@ describe('#unit BoltProtocolV4x4', () => {
834834
[
835835
'DateTimeWithZoneId / Sao Paulo just 1 after turn winter time',
836836
new DateTime(2019, 2, 18, 1, 0, 0, 183_000_000, undefined, 'America/Sao_Paulo')
837+
],
838+
[
839+
'DateWithWithZoneId / Berlin before common era',
840+
new DateTime(-2020, 6, 15, 4, 30, 0, 183_000_000, undefined, 'Europe/Berlin')
841+
],
842+
[
843+
'DateWithWithZoneId / Max Date',
844+
new DateTime(99_999, 12, 31, 23, 59, 59, 999_999_999, undefined, 'Pacific/Kiritimati')
845+
],
846+
[
847+
'DateWithWithZoneId / Min Date',
848+
new DateTime(-99_999, 12, 31, 23, 59, 59, 999_999_999, undefined, 'Pacific/Samoa')
837849
]
838850
])('should pack and unpack DateTimeWithZoneId and without offset (%s)', (_, object) => {
839851
const packable = protocol.packable(object)

packages/bolt-connection/test/bolt/bolt-protocol-v5x0.test.js

+12
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,18 @@ describe('#unit BoltProtocolV5x0', () => {
527527
[
528528
'DateTimeWithZoneId / Istanbul',
529529
new DateTime(2020, 6, 15, 4, 30, 0, 183_000_000, undefined, 'Pacific/Honolulu')
530+
],
531+
[
532+
'DateWithWithZoneId / Berlin before common era',
533+
new DateTime(-2020, 6, 15, 4, 30, 0, 183_000_000, undefined, 'Europe/Berlin')
534+
],
535+
[
536+
'DateWithWithZoneId / Max Date',
537+
new DateTime(99_999, 12, 31, 23, 59, 59, 999_999_999, undefined, 'Pacific/Kiritimati')
538+
],
539+
[
540+
'DateWithWithZoneId / Min Date',
541+
new DateTime(-99_999, 12, 31, 23, 59, 59, 999_999_999, undefined, 'Pacific/Samoa')
530542
]
531543
])('should pack and unpack DateTimeWithZoneId and without offset (%s)', (_, object) => {
532544
const buffer = alloc(256)

packages/neo4j-driver/test/temporal-types.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const MAX_TEMPORAL_ARRAY_LENGTH = 1000
3838
*/
3939
const MAX_DURATION_COMPONENT = 3000000000000
4040
const MAX_NANO_OF_SECOND = 999999999
41-
const MAX_YEAR = 999999999
41+
const MAX_YEAR = 99_999
4242
const MIN_YEAR = -MAX_YEAR
4343
const MAX_TIME_ZONE_OFFSET = 64800
4444
const MIN_TIME_ZONE_OFFSET = -MAX_TIME_ZONE_OFFSET

0 commit comments

Comments
 (0)