@@ -122,6 +122,41 @@ describe('dora.ts', function() {
122122 it ( 'should throw error if can\'t parse time string' , function ( ) {
123123 expect ( ( ) => Dora . parse ( '20220102123212' ) ) . toThrow ( )
124124 } )
125+
126+ it ( 'should interpret timezone-less string as wall-clock time in given timezone' , function ( ) {
127+ const m = Dora . parse ( '2020-10-08 15:32:01.158' , 'Asia/Shanghai' )
128+ expect ( m . timezone ( ) ) . toEqual ( 'Asia/Shanghai' )
129+ expect ( m . year ( ) ) . toEqual ( 2020 )
130+ expect ( m . month ( ) ) . toEqual ( 9 )
131+ expect ( m . date ( ) ) . toEqual ( 8 )
132+ expect ( m . hour ( ) ) . toEqual ( 15 )
133+ expect ( m . minute ( ) ) . toEqual ( 32 )
134+ expect ( m . second ( ) ) . toEqual ( 1 )
135+ expect ( m . millisecond ( ) ) . toEqual ( 158 )
136+ expect ( m . format ( 'Z' ) ) . toEqual ( '+08:00' )
137+ } )
138+
139+ it ( 'should use string timezone as the UTC moment, display in given timezone' , function ( ) {
140+ const m = Dora . parse ( '2020-10-08 11:03:16.158+08:00' , 'Asia/Yangon' )
141+ expect ( m . timezone ( ) ) . toEqual ( 'Asia/Yangon' )
142+ expect ( m . hour ( ) ) . toEqual ( 9 )
143+ expect ( m . minute ( ) ) . toEqual ( 33 )
144+ expect ( m . format ( 'Z' ) ) . toEqual ( '+06:30' )
145+ } )
146+
147+ it ( 'should correctly handle timezone-less ISO string with given timezone' , function ( ) {
148+ const shanghai = Dora . parse ( '2022-05-16T15:38:28.000' , 'Asia/Shanghai' )
149+ expect ( shanghai . format ( ) ) . toEqual ( '2022-05-16T15:38:28.000+08:00' )
150+ const utc = Dora . parse ( '2022-05-16T15:38:28.000' , 'UTC' )
151+ expect ( utc . format ( ) ) . toEqual ( '2022-05-16T15:38:28.000+00:00' )
152+ } )
153+
154+ it ( 'should fall back gracefully for non-ISO timezone-less string with given timezone' , function ( ) {
155+ // 'Mon May 16 2022 15:38:28' → first-space-to-T → 'Mon May 16T2022 15:38:28Z' which is invalid ISO
156+ const m = Dora . parse ( 'Mon May 16 2022 15:38:28' , 'Asia/Shanghai' )
157+ expect ( m ) . toBeInstanceOf ( Dora )
158+ expect ( m . timezone ( ) ) . toEqual ( 'Asia/Shanghai' )
159+ } )
125160 } )
126161
127162 describe ( '.format()' , function ( ) {
@@ -437,5 +472,56 @@ describe('dora.ts', function() {
437472 expect ( m . end_of ( 'isoWeek' ) . format ( ) ) . toEqual ( '2022-05-22T23:59:59.999+08:00' )
438473 } )
439474 } )
475+
476+ describe ( '.utc_offset()' , function ( ) {
477+
478+ it ( 'should return negative value for UTC+ timezone' , function ( ) {
479+ // UTC+8: internal offset = UTC fields - local fields = -480
480+ const m = new Dora ( 1652686708000 , 'Asia/Shanghai' )
481+ expect ( m . utc_offset ( ) ) . toEqual ( - 480 )
482+ } )
483+
484+ it ( 'should return positive value for UTC- timezone' , function ( ) {
485+ // UTC-6: internal offset = UTC fields - local fields = +360
486+ const m = new Dora ( 1652686708000 , 'America/Inuvik' )
487+ expect ( m . utc_offset ( ) ) . toEqual ( 360 )
488+ } )
489+
490+ it ( 'should return zero for UTC timezone' , function ( ) {
491+ const m = new Dora ( 1652686708000 , 'UTC' )
492+ expect ( m . utc_offset ( ) ) . toEqual ( 0 )
493+ } )
494+
495+ it ( 'should correctly compute offset for UTC+14 crossing year boundary' , function ( ) {
496+ // Pacific/Kiritimati is UTC+14
497+ // 2022-12-31T22:00:00Z = 2023-01-01T12:00:00+14:00 (year boundary crossed)
498+ const ts = new Date ( '2022-12-31T22:00:00Z' ) . getTime ( )
499+ const m = new Dora ( ts , 'Pacific/Kiritimati' )
500+ expect ( m . year ( ) ) . toEqual ( 2023 )
501+ expect ( m . month ( ) ) . toEqual ( 0 )
502+ expect ( m . date ( ) ) . toEqual ( 1 )
503+ expect ( m . utc_offset ( ) ) . toEqual ( - 840 )
504+ expect ( m . format ( 'Z' ) ) . toEqual ( '+14:00' )
505+ } )
506+
507+ it ( 'should correctly compute offset for UTC-11 crossing year boundary' , function ( ) {
508+ // Pacific/Pago_Pago is UTC-11
509+ // 2023-01-01T10:00:00Z = 2022-12-31T23:00:00-11:00 (year boundary crossed)
510+ const ts = new Date ( '2023-01-01T10:00:00Z' ) . getTime ( )
511+ const m = new Dora ( ts , 'Pacific/Pago_Pago' )
512+ expect ( m . year ( ) ) . toEqual ( 2022 )
513+ expect ( m . month ( ) ) . toEqual ( 11 )
514+ expect ( m . date ( ) ) . toEqual ( 31 )
515+ expect ( m . utc_offset ( ) ) . toEqual ( 660 )
516+ expect ( m . format ( 'Z' ) ) . toEqual ( '-11:00' )
517+ } )
518+
519+ it ( 'should correctly compute offset for UTC+5:30 (non-whole-hour offset)' , function ( ) {
520+ // Asia/Kolkata is UTC+5:30
521+ const m = new Dora ( 1652686708000 , 'Asia/Kolkata' )
522+ expect ( m . utc_offset ( ) ) . toEqual ( - 330 )
523+ expect ( m . format ( 'Z' ) ) . toEqual ( '+05:30' )
524+ } )
525+ } )
440526 } )
441527} )
0 commit comments