Skip to content

Fix TimeZone initialization, exact offsets, and system abbreviation lookup - #95

Merged
marcprux merged 1 commit into
skiptools:mainfrom
shial4:main
Oct 4, 2026
Merged

marcprux merged 1 commit into
skiptools:mainfrom
shial4:main

Conversation

@shial4

@shial4 shial4 commented Feb 21, 2026 •

Copy link
Copy Markdown
Contributor

Unknown timezone identifiers currently fall back silently to GMT, abbreviation lookup has no default mappings, fixed offsets are passed to Java in the wrong units, and abbreviations always use the daylight-saving name. This PR fixes those behaviors in SkipFoundation. The relevant implementation remains unchanged in upstream main apart from its license header.

Changes

  • Reject unrecognized identifiers instead of accepting Java's GMT fallback. Abbreviation initialization uses the same validation and returns nil for missing or invalid custom mappings.
  • Generate the writable abbreviation dictionary from the system's available timezones, addressing the review request. Include standard names and daylight names for zones that use DST, using Locale.US so lookup keys do not depend on the device locale. Sort identifiers and retain the first match for deterministic collision handling. Ambiguous abbreviations can select a different region than Darwin Foundation; callers can override the dictionary.
  • Use java.util.TimeZone.getAvailableIDs() for both known timezone lists and dictionary generation, matching the initializer's provider. Android's java.time provider advertises aliases such as ACT that java.util.TimeZone rejects. Every advertised identifier must initialize successfully.
  • Validate fixed offsets within +/-18 hours and convert seconds to Java's milliseconds. Preserve partial-minute offsets with SimpleTimeZone; round only the display identifier to the nearest minute. For example, a 61-second offset remains 61 seconds. Zero uses the identifier GMT, preserving date-formatting behavior.
  • Select standard or daylight abbreviations using the supplied date.

Tests and verification

Add six regression tests covering invalid identifiers and valid GMT aliases, exact positive/negative offsets and bounds, winter/summer abbreviations, system-derived abbreviations, custom dictionary overrides, and fixed-offset use by Calendar and DateFormatter. Enable the existing Skip offset and abbreviation tests, check that both known timezone lists agree, and retain the check that every advertised identifier initializes.

The system abbreviation test uses the names supplied by the platform for Adelaide and Kathmandu. Android can supply GMT-offset names where desktop Java returns ACST/ACDT; the test verifies lookup of those names without assuming one timezone database's spelling. Integer-extreme rejection is tested on Skip because Darwin Foundation traps on those inputs.

  • skip test --filter TestTimeZone --filter TestCalendar: passed, 58 Swift tests and 44 Kotlin/Robolectric tests, with 14 existing Kotlin skips.
  • Android API 33 emulator: reproduced both failures from CI at 338a6e6 (ACT and missing ACST), then verified the fixes. TimeZone and Calendar pass: 44 Android tests, 14 existing skips; the same run passes 58 native Swift tests. TimeZone itself passes 18 Android tests with three existing skips.
  • CI at 338a6e6 passed Swift/Robolectric and connected iOS testing; Android API 28 failed on the two cases above. CI for 9abf44b reruns all checks, including API 28. Local emulator verification used API 33.
  • Full local swift test, including the Gradle harness, was executed. Eight native cases fail in DateTests, LocaleTests, TestDateFormatter, TestLengthFormatter, and TestNumberFormatter. Three Kotlin cases fail: BundleTests.testMainBundleInfo, TestDateComponents.testDateComponentsInitializationWithDate, and TestDateComponents.testDateComponentsWithSelectedComponents. All reproduce with the original PR's TimeZone implementation at d0b336d. The original implementation additionally fails Kotlin DateTests.testDateFormatting, which passes with this revision.
  • git diff --check: passed.

Local validation used Swift 6.4, Skip's Robolectric harness, and an Android API 33 emulator.

Contributor checklist

  • REQUIRED: I have signed the Contributor Agreement. shial4 is listed in the project's .clabot contributor list, and verification/cla-signed passes for 9abf44b.
  • REQUIRED: I have tested the change locally with swift test; results and existing failures are recorded above.
  • OPTIONAL: Tested on an iOS simulator or device through CI at 338a6e6; the latest CI rerun is linked above.
  • OPTIONAL: Tested on an Android API 33 emulator.
  • AI assisted this PR. Copilot assisted the original implementation. Codex revised the implementation, added regression tests, reviewed the complete diff and affected callers, compared behavior with Darwin Foundation, ran the tests above, and updated this description.

The PR contains one squashed commit, 9abf44b, authored by shial4, with AI assistance disclosed above.

@cla-bot

cla-bot Bot commented Feb 21, 2026

Copy link
Copy Markdown

Thank you for your pull request and welcome to the Skip community. We require contributors to sign our contributor license agreement (CLA), and we don't seem to have the user(s) @Copilot on file. In order for us to review and merge your code, for each noted user please add your GitHub username to Skip's .clabot file

Comment thread Sources/SkipFoundation/TimeZone.swift Outdated
}

public static var abbreviationDictionary: [String : String] = [:]
public static var abbreviationDictionary: [String : String] = [

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than hardwiring this, could we build it dynamically by getting all the system TimeZone.getAvailableIDs() and then calling tz.getDisplayName(false, TimeZone.SHORT) on each of them?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved

@cla-bot

cla-bot Bot commented Oct 4, 2026

Copy link
Copy Markdown

Thank you for your pull request and welcome to the Skip community. We require contributors to sign our contributor license agreement (CLA), and we don't seem to have the user(s) @Copilot on file. In order for us to review and merge your code, for each noted user please add your GitHub username to Skip's .clabot file

@shial4 shial4 changed the title TimeZone initialization and validation improvements Fix TimeZone initialization, exact offsets, and system abbreviation lookup Oct 4, 2026
shial4 added a commit to shial4/skip-foundation that referenced this pull request Oct 4, 2026
…ookup

AI assistance: Copilot assisted the initial implementation; Codex revised the implementation, added regression tests, and verified Swift and Kotlin behavior. See PR skiptools#95 for validation details and existing suite failures.
@cla-bot cla-bot Bot added the cla-signed label Oct 4, 2026
@shial4
shial4 requested a review from marcprux October 4, 2026 06:12
…ookup

AI assistance: Copilot assisted the initial implementation; Codex revised the implementation, added regression tests, and verified Swift and Kotlin behavior. See PR skiptools#95 for validation details and existing suite failures.
@marcprux
marcprux merged commit d7acb31 into skiptools:main Oct 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants