Categories

Once more, in Swift (or: A solution to day one of Advent of Code 2019)

As I wrote in the previous post, the Advent of Code is happening soon — it start on Tuesday, December 1st and runs all the way to December 25th. If you want to give your programming skills a good workout or test, you’ll want to try out Advent of Code’s challenges!

The previous post featured Python solutions to the day one challenges from the 2019 edition of Advent of Code. In this post, I’ll present solutions written in Swift.

Day one challenge, part one

Here’s the first part of day one’s challenge:

The Elves quickly load you into a spacecraft and prepare to launch.

At the first Go / No Go poll, every Elf is Go until the Fuel Counter-Upper. They haven’t determined the amount of fuel required yet.

Fuel required to launch a given module is based on its mass. Specifically, to find the fuel required for a module, take its mass, divide by three, round down, and subtract 2.

For example:

• For a mass of `12`, divide by 3 and round down to get `4`, then subtract 2 to get `2`.
• For a mass of `14`, dividing by 3 and rounding down still yields `4`, so the fuel required is also `2`.
• For a mass of `1969`, the fuel required is `654`.
• For a mass of `100756`, the fuel required is `33583`.

The Fuel Counter-Upper needs to know the total fuel requirement. To find it, individually calculate the fuel needed for the mass of each module (your puzzle input), then add together all the fuel values.

What is the sum of the fuel requirements for all of the modules on your spacecraft?

While the problems in the Advent of Code are the same for every participant, the data for each participant is different (there’s a sign-up process, which gives you an account, your own progress tracker, and your own data). This prevents participants from simply sharing the solution.

Here are the module masses that were provided for my account:

I used the Python REPL for my Python-based solution. For my Swift-based solution, I used the closest analogue: an Xcode Playground.

Swift, like Python uses the three quotes to denote multiline strings. I used them to define a multiline string constant, `rawInput`, into which I pasted the data:

With `rawInput` defined, it’s time to convert it from a multiline string into an array of strings, with each line getting turned into its own array element. The `String` class’ `split` method does this quite easily, and the result was the `splitInput` string array:

The next step was to convert `splitInput`’s numbers-in-string-form into actual numbers. This process would involve applying the same function — the `Int` struct’s “`init` from string” method — to all the elements in an array, which is exactly what the `map` method is for:

Swift’s `map` method takes a closure containing a function as its argument and applies that function to every item in the given array, creating a new array as its result.

In this case, the function in question is:

Parameters passed into the closure begin with the `\$` character, which is then followed by a number specifying which parameter it is. The first parameter is `\$0`, followed by the second parameter, `\$1`, followed by the third parameter, `\$2`, and so on.

Only one parameter is passed to the closure: `\$0`, which represents the current element of the `splitInput` array. It’s fed into the `init` method of `Int` that takes a string and attempt to produce an integer. Since it’s possible that this method will be given a string that can’t be converted into an integer, the method’s return type is the optional type `Int?`.

Since I’m quite certain that all the strings in the `splitInput` array convert to integers, I used the ! operator to force unwrap the resulting `Int?` values.

The end result is `masses`, an array of integers. Each element in the array represents the mass of a component in the ship, and we need to calculate the fuel necessary to propel each component to the final destination.

This calculation involves applying a function to every element in `masses`, and that function is:

• Divide the mass by 3, rounding down.
• Subtracting 2 from the result above.

Once again, I used `map`:

In the function above, `mass` and `3` are both integers, so `mass / 3` is an integer division, which automatically rounds down.

The result of this `map`ping is `fuelRequirements`, an array of integers containing the fuel requirements for each module.

The result is the sum of all the values in `fuelRequirements`. Unfortunately, Swift doesn’t have a built in method for getting the sum of an array, so we’ll need to roll our own:

For my data, the result was 3454942. This turned out to be correct, so it was time to tackle part two.

Day one challenge, part two

Part two involved recalculating the fuel requirements when also taking into account the mass of the added fuel:

During the second Go / No Go poll, the Elf in charge of the Rocket Equation Double-Checker stops the launch sequence. Apparently, you forgot to include additional fuel for the fuel you just added.

Fuel itself requires fuel just like a module – take its mass, divide by three, round down, and subtract 2. However, that fuel also requires fuel, and that fuel requires fuel, and so on. Any mass that would require negative fuel should instead be treated as if it requires zero fuel; the remaining mass, if any, is instead handled by wishing really hard, which has no mass and is outside the scope of this calculation.

So, for each module mass, calculate its fuel and add it to the total. Then, treat the fuel amount you just calculated as the input mass and repeat the process, continuing until a fuel requirement is zero or negative. For example:

• A module of mass `14` requires `2` fuel. This fuel requires no further fuel (2 divided by 3 and rounded down is `0`, which would call for a negative fuel), so the total fuel required is still just `2`.
• At first, a module of mass `1969` requires `654` fuel. Then, this fuel requires `216` more fuel (`654 / 3 - 2`). `216` then requires `70` more fuel, which requires `21` fuel, which requires `5` fuel, which requires no further fuel. So, the total fuel required for a module of mass `1969` is `654 + 216 + 70 + 21 + 5 = 966`.
• The fuel required by a module of mass `100756` and its fuel is: `33583 + 11192 + 3728 + 1240 + 411 + 135 + 43 + 12 + 2 = 50346`.

