Being overly clever with dates

To find out the distance, say in days, between two dates, call a calendar’s dateComponents(_:, from: , to:) method and pass it the unit you want to use. This call returns a DateComponents instance. You can then find out how many days fall between the two by looking at the returned instance’ property.

But what if you want to write a more general method that returns the distance for pretty much any unit you throw at it, whether it be days, minutes, seconds, or years?

Either you can write a really complex switch statement or you can build an extension for DateComponents that allows you to subscript using any Calendar.Component. (Essentially performing the exact same switch statement but as a built-in feature.) And that is, exactly what I did today.

Here are my distance functions, which use subscripting to access the component information after pulling the distance from the shared calendar:

static public func distance(_ date1: Date, 
    to date2: Date, 
    component: Calendar.Component) -> Int {
    return Date.sharedCalendar
        .dateComponents([component], from: date1, to: date2)[component] ?? 0

public func distance(to date: Date, 
    component: Calendar.Component) -> Int {
    return Date.sharedCalendar
        .dateComponents([component], from: self, to: date)[component] ?? 0

The subscripting itself, along with a full refresh of my NSDate (well, Date now) utilities can be found at my github repo. This has been one of my more popular (and personally neglected) repositories that dates back almost a decade and I’m happy to say I’ve cleaned it up quite a bit while updating it to Swift.

I’m using a much better way to calculate “same” (for example, same date or same week) by creating a canonical form from the dates and then comparing the canonical versions. For dates, that’s midnight at the start of the day. For weeks, it’s midnight at the start of the week. (update: Sebastian Celis points out the existence of compare(_ date1: Date, to date2: Date, toGranularity component: Component), which is part of swift-corelibs-foundation)

I’ve added in quite a lot of formatter and string options, and doing this in Swift is a pure delight. (It’s a pity playgrounds don’t let you code using gyb-nastics. There’s a lot of redundancy in my code.)

All the date offsets are now much cleaner, and completely migrated to date components (as they should have been years ago).

As always, if you want any requests or changes, ping me now while I’m paying attention to this because my primary interest is migration to Swift and not dates per se. And thanks in advance for any feedback.

Comments are closed.