# davedelong/time and the case for typed dates in Swift

> davedelong/time replaces loose calendar arithmetic with a set of Swift types whose precision is part of the type itself. It is a good fit for new scheduling, billing and logging code on macOS 13 and iOS 16 or later, and a poor fit for anything still deploying to older systems or anyone who needs time zone and daylight saving behaviour documented in the README today.

**davedelong/time** — Robust and type-safe date and time calculations for Swift

- Repository: https://github.com/davedelong/time
- Stars: 2,341 · Forks: 82
- Language: Swift
- License: MIT
- Published: 2026-09-30 · Updated: 2026-09-30 · Language: en
- Canonical page: https://hysenlabs.com/projects/davedelong-time

## Why Foundation's Date and Calendar are hard to use correctly

Foundation gives you two things that look like they should be enough. A `Date` is an instant on a timeline, and a `Calendar` projects that instant into fields such as year, month and day. Nothing in that pair stops you from adding forty days when you meant four weeks, from asking for a week of a month, or from comparing a value built with one calendar against a value built with another. Every one of those calls compiles. The damage shows up later, as a report that is off by one, an invoice that lands a day early, or a reminder that fires twice.

davedelong/time takes the opposite position. Rather than returning a bag of optional integers that a caller has to interpret, it returns a value whose precision is baked into its type. The library states this intent plainly in its description: it clarifies concepts and restricts improper usage through type-safe APIs. That makes it a library for the specific class of developer who schedules, bills, reports, or logs against wall-clock time and has been burned by calendar arithmetic, rather than for someone who needs a duration calculator.

## The precision ladder from RegionalClock down to Minute

The entry point is the device's `RegionalClock`, which you get through `Clocks.system`. From there the README describes a small vocabulary. `.today` returns the current calendar day. `.currentMinute` returns the current time accurate to the minute. Each of those returned values has methods that reach both outward and inward, so `today.hours` produces a sequence of every Hour value in the day, and a coarser unit can be narrowed as far as you need.

The interesting property is not the list of units but the direction of travel. From an instant you can always descend to a coarser unit, and the type system stops you from treating a Minute as though it were a Month. Formatting is uniform across the ladder through `.format(...)` methods, so code that prints a day and code that prints an hour do not need two different formatting paths.

One gap is worth naming. The clock is called `RegionalClock`, which hints that a clock is something you could construct rather than only read, but the README only shows the device's clock coming from `Clocks.system` and says nothing about creating an alternative one. Testing code that depends on the current time therefore has no documented seam in the README, and the hosted documentation is where to look for it.

## Adding the package to Package.swift and running the bundled examples

Installation is a single line in the `dependencies` array of `Package.swift`, copied exactly as the README gives it:

```swift
.package(url: "https://github.com/davedelong/time", from: "1.0.0")
```

That is the whole install procedure. There is no command-line installer, no CocoaPods podspec, and no Carthage step in the README. Because the constraint is written as `from: "1.0.0"`, SwiftPM is free to resolve up to the next major version, which today means release 1.0.3 published on 2026-08-26.

For a first real use, the README describes a short path. You take the device's `RegionalClock` from `Clocks.system`, ask it for `.today` to get the current calendar day, or ask it for `.currentMinute` when you need the time accurate to the minute. From the day you call `today.hours` to walk every Hour value in it. None of these values needs a format string to exist, and none of them returns an optional, which is the first thing you will notice when you move off `Date` and `DateComponents`.

The package itself ships no executable, so there is nothing to run from a terminal. What the repository does ship is an `Examples` folder containing `Examples/Examples.xcodeproj`, plus `Sources/` and `Tests/` at the top level, and the README says that folder contains code illustrating the core parts of the library. That Xcode project is the fastest way to see real usage. The long-form documentation is not in the repository: it is hosted at the Swift Package Index, which the README links twice and which the repository's `.spi.yml` file supports.

## The macOS 13 and iOS 16 floor is set by Duration

The README states the platform requirements in one line: Swift 5.7 or later, and macOS 13 or iOS 16, or an equivalent, or later. It then gives the reason, which is the detail that matters for planning. Core parts of the library are built on Swift's `Duration` type, and that type arrived in macOS 13 and iOS 16.

So the deployment target is a consequence of the implementation, not a conservative choice. Two costs follow. First, any app target that still supports iOS 15 or earlier cannot use the current line at all, and the release list (1.0.1, 1.0.2, 1.0.3) does not attach older platform notes to any of the earlier tags, so there is no documented fallback branch to pin to. Second, the Swift 5.7 language floor constrains which toolchain your CI image needs, which matters for teams that still build on an older Xcode.

The upside is a smaller surface. Because elapsed time is expressed with a standard-library type rather than a hand-rolled interval, the library does not have to define its own duration vocabulary, and comparisons between elapsed and calendar values do not need a conversion layer written by the package author.

## What the README leaves out about time zones and daylight saving

The README is short, and its silences are specific. It never mentions `TimeZone`, never names a `Calendar`, and never discusses what happens to a calendar day that contains twenty-three or twenty-five hours. `.today` returns the current calendar day, and `today.hours` returns a sequence of Hour values, but whether that sequence is guaranteed to have twenty-four members during a daylight saving transition is not stated anywhere in the README. Code that counts hours in a day and asserts the count will be the first place this shows up.