What is the sum of the fuel requirements for all of the modules on your spacecraft when also taking into account the mass of the added fuel? (Calculate the fuel requirements for each module separately, then add them all up at the end.)

This called for a recursive function, the Swift code for which is below:

I used this function to `map` the values in the `masses` array from part one onto a new array, `updatedFuelRequirements`

…and the sum of its the elements was the answer for part two:

For my data, the answer was 5179544.

Categories

Converting a number from a numeric form into words in just four lines of Swift

Until I started working on a video tutorial for Apple’s Combine framework (coming soon to raywenderlich.com!), I had no idea that this existed.

Open a Swift playground in Xcode and enter the following code:

Run the playground code, and you’ll see this:

87654 spelled out is eighty-seven thousand six hundred fifty-four.

Having come from the world of C, where you format strings using `printf()` and formatting strings, and later from other languages where you use whatever formatting method its string class provides, I’ve ignored most of Swift’s classes that derive from `Formatter` — with one notable exception: `DateFormatter`, which is indispensable when working with dates and times.

I’m now looking for an excuse to use this capability.

As I typed “DateFormatter” a couple of paragraphs above, I remembered that `DateFormatter` had a `locale` property. It’s for ensuring that any dates you present are in the correct form for the locale:

I wondered:

• Does `NumberFormatter` have a `locale` property?
• What happens if I changed it to something other than my system’s default of US English?

So I changed the code in my playground to the following:

I ran the code and saw this…

87654 spelled out in Filipino is walóng pû’t pitóng libó’t anim na daán at limáng pû’t ápat.

…and my response was “Ay nako!” (translation: OMG!)

The output:

87654 spelled out in Korean is 팔만 칠천육백오십사.

My response: 세상에 (“Sesange!”, which is pretty much Korean for OMG!)

Try it out!  You might find this list of iOS locale string identifiers useful.

Categories

Dates and times in Swift 5, part 4: Adding Swift syntactic magic

In this article, we’ll expand on material covered in the three previous articles in this series on working with dates and times in Swift 5:

A more readable way to work with `Date`s and `DateComponents`

Suppose we want to find out what the date and time will be 2 months, 3 days, 4 hours, 5 minutes, and 6 seconds from now will be.

If you recall what we covered in the last installment in this series, you’d probably use code like this:

In the code above, we did the following:

• We created an instance of a `DateComponent`s struct.
• We set its properties so that it would represent a time interval of 2 months, 3 days, 4 hours, 5 minutes, and 6 seconds.
• We then used `Calendar`‘s `date(byAdding:to:)` method to add the time interval to a `Date`.

This code wouldn’t look out of place in a lot of other programming languages, but we can do better in Swift. What if I told you that by defining a few helper functions, you can turn the code above into the code below?

Or this code?

I’d much rather write the code above. This article will cover the code necessary to make this kind of syntactic magic possible.

Overloading `+` and `-` so that we can add and subtract `DateComponents`

First, let’s write some code that allows us to add and subtract `DateComponents`. Start a new playground and enter the following code into it:

In the code above, we’ve overloaded the `+` and `-` operators so that we can add and subtract `DateComponents`. I derived these functions from Axel Schlueter’s SwiftDateTimeExtensions library. He wrote them when Swift was still in beta; I updated them so that they compile with the current version and added a couple of tweaks of my own.

The addition and subtraction operations are so similar and so tedious, which is a sign that there’s an opportunity to DRY up the code. I factored out the duplicate code from both the `+` and `-` overloads and put it into its own method, `combineComponents`, which does the actual `DateComponents` addition and subtraction.

You may have noticed a lot of `??` operators in the code for `combineComponents`. `??` is referred to as the nil coalescing operator, and it’s a clever bit of syntactic shorthand. For the expression below:

`let finalValue = someOptionalValue ?? fallbackValue`

• If `someOptionalValue` is not `nil`, `finalValue` is set to `someOptionalValue`‘s value.
• If `someOptionalValue` is `nil`, `finalValue` is set to `fallbackValue`‘s value.

Let’s confirm that our new operator overloads work. Add the following to the playground and run it:

You should see the following output:

1 day, 5 hours, and 10 minutes + 3 days, 10 hours, and 30 minutes equals:
4 days, 15 hours, and 40 minutes.
1 day, 5 hours, and 10 minutes – 3 days, 10 hours, and 30 minutes equals:
2 days, 5 hours, and 20 minutes.

Overloading `-` so that we can negate `DateComponents`

Now that we can add and subtract `DateComponents`, let’s overload the unary minus so that we can negate `DateComponents`:

With this overload defined, we can now use the unary minus to negate `DateComponents`. Add the following to the playground and run it:

You should see the following output:

Negating 1 day, 5 hours, and 10 minutes turns it into:
-1 days, -5 hours, and -10 minutes.

Overloading `+` and `-` so that we can add `Date`s and `DateComponents` and subtract `DateComponents` from `Date`s

With the unary minus defined, we can now define the following operations:

• `Date + DateComponents`, which makes it easier to do date arithmetic.
• `DateComponents + Date`, which should be possible because addition is commutative (which is just a fancy way of saying that a + b and b + a should give you the same result).
• `Date - DateComponents`, which once again makes it easier to do date arithmetic.

