Contents

designedbyclowns/timetravel

Re-anchor a Date to a new time zone — the underlying instant shifts so the wall-clock reading travels with it.

Usage

import TimeTravel

var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "America/Los_Angeles")!

let nyc = TimeZone(identifier: "America/New_York")!
let date = Date.explodingWhaleDay                        // 3:45 PM Pacific
let shifted = date.inTimeZone(nyc, calendar: calendar)!  // 3:45 PM Eastern

The calendar argument declares the source time zone — the frame in which date should be read. There's no default by design: Calendar.current would tie the result to the host machine, which is the non-determinism this library exists to avoid.

Anatomy of a date shift

To see what's actually happening, it helps to format the same date in two time zones with Date.FormatStyle:

let westCoastStyle = Date.FormatStyle(
    date: .complete,
    time: .complete,
    calendar: Calendar(identifier: .gregorian),
    timeZone: TimeZone(identifier: "America/Los_Angeles")!
)

let eastCoastStyle = Date.FormatStyle(
    date: .complete,
    time: .complete,
    calendar: Calendar(identifier: .gregorian),
    timeZone: TimeZone(identifier: "America/New_York")!
)

Format styles don't change the date — they only change how it's rendered. The same instant reads differently in each time zone:

let date = Date.explodingWhaleDay

westCoastStyle.format(date)
// "Thursday, 12 November 1970 at 3:45:00 PM GMT-8"

eastCoastStyle.format(date)
// "Thursday, November 12, 1970 at 18:45:00 EST"

To re-anchor the date so the wall-clock reading travels with it, use inTimeZone(_:calendar:):

let nyc = TimeZone(identifier: "America/New_York")!
let shifted = date.inTimeZone(nyc, calendar: calendar)!

date.timeIntervalSince1970     // 27,301,500
shifted.timeIntervalSince1970  // 27,290,700  (three hours earlier)

westCoastStyle.format(shifted)
// "Thursday, November 12, 1970 at 12:45:00 PM PST"

eastCoastStyle.format(shifted)
// "Thursday, November 12, 1970 at 3:45:00 PM EST"

The underlying instant moved by three hours, so the new wall-clock reading in NYC matches the original wall-clock reading in Florence, Oregon.

Why this isn't built in

Apple's TimeZone docs note that "Cocoa does not provide any API to change the time zone of the computer, or of other applications." Combined with Date's zone-less model, that makes deterministic time-zone shifts awkward — this library smooths over the gap.

Installation

Add the package as a dependency in your Package.swift file

let package = Package(
    name: "Foo",
    // name, platforms, products, etc.
    dependencies: [
        .package(url: "https://github.com/designedbyclowns/TimeTravel", .upToNextMinor(from: "0.1.0")),
    ],
    targets: [
        .target(name: "Foo", dependencies: [
            .product(name: "TimeTravel", package: "TimeTravel"),
        ]),
    ]
)

Further reading

Calendars and dates are full of edge cases that look obvious until they aren't. For a quick tour of the assumptions that quietly break — leap seconds, time zones that change offset, calendars that disagree on what year it is — see Your Calendrical Fallacy Is….

Package Metadata

Repository: designedbyclowns/timetravel

Default branch: main

README: README.md