Other gaps are narrower but real. There is no mention of leap seconds, no note about non-Gregorian calendars, and no enumeration of what `.format(...)` accepts as its argument, so the formatting surface is defined entirely by the hosted documentation. There is also no guidance on migrating code that already holds a `Date` parsed from a stored string: the ladder is described as starting from the clock, and no example derives a Day or an Hour from an instant the library did not itself produce.

None of this makes the library unusable. It does mean the README alone is not enough to evaluate it for a codebase that cares about time zones, and the Swift Package Index documentation plus the `Examples` folder are the places to read before committing.

## How the type ladder differs from Calendar and DateComponents

The real alternative is the Foundation approach you probably already have: a `Date`, a `Calendar`, a `DateComponents` value, calls such as `date(byAdding:to:)` and `dateComponents(_:from:to:)`, and `Date.FormatStyle` for output. It is more capable in reach and much weaker in guarantees. Nothing stops you from populating a `DateComponents` with a month value and handing it to a week-based calendar; the call succeeds and the answer depends on which calendar instance you happened to pass. It is also easy to mix a fixed 86,400-second interval with calendar arithmetic in adjacent lines, which is precisely the class of mistake this package's types exist to close.

The difference in approach is that precision becomes part of the type rather than part of a parameter list. With Time, `today.hours` cannot be silently reinterpretted as a set of instants, and formatting is one uniform `.format(...)` call regardless of unit. The price is a smaller surface and unfamiliar behaviour: existing Foundation date code does not port mechanically, and a team that has internalised `Calendar` semantics will spend time relearning them.

There is one asymmetry worth weighing during a migration. Foundation lets you work from any `Date` you already hold. The README describes starting from a `RegionalClock` and does not show the path from an arbitrary instant into the library's units, so a codebase whose entry point is a parsed timestamp has an open question to answer in the hosted docs first.

## MIT licensing and an uneven release history

The repository is not archived, and the last push was on 2026-09-05, so work on it is current. The release history is less regular. Version 1.0.1 was published on 2024-03-10 and 1.0.2 on 2024-04-11, roughly a month apart, and then nothing until 1.0.3 on 2026-08-26. That is a gap of more than two years between the second and third tags, made more notable by the push days before it.

Two practical readings. First, the current tag is still 1.0.x, so the author is signalling additive work rather than a compatibility break, and a `from: "1.0.0"` requirement will pick up 1.0.3 and later 1.x tags. Second, the top-level entries are `.github/`, `.gitignore`, `.spi.yml`, `Examples/`, `LICENSE`, `Package.swift`, `README.md`, `Sources/` and `Tests/`. There is no `CHANGELOG.md` among them, so release notes live in GitHub releases, and the 1.0.3 notes are the only account of what changed after April 2024.

The licence is the MIT License, with the text at the repository root and a link to it from the README. That permits use in closed-source commercial products and requires the copyright notice to travel with copies. This is a reading of the licence text, not legal advice, and it is the least complicated part of adopting the package.

## Conclusion

Adopt davedelong/time for greenfield Swift code that reasons about calendar units and runs on macOS 13 or iOS 16 or later. Skip it if you must ship to older OS versions, or if you cannot accept that time zone and daylight saving behaviour are undocumented in the README. Before committing, read the Swift Package Index documentation for the formatting and time zone surface, run the bundled Examples project, and read the 1.0.3 release notes, since no tag appeared between 2024-04-11 and 2026-08-26.

## FAQ

### What are the platform requirements for davedelong/time?

The README states that davedelong/time requires Swift 5.7 or later and macOS 13, iOS 16, or an equivalent, or later. The reason given is that core parts of the library are built on Swift's Duration type, which was introduced in macOS 13 and iOS 16.

### How do I install davedelong/time in a Swift project?

Add one entry to the dependencies section of your Package.swift: .package(url: "https://github.com/davedelong/time", from: "1.0.0"). The README gives no other installation route, and points to the Swift Package Index for the full documentation.

### How do I get the current time with davedelong/time?

You obtain the device's RegionalClock through Clocks.system. The README shows that .today gives the current calendar day and .currentMinute gives the current time accurate to the minute, and that values like today can then be narrowed with .hours or widened as needed.

### Where are the examples and documentation for davedelong/time?

The long-form documentation is hosted at the Swift Package Index rather than kept in the repository, and the README links it twice. An Examples folder in the repository contains an Xcode project illustrating the core parts of the library.

### What licence is davedelong/time released under?

The README states that davedelong/time is licensed under the MIT License, and the repository's top level includes a LICENSE file that the README links to. The repository is not archived, and the last push was on 2026-09-05.

## Sources

- [davedelong/time on GitHub](https://github.com/davedelong/time)
- [Issues](https://github.com/davedelong/time/issues)
- [License: MIT](https://github.com/davedelong/time/blob/main/LICENSE)
- [README](https://github.com/davedelong/time/blob/main/README.md)
- [Releases](https://github.com/davedelong/time/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/davedelong-time