Note that we didn’t define an overload for calculating `Date - DateComponents` — such an operation doesn’t make any sense.

With these overloads defined, a lot of `Date`/`DateComponents` arithmetic in Swift becomes much easier to enter and read. Add the following to the playground and run it:

On my computer, the output looked like this:

Date() + oneDayFiveHoursTenMinutes = Friday, May 29, 2020 at 3:20:54 PM Eastern Daylight Time
oneDayFiveHoursTenMinutes + Date() = Friday, May 29, 2020 at 3:20:54 PM Eastern Daylight Time
Date() – threeDaysTenHoursThirtyMinutes = Sunday, May 24, 2020 at 11:40:54 PM Eastern Daylight Time

Extending `Date` so that creating dates and debugging are simpler

Creating `Date`s in Swift is a roundabout process. Usually, you end up creating them in one of two ways:

• Instantiating a `DateComponents` struct and then using it to create a `Date` using `Calendar`‘s `date(from:)` method, or
• Creating a `String` representation of the `Date` and then using it to create a `Date` using `DateFormatter`‘s `date(from:)` method.

Let’s simplify things by extending the `Date` struct with a couple of convenient `init` method overloads. Let’s also make it easier to print out the value of a `Date` for debugging.

Add the following to the playground:

With these methods, initializing `Dates` is a lot more simple. Add the following to the playground and run it:

On my computer, the output looked like this:

iPhoneStevenoteDate: Tuesday, January 9, 2007 at 1:00:00 PM Eastern Standard Time
iPhoneReleaseDate: Tuesday, June 26, 2007 at 8:00:00 PM Eastern Daylight Time
iPadStevenoteDate: Wednesday, January 27, 2010 at 1:00:00 PM Eastern Standard Time

Overloading `-` so that we can use it to find the difference between two `Date`s

When we’re trying to determine the time between two given `Date`s, what we’re doing is finding the difference between them. Wouldn’t it be nice if we could use the `-` operator to find the difference between `Date`s, just as we can use it to find the difference between numbers?

Let’s code an overload to do just that. Add the following to the playground:

Let’s test it in action. Add the following to the playground and run it:

On my computer, the output looked like this:

The first iPhone users had to wait this long:
0 years, 5 months, 2 weeks, 3 days, 7 hours, and 0 minutes.
It’s been this long since the first moon landing:
50 years, 10 months, 1 weeks, 0 days, 18 hours, and 22 minutes.

Extending `Int` to add some syntactic magic to date components

We’ve already got some syntactic niceties, but the real Swift magic happens when we add this code to the mix. Add the following to the playground:

This additions to `Int` allow us to convert `Int`s to `DateComponents` in an easy-to-read way, and with our overloads to add and subtract `DateComponents` to and from each other, and to add `Date`s to `DateComponents`, we can now perform all sorts of syntactic magic like this (add the following to the playground and run it):

On my computer, the output looked like this:

One hour from now is: Thursday, May 28, 2020 at 11:57:49 AM Eastern Daylight Time
One day from now is: Friday, May 29, 2020 at 10:57:49 AM Eastern Daylight Time
One week from now is: Thursday, June 4, 2020 at 10:57:49 AM Eastern Daylight Time
One month from now is: Sunday, June 28, 2020 at 10:57:49 AM Eastern Daylight Time
One year from now is: Friday, May 28, 2021 at 10:57:49 AM Eastern Daylight Time
10 years, 9 months, 8 days, 7 hours, and 6 minutes ago, it was: Thursday, August 20, 2009 at 3:51:49 AM Eastern Daylight Time

Extending `DateComponents` to add even more syntactic magic: `fromNow` and `ago`

And finally, a couple of additions to the `DateComponents` struct to make `Date`/`DateComponent` calculations even more concise and readable. Add these to the playground:

Let’s try them out! Add these to the playground and run them:

On my computer, the output looked like this:

2.weeks.fromNow: Thursday, June 11, 2020 at 11:03:36 AM Eastern Daylight Time
3.months.fromNow: Friday, August 28, 2020 at 11:03:36 AM Eastern Daylight Time
futureDate3: Friday, July 31, 2020 at 3:08:42 PM Eastern Daylight Time
pastDate2: Wednesday, March 25, 2020 at 6:58:30 AM Eastern Daylight Time

Wrapping it all up

Here’s the playground containing all the code we just worked with:

The How to work with dates and times in Swift 5 series

Here are the articles in this series:

Categories

What we’ve covered so far, and what we’ll cover in this installment

So far, in this series on programming with dates and times in Swift 5, we’ve looked at:

With this knowledge under our belts, let’s get to this article’s topic: doing date calculations.

Creating a couple of `Date`s to work with

Let’s create a couple of `Date`s to work with:

• The date and time of the Stevenote where the iPhone was introduced: January 9, 2007, 10:00 a.m. Pacific time (UTC-8), and
• The date and time of the Stevenote where the iPad was introduced: January 27, 2010, 10:00 a.m. Pacific time (UTC-8).

Start with a fresh playground, and paste or enter the following code into it:

In the code above, we’ve created our dates in two different ways:

