Thank you Dave! The follow-up questions:

1. I noted that Chronology-Core-dtl.83 and Chronology-Core-dtl.84 are still in the inbox. Should they be moved to trunk?
2. Our list of timezones is very incomplete at the moment. Do you think we should update the list? I don't have an overview of the TZ-Olson package, would it be worth merging in the trunk? Or could we just import the recent database once and generate an updated version of the constants in FixedTimeZone? I imagine that we could have a similar solution to Unicode class>>#initializeUnicodeData, so that in the end, a maintainer only has to rerun the database update once a while and we don't have additional dependencies in the image.

Best,
Christoph

---
Sent from Squeak Inbox Talk

On 2023-07-08T15:54:15+00:00, commits@source.squeak.org wrote:

> David T. Lewis uploaded a new version of Chronology-Core to project The Trunk:
> http://source.squeak.org/trunk/Chronology-Core-dtl.85.mcz
>
> ==================== Summary ====================
>
> Name: Chronology-Core-dtl.85
> Author: dtl
> Time: 1 July 2023, 9:01:03.976799 pm
> UUID: bdd66b0f-97e1-4fd5-bca6-4194eaf60096
> Ancestors: Chronology-Core-mt.82
>
> Establish protocol for aTimeZone offsetAt: aDateAndTime. Let TimeZone be abstract and let FixedTimeZone implement the previous behavior with offset represented as a constant (no DST transition support). Other packages (e.g. TZ-Olson) may implement concrete TimeZone with DST support.
>
> Save existing TimeZone instances in the package preamble and migrate them to FixedTimeZone in the postscript.
>
> =============== Diff against Chronology-Core-mt.82 ===============
>
> Item was added:
> + (PackageInfo named: 'Chronology-Core') preamble: '"below, add code to be run before the loading of this package"
> +
> + "Remember all instances of TimeZone. These will become FixedTimeZone in the postscript"
> + TimeZone instSize = 3 ifTrue: [
> +     Smalltalk at: #TimeZoneInstances put:
> +         (Dictionary newFrom: (
> +             TimeZone allInstances collect: [:tz |
> +                 tz -> { tz offset . tz name . tz abbreviation }]))].
> + '!
>
> Item was changed:
> ----- Method: DateAndTime class>>localOffset: (in category 'squeak protocol') -----
> localOffset: aDuration
>     "Override the local time zone (for testing). This disables the #automaticTimezone: preference"
> +     self localTimeZone: (FixedTimeZone offset: aDuration name: 'Local Time (override)' abbreviation: 'LTO').
> -     self localTimeZone: (TimeZone offset: aDuration name: 'Local Time (override)' abbreviation: 'LTO').
> !
>
> Item was changed:
> ----- Method: DateAndTime class>>now (in category 'ansi protocol') -----
> now
> +     "Answer time now as reported by #primitiveUtcWithOffset. If the automaticTimeZone
> +     preference is false, use the offset provided by LocalTimeZone rather than the offset
> +     provided by the primitive."
> -     "Answer time now as reported by #primitiveUtcWithOffset. If the primitive is not
> -     available, answer the Posix epoch GMT."
>
>     self automaticTimezone
>         ifTrue: [ ^ self basicNew initializeFromPrimitive ]
>         ifFalse: [ | timeArray |
>             timeArray := Time posixMicrosecondClockWithOffset.
>             ^ self utcMicroseconds: timeArray first offset: self localOffsetSeconds ]
> !
>
> Item was added:
> + TimeZone subclass: #FixedTimeZone
> +     instanceVariableNames: 'offset abbreviation name'
> +     classVariableNames: ''
> +     poolDictionaries: 'ChronologyConstants'
> +     category: 'Chronology-Core'!
> +
> + !FixedTimeZone commentStamp: 'dtl 6/20/2023 08:07' prior: 0!
> + FixedTimeZone is a simple class to collect the information identifying a UTC time zone. It is typically used in unit tests to specify specific time zone offsets.
> +
> + offset            -    Duration    - the time zone's offset from UTC
> + abbreviation    -    String        - the abbreviated name for the time zone.
> + name            -    String        - the name of the time zone.
> +
> + StaticTimeZone class >> #timeZones returns an array of the known time zones
> + StaticTimeZone class >> #default returns the default time zone (Greenwich Mean Time)
> + !
>
> Item was added:
> + ----- Method: FixedTimeZone class>>allTimeZones (in category 'accessing') -----
> + allTimeZones
> +
> +     ^ self timeZones , self timeZonesDST!
>
> Item was added:
> + ----- Method: FixedTimeZone class>>default (in category 'accessing') -----
> + default
> +     "Answer the default time zone - GMT"
> +
> +     ^ self timeZones detect: [ :tz | tz offset = Duration zero ]!
>
> Item was added:
> + ----- Method: FixedTimeZone class>>offset:name:abbreviation: (in category 'instance creation') -----
> + offset: aDuration name: aName abbreviation: anAbbreviation
> +
> +     ^ self new
> +         offset: aDuration;
> +         name: aName;
> +         abbreviation: anAbbreviation;
> +         yourself
> + !
>
> Item was added:
> + ----- Method: FixedTimeZone class>>timeZones (in category 'accessing') -----
> + timeZones
> +     ^{
> +         self offset: 0 hours name: 'Universal Time' abbreviation: 'UTC'.
> +         self offset: 0 hours name: 'Greenwich Mean Time' abbreviation: 'GMT'.
> +         self offset: 1 hours name: 'Central European Time' abbreviation: 'CET'.
> +         self offset: 2 hours name: 'South African Standard Time' abbreviation: 'SAST'.
> +         self offset: -8 hours name: 'Pacific Standard Time' abbreviation: 'PST'.
> +         self offset: -7 hours name: 'Mountain Standard Time' abbreviation: 'MST'.
> +         self offset: -6 hours name: 'Central Standard Time' abbreviation: 'CST'.
> +         self offset: -5 hours name: 'Eastern Standard Time' abbreviation: 'EST'.
> +     }!
>
> Item was added:
> + ----- Method: FixedTimeZone class>>timeZonesDST (in category 'accessing') -----
> + timeZonesDST
> +     ^{
> +         self offset: 1 hours name: 'British Summer Time' abbreviation: 'BST'.
> +         self offset: 2 hours name: 'Central European Summer Time' abbreviation: 'CEST'.
> +         self offset: -7 hours name: 'Pacific Daylight Time' abbreviation: 'PDT'.
> +         self offset: -6 hours name: 'Mountain Daylight Time' abbreviation: 'MDT'.
> +         self offset: -5 hours name: 'Central Daylight Time' abbreviation: 'CDT'.
> +         self offset: -4 hours name: 'Eastern Daylight Time' abbreviation: 'EDT'.
> +     }!
>
> Item was added:
> + ----- Method: FixedTimeZone>>abbreviation (in category 'accessing') -----
> + abbreviation
> +
> +     ^ abbreviation!
>
> Item was added:
> + ----- Method: FixedTimeZone>>abbreviation: (in category 'accessing') -----
> + abbreviation: aString
> +
> +     abbreviation := aString!
>
> Item was added:
> + ----- Method: FixedTimeZone>>name (in category 'accessing') -----
> + name
> +
> +     ^ name!
>
> Item was added:
> + ----- Method: FixedTimeZone>>name: (in category 'accessing') -----
> + name: aString
> +
> +     name := aString!
>
> Item was added:
> + ----- Method: FixedTimeZone>>offset: (in category 'accessing') -----
> + offset: aDuration
> +
> +     offset := aDuration
> + !
>
> Item was added:
> + ----- Method: FixedTimeZone>>offsetAt: (in category 'accessing') -----
> + offsetAt: dateAndTime
> +     "A FixedTimeZone has a constant offset, ignoring daylight savings time transitions"
> +
> +     ^ offset
> + !
>
> Item was added:
> + ----- Method: FixedTimeZone>>printOn: (in category 'private') -----
> + printOn: aStream
> +
> +     super printOn: aStream.
> +     aStream
> +         nextPut: $(;
> +         nextPutAll: self abbreviation;
> +         nextPut: $)!
>
> Item was changed:
> Object subclass: #TimeZone
> +     instanceVariableNames: ''
> -     instanceVariableNames: 'offset abbreviation name'
>     classVariableNames: ''
>     poolDictionaries: 'ChronologyConstants'
>     category: 'Chronology-Core'!
>
> + !TimeZone commentStamp: 'dtl 6/15/2023 22:27' prior: 0!
> + A TimeZone answers the UTC offset for a DateAndTime based on local rules for a geographic region. For each regional time zone, the UTC offset varies as a function of the DateAndTime, notably in support of daylight savings time changes. The UTC offset for a TimeZone also may change over time as local rules are updated for various regions and political jurisdictions.
> - !TimeZone commentStamp: 'dtl 7/11/2009 15:03' prior: 0!
> - TimeZone is a simple class to colect the information identifying a UTC time zone.
>
> + Concrete subclasses are expected to implement UTC offset rules. The simple case of FixedTimeZone implements a time zone with constant offset, which is useful for unit test support.!
> - offset            -    Duration    - the time zone's offset from UTC
> - abbreviation    -    String        - the abbreviated name for the time zone.
> - name            -    String        - the name of the time zone.
> -
> - TimeZone class >> #timeZones returns an array of the known time zones
> - TimeZone class >> #default returns the default time zone (Grenwich Mean Time)
> - !
>
> Item was added:
> + ----- Method: TimeZone class>>allForOffset: (in category 'accessing') -----
> + allForOffset: aDuration
> +
> +     ^ self allTimeZones select: [:ea | ea offset = aDuration]!
>
> Item was added:
> + ----- Method: TimeZone class>>allTimeZones (in category 'accessing') -----
> + allTimeZones
> +     "Various concrete implementations may be available. These may include a
> +     simple StaticTimeZone or e.g. the TZ-Olson time zone tables with daylight
> +     savings time offset transitions."
> +
> +     ^ self allSubclasses
> +         inject: OrderedCollection new
> +         into: [ :result :cls |
> +             (cls class includesLocalSelector: #allTimeZones)
> +                 ifTrue: [result addAll: cls allTimeZones].
> +             result].
> + !
>
> Item was changed:
> ----- Method: TimeZone class>>default (in category 'accessing') -----
> default
>     "Answer the default time zone - GMT"
>
> +     ^ FixedTimeZone default!
> -     ^ self timeZones detect: [ :tz | tz offset = Duration zero ]!
>
> Item was removed:
> - ----- Method: TimeZone class>>offset:name:abbreviation: (in category 'instance creation') -----
> - offset: aDuration name: aName abbreviation: anAbbreviation
> -
> -     ^ self new
> -         offset: aDuration;
> -         name: aName;
> -         abbreviation: anAbbreviation;
> -         yourself
> - !
>
> Item was removed:
> - ----- Method: TimeZone class>>timeZones (in category 'accessing') -----
> - timeZones
> -     ^{
> -         self offset: 0 hours name: 'Universal Time' abbreviation: 'UTC'.
> -         self offset: 0 hours name: 'Greenwich Mean Time' abbreviation: 'GMT'.
> -         self offset: 1 hours name: 'Central European Time' abbreviation: 'CET'.
> -         self offset: 2 hours name: 'South African Standard Time' abbreviation: 'SAST'.
> -         self offset: -8 hours name: 'Pacific Standard Time' abbreviation: 'PST'.
> -         self offset: -7 hours name: 'Mountain Standard Time' abbreviation: 'MST'.
> -         self offset: -6 hours name: 'Central Standard Time' abbreviation: 'CST'.
> -         self offset: -5 hours name: 'Eastern Standard Time' abbreviation: 'EST'.
> -     }!
>
> Item was removed:
> - ----- Method: TimeZone class>>timeZonesDST (in category 'accessing') -----
> - timeZonesDST
> -     ^{
> -         self offset: 1 hours name: 'British Summer Time' abbreviation: 'BST'.
> -         self offset: 2 hours name: 'Central European Summer Time' abbreviation: 'CEST'.
> -         self offset: -7 hours name: 'Pacific Daylight Time' abbreviation: 'PDT'.
> -         self offset: -6 hours name: 'Mountain Daylight Time' abbreviation: 'MDT'.
> -         self offset: -5 hours name: 'Central Daylight Time' abbreviation: 'CDT'.
> -         self offset: -4 hours name: 'Eastern Daylight Time' abbreviation: 'EDT'.
> -     }!
>
> Item was changed:
> ----- Method: TimeZone>>abbreviation (in category 'accessing') -----
> abbreviation
>
> +     ^ self subclassResponsibility!
> -     ^ abbreviation!
>
> Item was removed:
> - ----- Method: TimeZone>>abbreviation: (in category 'accessing') -----
> - abbreviation: aString
> -
> -     abbreviation := aString!
>
> Item was changed:
> ----- Method: TimeZone>>name (in category 'accessing') -----
> name
>
> +     ^ self subclassResponsibility!
> -     ^ name!
>
> Item was removed:
> - ----- Method: TimeZone>>name: (in category 'accessing') -----
> - name: aString
> -
> -     name := aString!
>
> Item was changed:
> ----- Method: TimeZone>>offset (in category 'accessing') -----
> offset
> +     "Answer the current offset"
>
> +     ^ self offsetAt: DateAndTime basicNew initializeFromPrimitive
> -     ^ offset
> !
>
> Item was removed:
> - ----- Method: TimeZone>>offset: (in category 'accessing') -----
> - offset: aDuration
> -
> -     offset := aDuration
> - !
>
> Item was added:
> + ----- Method: TimeZone>>offsetAt: (in category 'accessing') -----
> + offsetAt: dateAndTime
> +
> +     ^ self subclassResponsibility
> + !
>
> Item was removed:
> - ----- Method: TimeZone>>printOn: (in category 'private') -----
> - printOn: aStream
> -
> -     super printOn: aStream.
> -     aStream
> -         nextPut: $(;
> -         nextPutAll: self abbreviation;
> -         nextPut: $)!
>
> Item was changed:
> + (PackageInfo named: 'Chronology-Core') postscript: '"Let all old instances of TimeZone become FixedTimeZone"
> + (Smalltalk globals removeKey: #TimeZoneInstances ifAbsent: [])
> +     ifNotNil: [ :instanceData |
> +         instanceData keysAndValuesDo: [ :instance :data | | newInstance |
> +             newInstance := FixedTimeZone
> +                 offset: data first
> +                 name: data second
> +                 abbreviation: data third.
> +             instance becomeForward: newInstance ]].
> + '!
> - (PackageInfo named: 'Chronology-Core') postscript: 'Smalltalk removeFromStartUpList: DateAndTime'!