Blog

Latest Post

Swift Tip: Unexpected Results from a Date Formatter

We have almost finished rewriting our Swift Talk backend in Swift. While testing it against the production database, we stumbled over a crashing issue with our use of a date formatter. Today’s lesson: be careful when force unwrapping the result of string to date conversions, and always read the documentation carefully! 😬

Here’s how we set up the formatter:

fileprivate let formatter: DateFormatter = {
    let dateFormatter = DateFormatter()
    dateFormatter.locale = Locale(identifier: "en_US_POSIX")
    dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
    return dateFormatter
}()

On macOS 10.12+ and iOS 10+ you could use an ISO8601DateFormatter for this, which makes the setup easier and would have avoided the problem we encountered. However, we needed this to work on Linux.

Using this date formatter, we ran into a strange issue with a seemingly well-formed date string:

formatter.date(from: "2017-03-26T00:53:31")! // this works
formatter.date(from: "2017-03-26T02:53:31")! // this crashes!

This puzzled us for a while. As a first thought, we might be dealing with a leap year issue, but the crashing example has a date in March. We asked ourselves, what else happens in March? Then it dawned: the beginning of daylight saving time! Sure enough, in 2017 German daylight saving started on March 26th, at 2am.

The date and time in the string we were trying to parse didn’t actually exist. At the beginning of daylight saving the clock skipped the hour from 2am to 3am, and our date formatter seemed to know about this β€”Β as would we if we’d read the documentation more thoroughly!

We checked the time zone of our date formatter:

print(formatter.timeZone!)
// Europe/Berlin (current)

Since we didn’t specify otherwise, the date formatter uses the system time zone, which is set to our location. Therefore, it’s daylight saving time aware. The fix is easy, we just have to specify a time zone with a fixed temporal offset instead of a location.

We want our date strings to be interpreted as coordinated universal time (UTC):

fileprivate let formatter: DateFormatter = {
    let dateFormatter = DateFormatter()
    dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
    // ...
    return dateFormatter
}()

formatter.date(from: "2017-03-26T02:53:31")! // now it works!

Of course, you should still be careful about force-unwrapping the result since any non-existing date/time value will return nil, though happily, the string in question now parses correctly. πŸ‘

We’ll have more to say about our backend rewrite soon. In the meantime, you can enjoy Swift Talk in it’s original Ruby version.

Previous Posts

Swift Tip: Vector Algebra with Protocols

In last week’s Swift Talk we discussed the vector algebra required to build a routing graph for our running trail app. To work out where the tracks overlap, we needed to calculate the closest distance from a point to a line segment.

We won’t repeat the math here, but we’ll highlight a detail of the implementation.

For testing purposes we wanted to calculate with CGPoints, which makes it easy to draw the points in a view. In the final app we want to calculate with Core Location coordinates. It’s important to note that geographic coordinates are coordinates on a sphere, but for our use case, we’ll pretend that the earth is flat β€” it’s a good enough approximation for the small region we’re doing our routing in.

Instead of implementing the vector operations first on CGPoint, and then re-writing them on CLLocationCoordinate2D, we decided to introduce a simple protocol:

protocol Vector2 {
    associatedtype Component: Numeric
    var x: Component { get }
    var y: Component { get }
    init(x: Component, y: Component)
}

This protocol represents a vector with two numeric components, x and y. We’re using an associated type to specify the type of the components: in our case they can be of type CGFLoat (for CGPoint) or CLLocationDegrees (for CLLocationCoordinate2D). Since CGPoint already has all the protocol requirements, conforming it to Vector2 is a one-liner:

extension CGPoint: Vector2 {}

Now we can start to define vector operations on the Vector2 protocol, for example the dot product and vector addition:

extension Vector2 {
    func dot(_ other: Self) -> Component {
        return x * other.x + y * other.y
    }

    static func +(l: Self, r: Self) -> Self {
        return Self(x: l.x + r.x, y: l.y + r.y)
    }
}

Since the operations are defined on the protocol, we get all of them for free when we conform a new type to the protocol; for instance, with CLLocationCoordinate2D:

extension CLLocationCoordinate2D: Vector2 {
    var x: CLLocationDegrees { return longitude }
    var y: CLLocationDegrees { return latitude }
    init(x: CLLocationDegrees, y: CLLocationDegrees) {
        self.init(latitude: y, longitude: x)
    }
}

If you’d like to learn more, the first episode in this Collection is public. To follow our progress, you can Subscribe. πŸ€“

Happy Cyber Monday! πŸ‘¨πŸ»β€πŸ’»πŸ‘¨πŸ»β€πŸ’»

In a rare special, for one day only Swift Talk is 30% off.

New subscribers can save $5 a month, or $45 for the year, for the lifetime of your membership. Our first Swift Talk discount since 2016, it’s a great time to join.

We publish a new live-coding episode every week, discussing specific real world problems and developing solutions live, while you watch. Unlike traditional tutorials, Swift Talk is conversational in style, which makes it easier to follow our thought processes and helps you understand why we choose particular techniques.

In our latest Collection, you can follow us as we implement a map routing feature for a running trail app β€”Β the first episode is public. Each episode is about 20 minutes long, and at 128 episodes to date with 20 Collections arranged by topic, there’s plenty to watch, and we hope, much to learn!

Our Black Friday special continues too: 30% off all ebooks and bundles, including our latest, App Architecture, and our Complete Collection bundle which includes all five books. πŸ‘

All offers end midnight Pacific Time.

Follow this magic link to subscribe.

Enjoy! 😊

Happy Black Friday! πŸ›

Joining the Black Friday fray, we’re delighted to announce a 30% discount on all our eBooks and bundles until Monday!

For the first time, our latest book App Architecture is now $34, a saving of $15. For $69, the book comes complete with a 7+ hour video series of in-depth discussions and live coding in all five patterns, a saving of $30.

If you’ve already bought the book, the video upgrade is now $41. πŸ‘

This year, all our bundles are included, with a further 30% off the regular bundle discount. If you want to learn more about App Development, Everything Swift, or Swift Essentials, we’ve got you covered.

The Complete Collection, including all five books and the App Architecture videos, is now $139, our largest saving at $60 β€”Β if you could stack eBooks, they’d look great under the Christmas tree. πŸŽ„πŸ“š

Enjoy! 😊

Swift Tip: Local Struct Definitions

While working on our re-implementation of the Swift Talk backend in Swift, we stumbled across β€”Β or stumbled over? β€” a somewhat obscure language feature. Thankfully, it turned out to be helpful, and maybe you’ll find it useful too.

We’re using Swift’s Codable feature to generate and parse the JSON and XML strings needed for API requests. This technique is something we talk about in Swift Talk 115 (a public episode) and 116, where we implement a custom XML decoder.

Let’s say we need to send the following XML to the server:

<billing_info>
  <account_id>Some UUID</account_id>
  <token_id>Some Token</token_id>
</billing_info>

Instead of generating this XML string using string interpolation, we create a codable struct that represents the contents of the XML:

struct UpdateBillingInfo: Codable, RootElement {
    var account_id: UUID
    var token_id: String
    static let rootElementName = "billing_info"
}

Then we use our custom XML encoder to turn an UpdateBillingInfo value into an XML string. The XML encoder can take care of all the proper formatting and escaping, no matter what data we have to send.

Often, we don’t need to use these structs elsewhere, we only need to use them in the function that generates the request. Cluttering the namespace with all these types is an unwelcome side-effect of this approach, even if we make them private or nest them within another struct.

As it happens, we can define a struct even more locally: within the body of a function!

Here’s a function that generates the request with the payload above, with the struct neatly tucked away in its local scope:

func updatePaymentMethod(for accountId: UUID, token: String) -> RemoteEndpoint<RecurlyResult<BillingInfo>> {
    struct Update: Codable, RootElement {
        var account_id: UUID
        var token_id: String
        static let rootElementName = "billing_info"
    }
    let url = ...
    return RemoteEndpoint(xml: .put, url: url, value: Update(account_id: accountId, token_id: token))
}

This way, we can still have all the advantages of using the Codable infrastructure for serializing data, without cluttering the namespace with extraneous types. It also becomes very clear that this type is an implementation detail of the function.

For more useful stumbles, subscribe to Swift Talk. πŸ€“