• We created `iPhoneStevenoteDate` by setting up a `DateComponents` struct and then using the user’s `Calendar` to convert those `DateComponents` into a `Date`.
• We created `iPadStevenoteDate` by converting its `String` representation into a `Date` using a `DateFormatter`.

`Date` comparisons, part 1

Now that we have two `Date`s, let’s compare them. In Swift 5, we can use familiar comparison operators — `<``<=``==``!=``>``>==` — to tell which `Date` came first, or if they represent the exact (and I do mean exact) same point in time.

Add the following code to the playground and run it:

The output should be:

Did the iPhone Stevenote come BEFORE the iPad Stevenote? true
Did the iPhone Stevenote come AFTER the iPad Stevenote? false
Did the iPad Stevenote come BEFORE the iPhone Stevenote? false
Does the iPad Stevenote come AFTER the iPhone Stevenote? true
Do the iPhone Stevenote and the iPad Stevenote fall on the EXACT SAME date and time? false
Do the iPhone Stevenote and the iPad Stevenote fall on different dates and times? true

Note that these are comparisons of `Date`s, which measure time down to the nearest nanosecond. If you compare two `Date`s named `date1` and `date2`, where `date2` represents a point in time one nanosecond after `date1`, they will not be equal; `date2` will be greater than `date1`.

A little later on in this article, we’ll look at more “human” ways of comparing `Date`s.

How far apart are the iPhone and iPad Stevenotes, part 1: In seconds, using `Date`’s `timeIntervalSince()` method

`Date`‘s `timeIntervalSince` method can give us the difference between two dates and times — in seconds.

Add the following code to the playground and run it:

The output should be:

Number of seconds between the iPhone Stevenote and the iPad Stevenote: -96249600.0
Number of seconds between the iPad Stevenote and the iPhone Stevenote: 96249600.0

The results tell us that there were 96,248,600 seconds between the iPhone Stevenote and the iPad Stevenote.

While there are cases when you’ll want to know how many seconds there are between two given points in time, there are also many cases where you’ll want to find the differences between two points in time using other units, such as days, weeks, months, and years, not to mention hours and minutes. `Date`‘s `timeIntervalSince` method isn’t going to work for these cases.

How far apart are the iPhone and iPad Stevenotes, part 2: In days, using `Calendar`’s `dateComponents(_:from:to:)` method

Most of the time, when you are calculating how far apart two given `Date`s are, you’ll be using this method of the `Calendar` struct:

`dateComponents(components, from: startDate, to: endDate)`

Here’s a run-down of its parameters:

Parameter Description
`components` `Set` (expressed in array notation) of `Calendar.Component` values specifying the time units you want, which can be:

• `.second`
• `.minute`
• `.hour`
• `.day`
• `.month`
• `.year`
`startDate:` The start `Date` of the time period.
`endDate:` The end `Date` of the time period.

Let’s use `dateComponents(_:from:to:)` to find out how many days there were between the iPhone Stevenote and the iPad Stevenote.

Add the following code to the playground and run it:

The output should be:

There were 1114 days between the iPhone Stevenote of 2007 and the iPad Stevenote of 2010.

In the code above, we passed `dateComponents(_:from:to:)` three values:

• An array containing the `Calendar.Component` value `.day`, which specifies that we want the result expressed as the difference between `iPadStevenoteDate` and `iPhoneStevenoteDate` in terms of days.
• The two dates in question, `iPhoneStevenoteDate` and `iPadStevenoteDate`.

As the result tells us, there were 1,114 days between the iPhone Stevenote and the iPad Stevenote.

How far apart are the iPhone and iPad Stevenotes, part 3: In weeks

By changing the contents of the array of `Calendar.Component` values that we provide in the first argument of `Calendar`’s `dateComponents(_:from:to:)` method, we can get the result expressed in different time units.

Add the following code to the playground and run it:

The output should be:

There were 159 weeks between the iPhone Stevenote of 2007 and the iPad Stevenote of 2010.

In the code above, we passed `dateComponents(_:from:to:)` three values:

• An array containing the `Calendar.Component` value `.weekOfYear`, which specifies that we want the result expressed as the difference between `iPadStevenoteDate` and `iPhoneStevenoteDate` in terms of the numbered weeks of the year on which both dates fall. For example, if event1 took place on week 2 of a year and event2 took place on week 5, the difference between the two in `.weekOfYear` terms would be 3.
• The two dates in question, `iPhoneStevenoteDate` and `iPadStevenoteDate`.

The result indicates that 159 weeks passed between the iPhone Stevenote and the iPad Stevenote.

If you do the math, 159 times 7 days is 1,113 days, but our previous calculation said that the iPhone Stevenote and the iPad Stevenote were 1,114 days apart. That’s because the two events are 159 whole weeks apart, plus an extra day.

How far apart are the iPhone and iPad Stevenotes, part 4: In years, months, and days

We can also put multiple values of `Calendar.Component` into the array that we provide as the first argument of `Calendar`’s `dateComponents(_:from:to:)` method.

Add the following code to the playground and run it:

In the code above, we passed `dateComponents(_:from:to:)` three values:

• An array containing the `Calendar.Component` values `.year, .month, .day, .hour, .minute`, which specifies that we want the result expressed as the difference between `iPadStevenoteDate` and `iPhoneStevenoteDate` in terms of years, months, days, hours, and minutes. The method uses the largest applicable component before using smaller ones — for example, it will give results like 1 month and 5 days rather than 35 days.
• The two dates in question, `iPhoneStevenoteDate` and `iPadStevenoteDate`.

The results show that the iPhone Stevenote and the iPad Stevenote were 3 years and 18 days apart.

`Date` addition, part 1: What’s the last day of a 90-day warranty that starts today?

Now that we know how to answer the question “What’s the difference in time between two `Date`s?”, let’s try answering a different question: “If we add a time interval to a `Date`, what’s the resulting `Date`?”

To answer this question, we’ll use this method of `Calendar`:

`date(byAdding: timeInterval, value: numberOfTimeUnits to: startDate)`

Here’s a run-down of its parameters:

Parameter Description
`timeInterval` `dateComponents` struct whose properties contain values defining the interval of time.
`numberOfTimeUnits` The number of `timeInterval` units to be added to the `Date` in question.
`startDate` The `Date` in question.

Let’s start with a simple bit of code that tells us the last day of a 90-day warranty whose term starts right now:

The result is a `Date` representing a point in time 90 days from the present. On my computer, the output looked like this:

90 days from now is: Optional(“Tuesday, August 25, 2020 at 10:30:46 PM Eastern Daylight Time”)

`Date` addition, part 2: What was the date 5 weeks ago?

Just as we can convert addition to subtraction by adding a negative value, we can also do `Date` subtraction by providing `date(byAdding:value:to:)` with negative values. Here’s an example of code that returns a date that is an interval of time prior to the date in question:

The result is a `Date` representing a point in time 5 weeks in the past. On my computer, the output looked like this:

5 weeks ago was: Wednesday, April 22, 2020 at 11:12:40 PM Eastern Daylight Time

`Date` addition, part 3: What time will it be 4 hours and 30 minutes from now, and 4 hours and 30 minutes ago?

The `date(byAdding:value:to:)` method works when you just want to add one kind of time unit — a minute, hour, day, week, month, or year — to a `Date`. If you want to add multiple kinds of time units to a `Date`, such as 4 hours and 30 minutes, you need to use this `Calendar` method instead:

`date(byAdding: timeIntervalComponents, to: startDate)`

Here’s a run-down of its parameters:

Parameter Description
`timeIntervalComponents` `dateComponents` struct whose properties contain values defining the interval of time.
`startDate` The `Date` in question.

Here’s the code that answers the question “What time will it be 4 hours and 30 minutes from now?”

In the code above, we did the following:

• First, we defined a `DateComponents` struct representing a 4-hour, 30-minute span of time,
• then we added that span of time to the present date and time using the `date(byAdding:to:)` method.

The result is a `Date` representing a time 4 hours and 30 seconds in the future.

Let’s find out what the `Date` was 4 hours and 30 seconds ago:

On my computer, the output looked like this:

4 hours and 30 minutes from now will be: Thursday, May 28, 2020 at 3:42:40 AM Eastern Daylight Time
4 hours and 30 minutes ago was: Thursday, May 28, 2020 at 3:42:40 AM Eastern Daylight Time

Date comparisons, part 2: Making Date comparisons a little more “human”

One recurring theme in science fiction (and especially in Star Trek) is the tendency for ultra-smart characters and computers to be overly, needlessly, pointlessly precise. The writers for the original series often did this with Spock, and it seemed that at least a few writers were aware of this annoying trope in later series. Here’s a bit of dialogue from The Next Generation:

Data: 6 days, 13 hours, 47 minutes.
Riker: What, no seconds?
Data: I have discovered, sir, a certain level of impatience when I calculate a lengthy time interval to the nearest second. [beat] However if you wish…
Riker: No. No. Minutes is fine.

`Date`‘s comparison operators have the same problem with being overly precise.

Consider the following `Date`s related to the announcement of SwiftUI:

• The start of the announcement, 2 hours and 8 minutes into the WWDC 2019 keynote: June 3, 2019, 12:08:00 p.m. PDT
• One second after the start of the announcement: June 3, 2019, 12:09:00 p.m. PDT
• Five minutes after the start of the announcement: June 3, 2019, 12:13:00 p.m. PDT
• Three hours after the start of the announcement: June 3, 2019, 03:08:00 p.m. PDT

`Date`‘s comparison operators think of all these points in time as very different, but depending on your circumstances you may think of them as being practically the same:

• In most cases, there really isn’t a difference between the time when SwiftUI was announced and one second after.
• If you’re concerned only with the day when SwiftUI was announced and not the exact time, there’s effectively no difference between any of the `Date`s listed above.

`Calendar`‘s `compare(_:to:toGranularity)` method allows us to perform `Date` comparisons at different levels of granularity:

`compare(firstDate, to: secondDate, toGranularity: granularity)`

Here’s a run-down of its parameters:

Parameter Description
`firstDate` The first `Date` in the comparison.
`secondDate` The second `Date` in the comparison.
`granularity` The level of precision for the comparison, expressed as an `Calendar.Component` value, which includes:

• `.second`
• `.minute`
• `.hour`
• `.day`
• `.month`
• `.year`

This is a Cocoa method named “compare”, so you’ve probably guessed that its return type is `ComparisonResult`. Here’s what it returns:

If… `compare` returns:
`firstDate` is earlier than `secondDate`, when compared at the specified granularity `.orderedAscending`
`firstDate` is equal to `secondDate`, when compared at the specified granularity `.orderedSame`
`firstDate` is later than `secondDate`, when compared at the specified granularity `.orderedDescending`

It’s easier to show `compare(_:to:toGranularity)` in action than to explain how it works. Add the following code into the playground:

The output should be:

test1: false
test2: true
test3: true
test4: true
test5: true
test6: true

Wrapping it all up

Here’s the playground containing all the code we just worked with:

In the next installment, we’ll look at making working with dates and times in Swift 5 even better with with some syntactic magic.

The Dates and times in Swift 5 series

Here are the articles in this series:

Categories

Dates and times in Swift 5, part 2: Formatting and parsing dates and times

In the previous article in this series on working with dates and times in Swift 5, we looked at three key structs for date and time programming in Swift:

• `Date` represents a single point in time, using a format that can easily be translated into just about any calendar and time-reckoning system: a number of seconds relative to the start of the Third Millennium (January 1, 2001, 00:00:00 UTC).
• `DateComponents` specifies time units like year, month, day, hour, minute, and more to represent either a point in time or a duration of time.
• `Calendar` provides a context for `Date`s, and converts `Date`s to `DateComponents` and `DateComponents` to `Date`s.

These structs all deal with the internal representation of dates and times in Swift 5.

In this article, we’ll look at the `DateFormatter` class, which allows us to deal with the  external representation of dates and times in Swift 5 as strings to be presented to the user. We use this class to convert `Date`s into formatted `String`s that match the user’s language and locale, and properly-formatted `String`s into `Date`s.

Tap the image to see it at full size.

We’ve already used the `Date` struct’s `description` property and `description(with:)` method to print its value in a human-readable form, but they’re meant for debugging purposes only, and not for presenting date and time information to the user. When presenting dates to the user in string form, use strings that have been created by `DateFormatter`.

Let’s convert a `Date` into a `String`, part 1: Just the date

Start a new playground and enter the following code, which gives us a `Date` that we can format — June 2, 2014, the day when the Swift programming language was first released:

This code is similar to code we entered in the previous article:

1. Get the user’s current `Calendar`.
2. Create a `DateComponents` struct, `swiftDebutDateComponents`, providing the `year:``month:`, and `day:` parameters that correspond to the date June 2, 2014.
3. Use the user’s `Calendar` to create `swiftDebutDate` using `swiftDebutDateComponents`.

Let’s try turning this date into a string with a `DateFormatter`.

Add the following to the playground, then run it:

The output should look like this:

Swift’s debut date, via the DateFormatter:

You may be surprised that the result is an empty `String`. That’s because you need to specify a `dateStyle`, which specifies which pre-defined format should be used for the date. We’ll start with the `short` style.

Add the following to the playground, then run it:

The output should look like this:

Swift’s debut date, “short” style: 6/2/14.

Let’s try the other styles: `medium`, `long`, `full`, and `none`.

Add the following to the playground, then run it:

The output should look like this:

Swift’s debut date, “medium” style: Jun 2, 2014.
Swift’s debut date, “long” style: June 2, 2014.
Swift’s debut date, “full” style: Monday, June 2, 2014.
Swift’s debut date, “none” style: .

If turns out that the default `dateStyle` is `none.` Why would there be a `dateStyle` called `.none`? I’ll explain in the next section.

Let’s convert a `Date` into a `String`, part 2: A date and a time

Let’s create a date and approximate known time: When SwiftUI was announced at WWDC 2019. It’s introduced 2 hours and 8 minutes into a keynote that started at 10:00 a.m. Pacific Daylight Time, so we’ll say it debuted at 12:08 p.m. PDT on June 3, 2019.

Add the following to the playground, then run it:

On my computer, the output looked like this:

The newly-created date: Monday, June 3, 2019 at 3:08:00 PM Eastern Daylight Time.

The date and time you’ll see will be determined your system calendar settings.

Now that we have a date and time, let’s format it using the `dateStyle` property to style the date part, and `timeStyle` property to style the time part.

Add the following to the playground, then run it:

On my computer, the output looked like this:

Swift’s debut date and time, “short” style: 6/3/19, 3:08 PM.
Swift’s debut date and time, “medium” style: Jun 3, 2019 at 3:08:00 PM.
Swift’s debut date and time, “long” style: June 3, 2019 at 3:08:00 PM EDT.
Swift’s debut date and time, “full” style: Monday, June 3, 2019 at 3:08:00 PM Eastern Daylight Time.

You can mix and match `dateStyle` and `timeStyle` settings. Add the following to the playground, then run it:

On my computer, the output looked like this:

Swift’s debut date and time, with “full” style date and “short” style time: Monday, June 3, 2019 at 3:08 PM.

Now that we’re working with a date and time, I can tell you what the `.none` style is for: for suppressing the display of the date or time in a formatted date string.

Add the following to the playground, then run it:

Remember that the `Date` struct represents a single point in time, which has both a date and a time. The `.none` style for `DateFormatter`‘s `dateStyle` and `timeStyle` properties allows us to create a `String` representation of a `Date` that shows only its date or time part.

This table summarizes the different `dateStyle` and `timeStyle` settings for the US English language setting:

 Setting dateStyle timeStyle `.none` [ empty string ] [ empty string ] `.short` 6/3/19 3:08 PM `.medium` Jun 3, 2019 3:08:00 PM `.long` June 3, 2019 3:08:00 PM EDT `.full` Monday, June 3, 2019 3:08:00 PM Eastern Daylight Time

Let’s convert a `Date` into a `String`, part 3: Displaying dates and times in other languages

`DateFormatter` defaults to the user’s preferred language, as specified in their settings. In my case, that’s US English. By setting the `locale` property of the `DateFormatter`, I can specify the language for my formatted date strings. Add the following to the playground, then run it:

On my computer, the output looked like this:

International French: lundi 3 juin 2019 à 15:08:00 heure d’été de l’Est.
Canadian French: lundi 3 juin 2019 à 15:08:00 heure avancée de l’Est.
Croatian: ponedjeljak, 3. lipnja 2019. u 15:08:00 (istočno ljetno vrijeme).
Korean: 2019 6 3 월요일 오후 3 8 0 동부 하계 표준시.

Let’s convert a `Date` into a `String`, part 4: Custom date/time formats

In addition to the built-in formats for dates, you can tell `DateFormatter` to use a custom format.

Before we begin working with custom date/time formats, I should point out that if you need to display a `Date` as a `String` to the user, it’s best if you use Swift’s built-in `dateStyle` and `timeStyle` values. They display dates and times properly, according to the user’s settings, which include country and language. You’d be surprised how date formats differ from culture to culture, and it’s better to let Swift do the formatting work.

However, there are times when you need to format dates and times in a specific way that doesn’t match the styles provided by `DateFormatter`’s `dateStyle` and `timeStyle` properties, such as when dealing with certain APIs. That’s where `DateFormatter`’s `dateFormat` property comes in handy.

To be certain that the `DateFormatter` will use your custom date format, set its `locale` property to POSIX, then define the custom date format string in `dateFormat`.

Add the following to the playground, then run it:

You can use the date format specifiers listed in Appendix F of the Unicode Technical Standard #35 to define the formatting `String` for the `dateFormat` property. Here are some examples (Add the following to the playground, then run it):

Let’s convert a `String` into a `Date`

`DateFormatter` works the other way — just as it can convert `Date`s to `String`s, it can also convert `String`s to `Date`s. By setting its `dateFormat` to the format of the `String` it should expect, you can use its `date(from:)` method to convert a `String` into a `Date`.

Once again, use the date format specifiers listed in Appendix F of the Unicode Technical Standard #35 to define the formatting `String` for the `dateFormat` property.

Add the following to the playground, then run it:

On my computer, the output looked like this:

newDate1’s value is: 2019-06-03 07:08:00 +0000.
newDate2’s value is: nil.

Let’s change the `dateFormat` string and try it again. Add the following to the playground, then run it:

On my computer, the output looked like this:

newDate3’s value is: nil.
newDate4’s value is: 2019-06-06 19:08:00 +0000.

If you’re trying to parse a weird date format, use a weird date format string. Add the following to the playground, then run it:

On my computer, the output looked like this:

weirdEmojiDate’s value is: 2020-11-28 05:00:00 +0000.

Wrapping it all up

Here’s the complete code for the playground containing all the code we just worked with:

In the next installment on dates and times in Swift 5, we’ll look at date calculations.

The How to work with dates and times in Swift 5 series

Here are the articles in this series:

Categories

Dates and times in Swift 5, part 1: Creating and deconstructing dates and times

If you’re just getting started with programming dates and times in Swift 5, you probably looked at Apple’s documentation and got confused. Let me reassure you that it isn’t your fault. For starters, Apple’s documentation hasn’t been very good lately, and I’m not the only developer who’s noticed this decline in quality.

There’s also the fact that working with dates and times in Swift 5 seems unnecessarily complicated. If you’ve come to Swift from other programming languages, such as JavaScript, which uses a single object type called `Date`, the idea of having this set of classes just to handle dates and times looks like overkill:

I promise you that there’s a method to this madness. The set of structs for working with dates and times in Swift 5 make for a super-flexible system that will let you keep store, calculate, and display dates and times no matter what time zone, calendar system, or language you use.

For example, with Swift, I can easily schedule an appointment for the third Wednesday of July at 3:30 p.m. Pacific and then display that date as it would appear in the Coptic Calendar system in Melbourne, Australia. If you had to do that in JavaScript, the only easy answer is “go away” (there are, of course, some less polite variations of that answer).

This series, Dates and times in Swift 5, will help you make sense of the set of classes that Swift provides for dealing with timekeeping and time calculations. It will do so with a lot of examples and experimentation. I strongly recommend that you fire up Xcode, open a Swift playground, and follow along.

• The `Date` struct, which stores date and times in Swift 5.
• The `Calendar` struct, which represents one of 16 different calendar systems, and provides a meaningful context for `Date`s.
• The `DateComponents` struct, which a collection of date and time components, such as years, months, days, hours, minutes, and so on.
• How to create a `Date` object representing the current date and time.
• How to create a `Date` object representing a given date and time.
• How to create a `Date` object based on criteria such as “the first Friday of June 2020.”
• How to extract the parts of a date, such as the year, month, day, time, and so on from a `Date` object.

The Date struct

The `Date` struct is used to represent dates and times in Swift 5, and it’s designed to do so in the most flexible way possible: as a number of seconds relative to the start of the Third Millennium, January 1, 2001, 00:00:00 UTC.

This approach allows `Date` to be independent of any time zone or any calendar system; you store it as an amount of time before or after the start of the Third Millennium and use other objects (which you’ll see soon) to convert into the appropriate calendar, time zone, and format.

To create a `Date` object containing the current date and time, simply create an instance of `Date` using the default, no-argument initializer.

Open a playground in Xcode and add the following:

To see the value stored inside the newly created `Date` object, use `Date`’s `timeIntervalSinceReferenceDate` property, which contains the number of seconds since the reference date.

Add the following to the playground, then run it:

When I ran that line of code (just before 9:00 a.m. EDT on Tuesday, May 26, 2020), I got this output: It’s been 612190714.691352 seconds since the start of the Third Millennium.

To see the `Date`’s value in a more meaningful form, use `Date`’s `description` property to see it in “YYYY-MM-DD HH:MM:SS +HHMM” format, or the `description(with:)` method with a `Locale` instance to display its value using a specified locale.

Add the following to the playground, then run it:

To create a `Date` object containing a date and time that isn’t the current date and time, and without other helper objects, you have to use one of the following initializers:

 Date initializer What it does `Date(timeIntervalSinceNow:)` Creates a `Date` that is the given number of seconds before or after the current date and time. Parameters: `timeIntervalSinceNow:`The number of seconds before or after the current date and time, expressed as a `TimeInterval` (which is just a typealias for `Double`). Positive values denote seconds after the current date and time, negative values denote seconds before the current date and time. `Date(timeIntervalSinceReferenceDate:)` Creates a `Date` that is the given number of seconds before or after Swift’s reference Date, January 1, 2001 at 00:00:00 UTC. Parameters: `timeIntervalSinceReferenceDate:`The number of seconds before or after the Swift reference date, expressed as a `TimeInterval` (which is just a typealias for `Double`). Positive values denote seconds after the reference date, negative values denote seconds before the reference date. `Date(timeIntervalSince1970:)` Creates a `Date` that is the given number of seconds before or after the Unix Epoch (Unix’s reference date), which is January 1, 1970 at 00:00:00 UTC. This initializer was included for compatibility with Unix systems. Parameters: `timeIntervalSince1970:`The number of seconds before or after the Unix reference date, expressed as a `TimeInterval` (which is just a typealias for `Double`). Positive values denote seconds after the reference date, negative values denote seconds before the reference date. `Date(timeInterval:since:)` Creates a `Date` that is the given number of seconds before or after the given reference date. Parameters: `timeInterval:`The number of seconds before or after the given reference date, expressed as a `TimeInterval` (which is just a typealias for `Double`). Positive values denote seconds after the reference date, negative values denote seconds before the reference date. `since:` The reference date, expressed as a `Date`.

Here are some examples showing these initializers in action — add the following to the playground, then run it:

Of course, we don’t think of dates and times in terms of seconds relative to the start of the Third Millennium, or the start of the Unix Epoch, or any other arbitrary date and time. That’s why dates and times in Swift 5 make use of a couple of other structs to help us make sense of `Date`s: `Calendar` and `DateComponents`. `Calendar`s give dates context, and `DateComponents` let us assemble dates or break dates apart.

The Calendar struct

Think of the `Calendar` struct as a way to view `Date`s in a way that makes more sense to us: not as a number of seconds before or after January 1, 2001 00:00:00 UTC, but in terms of a date in a calendar system.

The `Calendar` struct supports 16 different calendar systems, including the Gregorian calendar (a.k.a. the Western or Christian calendar), which is likely the one you use the most.

The DateComponents struct

The `DateComponents` struct allows us to assemble a point in time or a length of time out of components such as year, month, day, hour, minute, and more. We’ll use `DateComponents` to construct a `Date` object using a year, month, day and time, and also deconstruct a `Date` object into a year, month, day and time.

Consider Swift’s reference date: January 1, 2001 at 00:00:00 UTC. Here are what its components are in various calendar systems:

 Calendar Date components for January 1, 2001 00:00:00 UTC Gregorian Year: 2001 Month: 1 Day: 1 Hour: 0 Minute: 0 Hebrew Year: 5761 Month: 4 Day: 6 Hour: 0 Minute: 0 Buddhist Year: 2543 Month: 1 Day: 1 Hour: 0 Minute: 0

Let’s use `Calendar` and `DateComponents` to make it easier to create `Dates`.

Creating known `Date`s with `Calendar` and `DateComponents`

Let’s create a `Date` based on the first moment in phone history: March 10, 1876, when Alexander Graham Bell made the first phone call. I don’t know what time he made the call on that day, so for this example, I’m going to assume that it happened at 1:00 p.m..

Add the following to the playground, then run it: