Opening and closing times with Swift

Sam Piggott
4 min readSep 13, 2015

--

📅 Or, comparing dates is a huge time-sink so I made a gist so you can be lazy and not have to worry about it 📅

One of the most bizarre things I’ve discovered about developing with UIKit is how there’s this odd absence of comparing dates easily. It’s not a huge ball-ache to do once you’ve got your head around it, but with all the NSDateComponents/NSCalendars/NSTimeZones potentially involved, it can get messy quick.

I threw together this super-lightweight-single-file library whilst working on the latest version of Dojo. We’ve got a bunch of events and venues that have opening times, and we need to check if the current time sits within ‘em. Seems simple enough, right?

If you’re like me and just want to lift the code out and slap it into your own app, then jump straight to the repo. But if you’re on your lunch break and already finished reading BBC News for conversation fodder for the looming afternoon, then by all means, read on.

Humble Beginnings 😌

Right, before we do anything, we’re not checking dates here, we’re checking the specific times on a date object. That means that the actual date is entirely irrelevant, and it’s only going to cause problems, so we’re going to ground all the dates to 1970 before we do anything else. It’s probably good practice to do this in your environment if you’re dealing with data fed from an external server, as you can never guarantee that the date will always be the same.

  1. First, we create a gregorian calendar. This is probably the one you want. Lovely little gotcha — you need to set a time zone for the calendar, too — otherwise you’ll crash and burn.

Then, we create a function within our class function which generates a flattened date. What we’re effectively asking here is to basically take just the .Hour, .Minute and .Second, ignoring the .Day, .Month, .Year, etc. When we create a date out of these (See 3.), because we didn’t supply those details to the NSDateComponents object, we can expect a date of 01–01–1970 (UNIX standard time), but with the hours/minutes/seconds we specified.

First off, I went for this simple approach.

That basically checks:

  1. (I assign each item as I go in line 1. We need all those dates to be able to determine whether the place is open or not, so if any of them are missing, we don’t wanna run that code. No, ma’am.
  2. If the current date is earlier than the open date, the place isn’t open — so return false.
  3. If the current date is later than the close date, the place isn’t open — so return false.
  4. If neither of those if statements executed, then we’re sat slap-bang in the middle of the opening time. Boom. Return true.
    _shaking finger gif_

What do you mean, you guys stay open after midnight?! 😱

Alright. That’s great. Lovely and simple. But for some unknown reason, bars in London and France have this tendency of staying open longer than past midnight. And that logic doesn’t agree with that code. Nope, not one bit.

To fix this, I mutate the closeDate conditionally by making the date a day later than the openDate — but only if the closeDate is earlier or equal to the openDate.

Yeah. Eat it, late-night closing times.

Alright, let’s take a look at what we’ve got so far.

  1. Quick little footnote here — the components return an optional Date object when we ground it. It’s unlikely to be nil, but it’s good to be safe — so we catch it by returning nil if everything goes tits-up.

Multiple. Opening. Times. 😰

But wait. A little localisation quirk I didn’t see coming — the French have a tendency of having separate opening times for the mornings and afternoons. That means we have to check multiple open and close dates per day.

So we go deeper. We’re happy with our lovely little function for a single date, but we’d like to run it over all of the dates for the day in question. Let’s make another function to iterate over the array and check all those bad boys, too.

  1. Alright. We declare an optional boolean to keep track of whether the venue’s open or not (as this might be nil if we don’t have any opening times for our object), and get today’s date by calling NSDate().
  2. I don’t know how you’re keeping your dates, but I’m using an array of structs; so I’m going to iterate over those to get our first and last opening times for the available day.
  3. Now for the clever bit. If the event reports as anything but true (that means you too, nil), then we want to assign it. However, if we are sat within one of those date sets, we don’t want to override it later down the line. That means that if we get a true at any point after discovering a true, then we don’t want to mutate that value any more. The venue’s open, that’s all we need to know.

What’s nice about using all of these optionals is that we don’t have to expect opening times. This is pretty great for me at Dojo, as we sometimes have a delay between getting the opening times for a venue before it goes on the app. So if the JSON supplied didn’t fill the object’s opening times, the app won’t crash. No, sir. That’d be bad news.

With all this said, I think there might be a cleaner approach to this. I’ve put it up on Github, so if you have any improvements then I’d welcome a pull request with open arms.

¯\_(ツ)_/¯

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Sam Piggott
Sam Piggott

Written by Sam Piggott

More than likely found in front of a screen. Making code courses over at CodeSnap.io.

No responses yet

Write a response