[ Silence ]
Hello and welcome to Solutions to Common Date and Time Challenges, I'm Chris Kane.
Now, two years ago at WWDC 2011 I gave a very similar talk called Performing Calendrical Calculations and I you can go on the develop site at apple.com and find the video for that and watch that too.
But I promise for this talk I have some all new content.
So, this talk is not really not just a duplication of that talk 2 years ago.
What I'm going to be doing today is I'm going to give you a brief introduction to the calendar APIs, these are the APIs that one uses to do calendar operations, calendrical calculations if you will and I'll be explaining that.
Then the bulk of the talk is going to be spent covering several common tasks that we see people doing over and over again, and I'm going to talk about how I would go about, you know, doing those kinds of operations.
Now, my examples are going to use some new methods that are in Mavericks OS X, Mavericks, but not yet in iOS watch for a future update in iOS for those APIs to appear.
They're not here in your seed for example, iOS seed.
Finally, I'm going to wrap up with just a few words about testing calendar calculations.
And then give you some more information about where to look for additional resources and stuff like that.
So, let's dive in.
So, when I talk about the calendar APIs, I'm referring to just these 4 classes here, NSDate, NSDateComponets, NSCalendar and NSTimeZone.
Now, if you wanted to present information to the user on the screen like display a date, you would use a class called NSDate Formatter.
I'm not going to be talking about NSDate formatter in this particular talk but you can go look about look at the documentation for NSDate formatter online or an Xcode.
So, what is an NSDate?
Well, NSDate is a very simple value object that has just one property which is a floating point number of seconds relative to our reference date.
So, basically it just got one property which is a double floating point number, happens to be a double in this case and that's stores the number of seconds either before or after our reference date.
So, at this point I'm going to introduce this graphic which I'm going to use throughout the talk, this is our timeline.
Now, I'm going to add a boss here to the timeline, this little knob in the middle and that's going to refer in this particular case to our reference date.
So, we're a little bit after our reference date right now that the actual value of the reference date doesn't really matter, it's in 2001 for in the Gregorian calendar as it happens so it's a little ways in the past but so the numbers right now that an NSDate their storing is a bit the numbers are positive.
We're about 12 years after 2001 and so the numbers are slightly positive but because this is a floating point number.
These numbers cans be very large and, you know, go often to the, you know, far future and refer to dates into the far past.
They're about, what, 31 million seconds or so in every year so of course after 12 years there must be over, what, 360 million seconds that are being as value seconds, that are being stored in every NSDate for dates that around the current time.
So, these numbers are very large of course and we don't work with them numbers like 360 million seconds, that's 2001 as humans and I'll be getting to that in a second what we do instead.
Now, in NSDate, I want to emphasize represents both a time and a date.
It has the word date in there in the name but since it is a number of seconds since the reference date, it is both a date and a time.
It refers to a specific moment in time really.
A typical thing you might do with NSDate is to get the current date, a date object that represents now, this very moment when I making the method call.
And I'll be using this a bunch in the talk so that's why I'm putting it up in the slide now.
To get the current time or a date with the current date in it you simply call the class method Date.
It's very simple, straight forward.
So, because these numbers are very large, of course like numbers of seconds, they are really cumbersome for human to deal with.
And so, we as humans over time have developed these notions of what we call in this case dateComponents that is years and months and days and hours and minutes and seconds.
We break time down into either, you know, something that relates to an astronomical cycle, or something artificial like hours and minutes and seconds which are easier for us to deal with.
Now, an NSDateComponents is a slide says here a simple model object with stores these kinds of components.
So, if I have NSDateComponents object I can set it as month property to 6 for example or it's day property to 14.
Now, the other properties like well there's many other properties, other properties like hours and minutes and seconds, or year or what the weekday is or those kinds of things.
I've not specified in this date components object of what happens with those.
Well, the default value for every component is "unspecified" with NSDateComponents.
So, unless a value has been set it has this value, special value which is basically blank has not been set.
And there's a constant for that NSDateComponentsUnspecified.
NSCalendars where most of the calendar calculations APIs occur.
NSCalendar is the object that represents various kinds of world calendars and knows how to do calendar math on them.
It knows how to take an NSDate for example and break it down into the components like what is the year, what month and day within a given calendar.
And the you know, various kinds of calendars include for example the Gregorian calendar.
That's the calendar I'm mainly going to be using in this talk for some of my illustrations.
Here we see a calendar showing January 2012.
But and the Gregorian calendar is of course the a name for the what some people also call the Western Calendar.
The calendar which is very commonly used in commerce for example around the world even where a local calendar like the Hebrew Calendar or the Islamic Calendar, or the Thai Buddhist Calendar is being used instead by the local people.
So, as I say, NSCalendar knows how to convert between NSDates, these very large numbers which are not specific to any particular calendar.
And the components that is the human components that humans are using with the specific calendar systems.
NSCalendar also contains various calendar calculation APIs.
And we'll be looking at some of those today.
And it has several properties as well to control the calculation parameters.
For example, what is the time zone that I want to do the calculations in.
To a common calendar that when why use is the what we call the autoupdatingCalendar.
And here I've shown a very simple example of how to create one of those.
The user on the system hasn't preferred calendar.
There's a setting for that or preference for that.
If the user changes their preferred calendar, you may want your application to update to whatever the new users preference is.
And so, this is what this does is it returns a calendar object which watches for changes to the user's calendar preference and updates itself.
So, you can use this and sort of fire and forget if you will, and not have to worry about the user's calendar changing.
This thing will change itself to match whatever the user's setting is at any given point.
So, what are these calendar calculations that you can do?
Well, there's many different kinds of things that why I'm want to do but I'm going to give a couple of examples here.
So, here we are the timeline again, I've marked June 14th and August 26th.
And one might ask for example, how many weeks are there between these two dates?
Well, I know between strictly between these two dates there are 72 days.
And since there's seven days in a week, that's 10 weeks, they're up to 10 weeks plus two extra days in between these two dates.
Another kind of calculation one might do is to ask questions about weeks.
Now, here I'm going to show a graphic where I've highlighted today, June 14th.
But one thing you might notice is for example if you're used to United States Convention of starting the calendars with Sunday on the far left, you might noticed this is little odd.
I've chosen to start this calendar with Monday is the first day.
And so, I've just doing this to highlight the fact that different kinds of locales might choose different first days in the week or different days of the week to be the their first day of the week.
This is a convention that you might see for example more often in Europe than here in the United States.
So, one question I might to ask is given that today is the 14th of June.
What is the week that contains this date?
Well, here I've highlighted it.
June 10th was the first day of the week in this particular locale of this calendar.
And the week extends through the 16th.
NSTimeZone then I mentioned time zones already.
NSTimeZone is our object that represents these time zone regions.
A time zone is the geo-political region like the one I've highlighted here with Geneva, Switzerland having the blue dot over it.
It's a geo-political region of the world that has a particular offset from Universal Time and a particular set of rules that determine when that offset changes.
Generally, we call that kind of thing for example "daylight saving time" or "summer time."
And you see it's a very irregular region but, you know, I call it geo-political.
Geo meaning, you know, related to the earth and it is very much vertical band of the earth which has more or less the same longitudes in it.
But also that word political is important in geo-political because each country within a given longitude band could of course decide on its own that it has one or another different set of rules from other countries within the same kind of band.
And it's NSTimeZone that has to keep track of all these different countries rules about, for example, when they go into daylight saving time or summer time.
And when they come back out back to standard time.
So, as I say NSTimeZone is the object that knows about the local offset from Universal Time and when that changes.
Now, very similar to NSCalendar, you can create an NSTimeZone object which we call the local time zone.
And this object will represent whatever the current time zone is that the user has set on their computer system.
Or if the user has, you know, requested that the time zone changes the user moves around, this object will update itself based on the user's location changes.
So, let's dive in now to this Common Operations that I want to talk about.
And I'm going to begin by talking about midnight.
It's very common for people to want to know about midnight for various reasons.
But midnight can be a little problematic.
And that's why I have midnight in quotes, and you'll see why I have midnight in quotes in a few bullets here.
Well, first, why do people want midnight?
Well, one common reason is that people are using it as a default "don't care" time.
It is they may want to use an NSDate object to represent a date.
For example, suppose they want to use an NSDate object to represents somebody's birthday.
But they don't care about the time part that of NSDate.
You know, generally, we don't worry about what time people are born within that day unless you're say calculating astrological charts or something like that.
So, they say to themselves the programmers says, "Well, I want to use an NSDate to represent this person's birthday, but I don't care about what time of day it is, so I'm going to I went up the kind of tidy about things so I'm going to set that to midnight."
Well, what I would suggest is when you need to do this, use noon instead.
Midnight can be problematic as I'll described but in a moment.
So, if you really don't care about the time use noon instead.
The other main reason that people want to it over midnight is they want to know when the day changes.
So, for example, they may want to update the user interface of the application when the day changes from one day to the next which is what midnight is, the moment at which the next day starts.
But midnight can be troublesome.
For example, in Brazil, the Brazilian time zone changes by jumping forward from midnight to 1 a.m. when they go into their summer time.
And then the reverse happens, you know, in their fall.
So, there may not exist a midnight.
When 11:59 and 59 seconds comes along and in Brazil, midnight is skipped.
And the first moment of that day is 1 a.m. not midnight.
So, and then, of course, if the reverse happens there are two midnights then when they go back in the standard time.
So, if you're using midnight to mean a special for some special reason, you can get in trouble of course because there may not exist one.
Instead I would you encourage to think in terms of the "start of a day."
When does the day start?
What is the range of time of a day?
And so, how do you do go about calculating that?
Well, this is very common operation we found.
So, we've now added an operation to do that.
So, to calculate today's start what I would now do nowadays with this new API we've added is to call the method startOfDayForDate.
And here I'm passing an NSDate date which is of course the now date, the date representing the current moment.
For and that would give me of course today's start date.
For tomorrow's start date, we need to do some more work.
Now, here in this example I'm going to be very robust about my calculation.
So, first I'm going to create the date which is the startOfToday and I do that again with the same line of code.
Then I calculate a date which is sometime in tomorrow by using this method dateByAddingUnit and passing in the constant NSCalendarUnitDay.
So, I'm going to add one day to my start date which was the previous line here, the start of today.
And I'm not going to pass in any options this particular case and I have a date which is sometime in tomorrow.
But, of course, if today's start moment, if the first moment of the day was 1 a.m., well, that's not going to be the same moment that tomorrow because of the daylight saving time transition.
I mean that's not going to the same start of the moment, start of the day tomorrow.
So, I have to call startOfDateForDay startOfDayForDate, excuse me, again once more to compute the real start moment of tomorrow.
So, anyway, let's move on.
So, why does one want to compute midnight?
Well, the second example I gave was you want to do some reaction to midnight.
You want to run some code when midnight occurs.
So, we have a new notification for that special case that is so very common.
And so, now you can register for the NSCalendarDayChangeNotification.
And you'll your code will get called when the day changes.
When midnight or, you know, the first moment of the next day occurs.
Why would one want to do that?
Well, maybe, you've been awake at midnight and had a mail application open, and you've seen suddenly at midnight it changes all of the today strings in the UI to yesterday for all those mail messages.
Well, first thing I do to go about doing this is I use the local our local notification center so I call the defaultCenter method to get that.
I use the usual method that addObserverForName and I pass a name of this new string constant which represents this notification.
There's no object or queue that I'm going to specify in this particular example.
And then I specify the block of code that I want to execute when this notification occurs.
So, it's fairly straightly forward use of NSNotificationCenter in this case.
Now, midnight of course is a specific example of wanting a specific time but sometimes people want different specific times but within the same day.
So, how does one go about setting a date to a specific time within that date?
Well, let's suppose we want to calculate 11:30 today, 11:30 being the time at which this talk started.
Well, let's suppose I have a date which is at point A there on the graphic.
So, that would be a date which before at a time within this date which is before 11:30.
Obviously, I need to compute a date which is in the future at which pushes the date forward in time.
But if the data object that I start with is at say point B, I need to pull the date back to 11:30.
So, what do I do?
Well, right now, we're after 11:30 so we're more like at point B here.
So, to compute 11:30 of today I'm going to start with the current moment and use this new method called dateBySettingHour and set that to 11, minute set it to 30, and second set it to zero toDate.
And again, in this case there are no options that I'm going to specify.
And what I get is the date object that I started with which was the current moment has moved either forwards or backwards in order to set it's time to 11:30.
Another kind of question people like to ask is, is this date in today?
Well, it's a good questions and very common.
So, we added a new method for that isDateInToday, and this returns a Boolean.
Now, of course, we didn't just add one method here, it's also interesting to know about yesterday and tomorrow.
So, we added two methods for that as well.
Now, an interesting thing about this particular API is that the answer is going to change over time, time marches forward, and so, a date object which represents a time in today, well, tomorrow it won't be a time which is in today of course.
And so, this is an answer which is in some sense very transient so that's something to keep in mind and think about.
Now, if you want to compare dates, we have some new API for that as well.
NSDate itself has a compare method.
But since NSDate is simply, basically an object wrapper around a floating point number.
The compare method of NSDate is very literal when you talk about wanting to know is equal kind of comparison.
It's very literal [inaudible] comparison.
But often people want to know more like, you know, is this are these two dates, you know, within the same day or within the same hour?
Well, asking a question like I just asked on the previous slides "Is this date today" is really just a special case of asking if two dates, a date representing the current moment and, you know, some other given day that you want to compare with are on the same day.
You know, is this date in the same day as a date representing the current moment?
Well, we have a new method for this.
This is the compared date toDate method.
You pass in the toDates of interest.
And then as the last parameter toUnitGranularity, you pass in one of the NSCalendarConstants for the unit that you're interested in.
So, in this case I'm going to ask the question, are these two dates in the same day?
But I could ask are these two dates in the same month or year or minute or what have you.
Now, and then, of course, if the result is NSOrder the same that really means that they are in the same day.
Now, it's important to note that this is not the same as asking if toDates are within some amount of one another.
So, toDates for example can be on the same day but they can be 23 hours and 59 minutes, sorry, apart.
But at the same time, toDates can be just one second apart but be on two different days within, you know, some given calendar.
And so, this is not the same I want to point out as asking if toDates are close to one another, but rather if they're on the same within the same calendar unit within the given calendar that you're using.
Another thing people tend to do with NSDate objects is they want to treat them as timeless entities, so I call this "Timeless Dates."
Just like in my birthday example earlier, you don't care about the time component, you just want to use an NSDate to store a date, a year and a month and a day essentially.
But NSDates are here to store the number of seconds relative to our reference date.
So, they don't simply store values like Era, Year, Month and Day which you might want to simply store yourself.
In those cases I would suggest using an NSDateComponents object.
An NSDateComponents object as I said is very simple model object that has separate properties for each of the calendar components.
And so, it's very straightforward to use one in this way, just to store say something like a birthday where you just a have a year and a month and a day.
Or, of course, another approach would be to create your own simple model object with just three integers say or four integers if you want to also start the Era.
And, you know, if you use the app property syntax in Objective-C the compiler will create the setter and the getter methods for you.
Now, you need if you do this you need to remember to include a property in this object for the calendar that these components are relative too.
You know, a year number, a month number, a day number, these are just integers.
They have no meaning outside of the context of a calendar.
You know, what calendar is that year in?
Well, for example, I can be talking about the year 1434.
And if you assume that I'm talking about the Gregorian calendar, you say, "Oh, he was talking about a time 600 years in the past."
But instead I'm talking about the Islamic calendar and that's the current year.
So, you have to have some notion of what calendar any given set of components are related to.
So, one approach is to include a property for the calendar, you use to break a date down into those components.
Or you can define the calendar for that class of model object to always be a fixed value.
You can say, "Well, these are always Gregorian dates or these are always dates in the Japanese Imperial calendar."
But when you do that, remember; do not use the user's calendar as the fixed calendar.
The user's calendar is not a fixed value.
The user can change that setting.
And so if you say, Well, if you use the user's calendar and breakdown a date and given a set of components are store some information that the user input like the year 1434.
And then later the user changes their calendar.
Well, now you've lost some information because in that year 1434 is not necessarily the same year, you know, it's the same real value as would exist in the user's new preferred calendar.
So, do not use the user's calendar as a fixed calendar value.
Now, the same discussion here applies to dateless times.
Sometimes people use NSDate objects or try to use NSDate objects to represent times like 11:30 in the morning.
And they don't want to they don't need or want to deal with any of the higher components like year, month and day.
They want to use NSDate for whatever reason but they don't need those higher level components.
Well, the same discussion applies.
Use an NSDateComponents object instead would be my suggestion or create your own simple model object.
Now, the bulk of the talk here is as I wrap up is going to focus on finding the next matching date.
Many kinds of calendar calculations we found can be thought of in terms of or expressed as the question, "What is the next date which matches a given set of criteria?"
So, we've added a new API for that.
And this is perhaps the most significant of the new APIs we've added.
So, one thing one question one might ask is when is the next 10 a.m.?
You know, suppose I'm an alarm clock application and the user says, "Why do I want to alarm at 10 a.m.?"
Well, the alarm clock wants to know, well, when is the next 10 a.m. so they can fire the alarm.
Or the application might want to know, well, "When is the next Wednesday?"
Maybe the user has a meeting on Wednesdays so they need to know when is the next Wednesday or you could ask when is the next Wednesday at 10 a.m. and so on.
I mean you can it fully specifies a set of components and I'll get into an example of this in a minute.
And you ask the question, "Well, give me the next occurrence of this particular time that I've specified."
So, here's one of the methods that we've added to do this.
This is one of the simpler ones.
The nextDateAfterDate method, matchingComponents, options method I should say takes a date object at which to begin searching and always finds an answer which is strictly after that date.
For the second parameter you pass in the components which match are to be matched.
Now, these are the literal values.
This isn't a method for doing sort of arbitrary Boolean calculations of, you know, give me the next date where the hour is less than 11 and the weekday is greater than Thursday and it's a full moon.
This is-is not an API for that.
You pass in the literal set of components that the date should match.
But of course it doesn't have to be complete set of components.
You don't have to specify every component like year, month and day and so on.
You can just say, "I want, you know, the next 11:30 a.m."
And then you pass in as the third argument various options.
So, let's look at this example.
I want to find the next Wednesday at 10 a.m. So, I create a blank or empty NSDateComponents object and I set two properties on it.
I set the weekday, four happens to be the constant for Wednesday and I set the hour to 10 for 10 a.m. Now, of course in your real application and your real program, you're not going to have numbers right there like 4 and 10.
You're going to have numbers or values which you've gotten from the user or you've gotten from a database, or you've gotten over the network from some JSON you've parsed or whatever it happens to be.
But for the purposes of this particular example to keep things a little simpler I'm going to ignore where these numbers came from and just literally expose them here on my slides.
So, then I call the method nextDateAfterDate.
I pass in NSDate date which is the current moment.
I want to start searching now.
I passed in the dateComponents that I just initialized.
And I passed in some options and I'm going to ignore the question of options for several slides here but I promise I will get back to those.
Now, the question arises what happens to these other components that I didn't specify?
What is the algorithm do?
You know, I didn't say what min that I want and I didn't say what month I wanted.
Well, those of course as I said towards the beginning in an NSDateComponents simply have a value of NSDateComponents and specified.
Well, that doesn't tell us what the algorithm does with those values, it tells us what the values are.
For the lower components that is the smaller components if you will.
The smaller cycles that are unspecified, what the algorithm does is basically assume the first or the lowest value of that cycle can take on.
In the case of minute or second the lowest value is zero.
So, and this of course is easy to understand.
If I'm searching forward in time for the next 10 a.m. the first moment within any 10 a.m.
that I'm going to find is the moment which has minute zero and second zero of course.
So, what happens for the larger components?
Let's suppose we look at the weekOfYear component.
Well, what we do in this algorithm is we match the same value that the date that you passed in, that after date, the data which to begin searching.
We take its value of that component and we look for either that same value or the next occurrence of that value.
Now, that's a little complicated.
So, let me explain with the graphic.
So, here's our June 14th again.
And suppose we're searching as in this example for the next Wednesday at 10 a.m. Well, the largest component I specified in my question was the weekday, Wednesday.
So, we're going to search within the same week as today is 'cause I passed in today the current moment as my start date to begin searching.
And we're going to search in this week then and the next week.
So, this is the range of time we're going to search.
So, I ask for weekday as the largest component I asked for.
The larger cycle, the next larger cycle that is of course the week.
The weekday cycle around repeat one after the other within the cycle of week.
And so, we begin looking in this week but after the date I passed in which is the current moment and we look in the next week.
Now, of course if the start date that I pass in is at the end of the year or the end of the month or the end of the year that next week that we're willing to search in for an answer might be in the next month, it might be in the next year even.
So, we have to do the same kind of treatment for all the larger components.
Now, this is the default behavior of the algorithm.
We only search in a sense a little ways forward in time and find you some answer for that.
And this I'm going to give an example in several slides here which will make this clear why we do this but this the default behavior and there's an option for changing this default behavior.
Let's go back to an example I had early in the talk which was Finding Tomorrow's "Midnight."
Now, that took several lines of code in the previous example but I can rephrase that question as one of finding.
So, I'm going to use this new API, create an empty NSDateComponents object and simply specify the hour to be zero.
So, what this is going to do is the algorithm is going to begin at the date that I'm going to give it which is the current moment here.
And it's going to search forward for the next case where a date is the date is or has maybe I should say the hour 0.
So, I pass in the dateComponents and again I pass in some options which I'm going to skip over for the moment but I promise I will get back to those.
Now, it's possible that there's no possible results.
For example, let's suppose I initialized the day field of my dateComponents to 50.
Well, there's no calendar at least that I'm aware of that has a day 50 in any of its months.
And so, if I call the API then passing that in what I'll get is you know, it's just an unreasonable request in one sense to ask for the next day which is 50.
So, what are these options that I've been referring to but I'm not explaining.
Well, I talked about the default behavior where we only search a little ways forward in time.
We only search the next occurrence of the next larger cycle if you will for an answer.
But if you need us to search farther, there's this option NSCalendarMatchStrictly.
An example would be suppose you wanted to find the next leap day in the Gregorian calendar.
You want to find the next February 29th.
Well, that could be as much as four years in the future.
So, you need us to search more than the current year and the next year for this answer.
You need to you might need to search up to four years in the future.
And so, that is the case where you would need to pass in this option match strictly.
Another example which I'll get to in a minute is what happens when a time doesn't exist because of a daylight savings time transition.
And again, this option has a behavior, there in that kind of case and I'll talk about that in a second.
You might also want to search backwards in times.
So, instead of just searching forwards for the next occurrence even though that's common for calendar or alarm clock kinds of applications in that kind of thing but you also might want to go backwards and so there's an option for that.
Then there are three options for what to do, what the algorithm should do when the time is missing when there is no time that matches that.
Now, I'm going to explain I'm going to dive in to this particular example in the next several slides.
So, I'm going to skip over these options for the moment.
If there are multiple matches such as there are multiple 1:00 AM's because Daylight Saving Time transition has caused time to jump backward and there are happen to be two 1:00 AM's.
Well, there are two options for you to tell us which of those two options or two alternatives you want.
NSCalendarMatchFirst is the default option so you don't need to specify that one if you want the first 1:00 a.m. for example.
Now, one of these four options is required or will raise an exception.
You either need to ask for strict matching or you need to pass in one of the options that tell us what to do when the most desirable time is actually missing.
So, let's look an extended example, really, where we're looking for the next 2:30 a.m. In the United States, the Daylight Saving Time transition in the spring skips the 2:00 hour.
And so, what does that look like?
Well, here's our timeline again.
So, midnight of the Daylight Saving Time transition day comes along, time passes and we have 1:00 a.m.
And then another hour passes and we get to what would normally be 2:00 a.m.
But 2:00 a.m. hour is skipped and it's totally missing and so 3:00 a.m. is actually the next time.
So, one hour after 1:00 a.m. is actually 3:00 a.m.
in the United States on the date of the transition.
And then time of course continues as normal in 4:00 a.m.
and 5:00 a.m. come and go.
Now, if I'm looking for 2:30 in the morning, the best result here 2:30 is actually missing.
There is no 2:30 a.m. on that day.
Well, if I pass in the NSCalendarMatchNextTime option, what that means is, you said, you want the next time which exists.
And so in this case, the next time which exist after the most desirable time is 3:00 a.m. If instead, you pass in the NSCalendarMatchNext TimePreservingSmallerUnits, what we'll get is 3:00 a.m. out of the algorithm.
So, what this has said is you want us to give you the best answer within the next hour, in this particular case, where we give you the minutes and the seconds that you requested even though we can't give you the hour that you requested.
And then of course there is the reverse which is NSCalendarMatchPrevious TimePreservingSmallerUnits.
And here you get 1:30 instead of the most desirable answer 2:30 which of course as I say doesn't exist.
Now, if you had passed in instead the NSCalendarMatchStricly option, what happens instead is there is no 2:30 but you've asked for a strict match and so the result you get is going to be in the next day.
Well, I have a friend who works at the local airport and he needs to be at work at 3:30 in the morning before the first international flights takeoff and before the first passengers arrive for those international flights.
And he uses a fairly simple alarm clock application where he just specifies what time he wants his alarm.
So, he sets his alarm for 2:30 in the morning and so he is of course, you know, right in the crosshairs for this particular issue to occur every spring.
Well, 2:30 in the morning doesn't exist on that transition day in the United States.
And so, what happens?
Well, if the alarm clock application were to pass in the NSCalendarMatchNextTime option.
The alarm clock is going to ring at 3:00 a.m.
and he'll have 30 minutes to get to work instead of the usual hour that he needs.
If instead, it passes in the NextTimePreservingSmallerUnits option, it's going to ring the alarm at 3:30 in the morning and he'll have no warning to get to work.
On the other hand, if it passes in the PreviousTimePreserving SmallerUnits option, it's going to ring at 1:30 and he's going to have an hour or two groups of 30 minutes before and after that missing gap of time so he'll have his usual hour to get to work.
So, that's sound like a good option.
If instead it uses the strictly option, he's not going to get any alarm that rings at all.
It's going to ring the next day because it will continue its search and find a 2:30 in the morning on the next day and not ring this day at all.
So, what my friend really wants to specify isn't 2:30 with his alarm clock application.
He really wants to specify one hour before 3:30 so it'd be much nicer if the user interface of this alarm clock had two controls, one which was a time and one which was a relative time before that time at which you want to begin searching.
Of course even nicer might be for the alarm clock application to warn him that his desired time doesn't actually exist, you know, when it's like a day before the transition and give him an alert saying "Hey, you know, there's a Daylight Savings Time transition coming up, you know, you got an issue here."
Maybe you'd ask him, "What do you want me to do?"
or it just says, "I'm going to wake you up at 1:30 instead."
Another way to look at the question of what is the best option is to look at what normally happens around this gap.
So, in the United States, they put the transition in the middle of the weekend.
That is early in the morning Sundays so it's is right in the middle of the weekend.
And so, what happens if you just look at, say, 6:00 a.m. is that from Friday 6:00 a.m. to Saturday 6:00 a.m., there's an ordinary period of 24 hours, then from Saturday 6:00 a.m. to Sunday 6:00 a.m., there's just 23 hours.
But then again, from Sunday 6:00 a.m.
to Monday 6:00 a.m. there's a period of 24 hours.
So, what happens every year is same old cliché joke is try it out, "Oh, you're going to have one hour less of sleep tonight."
And that happens, you know, Saturday night all the news reporters talk about that to remind people about the Daylight Saving Time change.
One hour less sleep but that occurs in the middle of the weekend.
That's kind of the point why the U.S. does that transition in the middle of the weekend.
Well, let's go back and shift our timeline again back to the 2:30 example.
So, if I ask for NSCalendarMatchNextTime to get 3:00 a.m., what will happen is a 24 hour period occurs from Friday to Saturday then a 23 and a half hour period occurs between alarm clock firings on Sunday morning and Monday morning.
So, you've kind of split the different there.
On the other hand, if you pass in MatchNextTime PreservingSmallerUnits, you get a 24-hour period between alarm clock firings on Saturday morning and Sunday morning and then your short night in a sense or a short day is between Sunday and Monday.
And so, it's really Monday morning where you end up losing that hour of sleep.
And finally, if you pass in the MatchPreviousTime PreservingSmallerUnits, you get the same kind of pattern we saw originally where there is a 24-hour period, a 23-hour period and a 24-hour period.
If you need to enumerate matches, that is not just find one mixed instance of a match but you want to find all times that match certain criteria and enumerate them all and do some work for each match, then you should use this method.
The enumerate dates starting after date method takes the same kind of parameters, the first parameter, the date at which to begin searching.
It takes your date components that you want to have matched and some options, the options I've explained and you pass in a block.
The block takes three parameters.
The first two parameters of the block are the date that the algorithm found and a Boolean telling you whether it found an exact match or not.
If the algorithm had to fudge the answer based, you know, give you a 1:30 or 3:30 instead of the 2:30 you asked for in our previous example.
This algorithm will tell you with that Boolean whether it had to that or not.
Then there's the third parameter which is the mechanism you use to stop the algorithm when you want to stop it.
So, we've used this in other enumerate methods, it's the same kind of pattern.
We pass in a pointer to a Boolean and when the condition arises where you want to stop the enumeration, you simply set the value pointed to, you know, star stop in this case to "Yes".
You don't need to set the Boolean to "No" every time to keep enumerating, it will keep doing that.
You don't need to set it to know ever.
You just need to set it to "Yes" once when you want to stop the enumeration.
So, there were some operations that are very common and we found lots of people want to do a lot.
Let me talk a little bit here, give me few minutes of talk about testing these algorithms and testing the calculations that you're doing within your application.
Well, the first thing you need to do is of course consider the interesting cases.
Well, what are the interesting cases?
Well, an application today might be used worldwide and so you need to consider different locales and different calendars that the local users, you know, in a given area might be using.
So, you need to test different locales and calendars.
Of course, these different users around the world are existing and living in different time zones so it's good to get some testing within different time zones.
But you also need to consider the cycle boundaries, where are the interesting cases.
Well, these various cycles of time, for example, hours go from, say, 0 to 23 and then the cycle repeats the next day, 0 to 23 and so on.
So, an example of a cycle boundary is the end of a day or the beginning of a day is the same thing, midnight.
But you also have interesting things that can happen at the end of months or at the end of years or beginning of years, it's the same thing.
In some cases, some calendars, the Era is really important to also test for and keep in mind.
What kind of things do you look for?
Well, you look for incorrect results.
It's very obvious but very dull answer, right and obvious.
Well, you look for incorrect results.
Well, the real question here is, how do you know that the answers that you're seeing, that the answers you're getting are the correct answers?
Well, what can you do?
You have to find some sort of authoritative information.
Like, how do I know that it's, you know, a certain year within the Hebrew Calendar, I'm being told 5,700 and something.
Well, how do I know that's correct?
Well, you have to find some sort of authoritative information.
Well, there's these old fashion things called Almanacs which are going to help in books and of course nowadays, I tend to use the internet a lot and so I do a search on the internet.
What is the current Islamic Calendar year?
And I don't just look at one website of course.
I look at many websites and compare their answer.
And you can also ask people.
So, if you have people that you know or can ask about the answer, you know, you can verify it with real people and I'll get to that back to that in a second.
So, how do you test?
Well, to literally test of course, you have to turn off the time syncing on the device, on the computer or on iPhone or iPad, what have you.
Then you, of course, you can set the clock manually.
You can set the time zone to different values.
You can set the calendar in locale to different values manually and, you know, try out your application.
But, perhaps a more valuable thing to do is to develop some variety within your beta tester pool.
So, if, you know, assuming you have some people that you ask to beta test your application, you can try to collect a group of people which live in different time zones, which live in different locales of the world and they will naturally of course know the right answer 'cause at worse, they can look at a newspaper or ask their friend what the day is if they don't know.
But they'll know what the right answers are and they'll be able to tell you what, you know, what you're doing wrong when something happens that's wrong within their application.
But another thing you can do is direct their testing.
Tell them, you know, what if you say, "Well, this guy in my beta tester pool lives in China.
I know he lives in China.
You can ask him specifically, "Can you test, you know, this or that bit of functionality in this or that way?"
So, you can direct their testing rather than just giving them the app and say, "Oh, here's a new version, go try it out."
So, I've talked about various kinds of common operations and we've added some API for and there are many new methods that we added that I didn't talk about today.
You have to go and look at the NSCalendar documentation, the NSCalendar.h Header to see those.
If you had some feedback on this talk, you can talk to our Evangelist Paul Marcos.
The Date & Time Programming Guide is very good.
I recommend reading that.
And of course, there's the documentation for the specific classes that I talked about like NSCalendar.
And of course, the Developer Forums, our resource for asking questions about these things.
And with that, I thank you.
[ Applause ]