diff --git a/repository/ZTimestamp-Core/ZTimestampFormat.class.st b/repository/ZTimestamp-Core/ZTimestampFormat.class.st index fec307a..553f27b 100644 --- a/repository/ZTimestamp-Core/ZTimestampFormat.class.st +++ b/repository/ZTimestamp-Core/ZTimestampFormat.class.st @@ -361,7 +361,13 @@ ZTimestampFormat >> compileSpecification [ | elements | elements := self specificationElements. formatter := elements - collect: [ :each | each isCharacter ifTrue: [ each ] ifFalse: [ (#format: , each , #On:) asSymbol ] ]. + collect: [ :each | + each isCharacter + ifTrue: [ each ] + ifFalse: [ + (each beginsWith: #timeZone) + ifTrue: [ (#format: , each , #'On:usingOffset:') asSymbol ] + ifFalse: [ (#format: , each , #On:) asSymbol ] ] ]. parser := elements collect: [ :each | each isCharacter @@ -627,12 +633,16 @@ ZTimestampFormat >> format: object nanosecondOn: stream [ ZTimestampFormat >> format: object on: stream [ "Format object on stream according to my specification" - | local | + | local offset| local := self gmtToLocal: object. + offset := self actualOffsetForTimestamp: object. formatter do: [ :each | each isCharacter ifTrue: [ stream nextPut: each ] - ifFalse: [ self perform: each with: local with: stream ] ] + ifFalse: [ + each numArgs = 2 + ifTrue: [ self perform: each with: local with: stream ] + ifFalse: [self perform: each with: local with: stream with: offset ] ] ] ] { #category : #formatters } @@ -654,6 +664,13 @@ ZTimestampFormat >> format: object timeZoneAbbreviatedLongOn: stream [ ifFalse: [ stream << (self abbreviationForTimeZoneOffset: offset) ] ] +{ #category : #formatters } +ZTimestampFormat >> format: object timeZoneAbbreviatedLongOn: stream usingOffset: offset [ + offset isZero + ifTrue: [ stream << #UTC ] + ifFalse: [ stream << (self abbreviationForTimeZoneOffset: offset) ] +] + { #category : #formatters } ZTimestampFormat >> format: object timeZoneAbbreviatedOn: stream [ | offset | @@ -663,6 +680,13 @@ ZTimestampFormat >> format: object timeZoneAbbreviatedOn: stream [ ifFalse: [ stream << (self abbreviationForTimeZoneOffset: offset) ] ] +{ #category : #formatters } +ZTimestampFormat >> format: object timeZoneAbbreviatedOn: stream usingOffset: offset [ + offset isZero + ifTrue: [ stream << #UTC ] + ifFalse: [ stream << (self abbreviationForTimeZoneOffset: offset) ] +] + { #category : #formatters } ZTimestampFormat >> format: object timeZoneOn: stream [ | offset | @@ -675,6 +699,16 @@ ZTimestampFormat >> format: object timeZoneOn: stream [ printOn: stream base: 10 length: 2 padded: true ] +{ #category : #formatters } +ZTimestampFormat >> format: object timeZoneOn: stream usingOffset: offset [ + stream nextPut: (offset positive ifTrue: [ $+ ] ifFalse: [ $- ]). + offset hours abs + printOn: stream base: 10 length: 2 padded: true. + stream nextPut: $:. + offset minutes + printOn: stream base: 10 length: 2 padded: true +] + { #category : #formatters } ZTimestampFormat >> format: object timeZoneZOn: stream [ | offset | @@ -690,6 +724,19 @@ ZTimestampFormat >> format: object timeZoneZOn: stream [ printOn: stream base: 10 length: 2 padded: true ] ] +{ #category : #formatters } +ZTimestampFormat >> format: object timeZoneZOn: stream usingOffset: offset [ + offset isZero + ifTrue: [ stream nextPut: $Z ] + ifFalse: [ + stream nextPut: (offset positive ifTrue: [ $+ ] ifFalse: [ $- ]). + offset hours abs + printOn: stream base: 10 length: 2 padded: true. + stream nextPut: $:. + offset minutes + printOn: stream base: 10 length: 2 padded: true ] +] + { #category : #formatters } ZTimestampFormat >> format: object weekdayNameAbbreviatedCapitalizedOn: stream [ stream << ((self weekdayNames at: object dayOfWeek) copyFrom: 1 to: 3) diff --git a/repository/ZTimestamp-GT/ZTimezone.extension.st b/repository/ZTimestamp-GT/ZTimezone.extension.st index d4f26dc..dca700e 100644 --- a/repository/ZTimestamp-GT/ZTimezone.extension.st +++ b/repository/ZTimestamp-GT/ZTimezone.extension.st @@ -141,9 +141,13 @@ ZTimezone >> gtViewTransitionsIn: composite [ ^ composite columnedList title: 'Transitions'; items: [ self resolvedTransitions ]; - column: 'Start absolute' text: [ :association | association key ]; - column: ('Start ' , self id) - text: [ :association | ZTimestampFormat isoTZ timezone: self; format: association key ]; + column: 'Start absolute' + text: [ :association | association key ]; + column: 'Start local' + text: [ :association | + ((ZTimestampFormat fromString: '2001-02-03 T 16:05:06+00:00') timezone: self; format: association key - 1 second) , + ' > ' , + ((ZTimestampFormat fromString: '16:05:06+00:00') timezone: self; format: association key) ]; column: ('Start ' , ZCurrentTimezone value id) text: [ :association | ZTimestampFormat isoTZ useCurrentTimezone; format: association key ]; column: 'Subzone' text: [ :association | association value description ] diff --git a/repository/ZTimestamp-Tests/ZTimestampFormatTests.class.st b/repository/ZTimestamp-Tests/ZTimestampFormatTests.class.st index 30839a0..c6b849a 100644 --- a/repository/ZTimestamp-Tests/ZTimestampFormatTests.class.st +++ b/repository/ZTimestamp-Tests/ZTimestampFormatTests.class.st @@ -287,6 +287,30 @@ ZTimestampFormatTests >> testTimeParsing [ equals: (ZTimestamp year: 1 month: 1 day: 1 hour: 23 minute: 30 second: 19). ] +{ #category : #accessing } +ZTimestampFormatTests >> testTransitionFormatting [ + | t1 t2 | + t1 := ZTimestamp fromUnixTime: 1679792400. "winter->summer" + t2 := ZTimestamp fromUnixTime: 1698541200. "summer->winter" + ZCurrentTimezone + value: ZTimezone europeBrussels + during: [ + self + assert: (ZTimestampFormat isoTZ useCurrentTimezone; format: t1) + equals: '2023-03-26T03:00:00+02:00'. + self + assert: (ZTimestampFormat isoTZ useCurrentTimezone; format: t1 - 1 second) + equals: '2023-03-26T01:59:59+01:00'. + + self + assert: (ZTimestampFormat isoTZ useCurrentTimezone; format: t2) + equals: '2023-10-29T02:00:00+01:00'. + self + assert: (ZTimestampFormat isoTZ useCurrentTimezone; format: t2 - 1 second) + equals: '2023-10-29T02:59:59+02:00'. + ] +] + { #category : #testing } ZTimestampFormatTests >> testWeekdayNames [ | timestamp |