iOS

A Beginner’s Guide to NSDate in Swift


If I was ever asked what’s one of the most common stuff I do among all projects, then I would have answered that dealing with dates is definitely one of them. Undoubtably, there’s no developer out there who doesn’t really need to “play” with the NSDate class and handle dates in some manner, no matter how much or little the work on dates is. From simply converting a date value into a string up to performing calculations with dates, there’s always one constant fact: Developers have to be acquainted with this side of programming in iOS. It’s not hard to master, and eventually can lead in gaining time in other more important programming tasks. Working with dates might seem like a hassle to new programmers; however that’s not true. All you need is to get the grasp of it.

The most common operation when using date (NSDate) objects in applications, is to convert them into string objects so they can be properly formatted and shown to the users. Quite common is the reverse action as well; converting strings to date objects. However, these are not the only tasks regarding dates. Here’s a sample list of what else can be done when messing with dates:

  • Compare dates.
  • Calculate dates in the future or in the past, simply by using a reference date (e.g. the current date) and adding or subtracting periods of time (days, months, years, etc).
  • Calculate date differences (e.g. find the elapsed time between two specific dates).
  • Break a date into its components and access each date part separately (day, month, etc).

All the above, including the conversions to and from strings, are subject for discussion in this tutorial. Through the next parts, you’ll see that is actually easy to do whatever you wish with dates, as long as you know what your tools are and how you should use them.

For your reference, I give you next a list of links with some important documentation. Don’t forget to pay a visit in case you need more information on specific topics:

About the Demo App

Well, in this tutorial we won’t really work with a demo application at all (yes, you’ve read well). Instead of an app, this time we’ll use a Playground for all the examples we’re about to see next. I’ve chosen this way on purpose, as my intention is to provide you with multiple sample code snippets targeting to all the NSDate aspects I want to deal with here.

Even though you can download the provided playground file and open it in Xcode, I strongly suggest you to create a new Playground file and test every new code snippet presented in the following steps. That way it’ll be easier for you to understand how each demonstrated aspect works, and moreover you’ll be able to modify it and see in real time how the results get changed depending on the modifications you perform.

The playground file that I provide you with all the code snippets is named PlayingWithDates. Feel free to use the same, or a different name for your file.

The Basics

Before we start looking at the details of dates and what we can do with them, it’s important to make sure first that some basic concepts are clear to everyone. So, let me start by the simplest thing, the NSDate object. An object like that describes both date and time in programming terms, so it’s not used only when we want to deal with dates, but with time too. The meaning of formatting doesn’t exist when talking about NSDate objects; just think of both date and time as properties, like any other properties in other classes. Talking about formatting is useful only in cases of converting a date object into a string, and we’ll see many details about that in the next parts. Generally, keep always in mind that the NSDate class is what you need, no matter if you’re interested only in date, time, or both.

Another class that we’ll meet a little bit later, is the NSDateComponents class. It would be easy to say that this one could be called the “sister” class of the NSDate, as it provides developers with some extremely useful features and operations. The first important thing about this class is the fact that it can represent each date or time part as a single property, so each of it can be accessed directly and used in other tasks (such as calculations). For example, the day and the month in a NSDateComponents instance are represented by the day and month properties as shown next:

It’s as simple as that. Of course, accessing the date parts and populating the date values into a NSDateComponents object requires some conversion mandatorily to be done first, but we’ll discuss about that later.

Besides the above, the NSDateComponents class is also quite useful when it’s necessary to calculate dates either in the future or in the past. All you have to do when you want to find an upcoming or a previous date of a reference date is to add or subtract the proper components, and eventually convert to the new date. Additionally, the NSDateComponents is also suitable for finding date differences. No need to go deeper in any of those two right now, as we’ll see details in a while.

Even though we’re not going to make big use of it, and we’ll just need it to perform conversions from NSDate to NSDateComponents and back, the NSCalendar class is also one more player to the dates game. The features this one supports are not going to be part of the subject in this tutorial. The duty to convert dates from NSDate to NSDateComponents (or the opposite) belongs to the NSCalendar class, as always a specific calendar object is required to be used for conversions. Actually, the system needs to know what calendar to use prior to any conversion, so it’s possible to produce the proper results (don’t forget that there are different calendars all over the world, so the converted days, months, etc values can vary). I’ll let you go and read more about calendars in the documentation link I provided you with in the introduction; all I have to say here is that for convenience we’ll use the currentCalendar() class method of the NSCalendar class that returns the specified by the user calendar in Settings.

Further than all the above, there’s one great tool that we’ll make use of starting from the next part, and that is the NSDateFormatter class. This one makes it possible to convert NSDate objects to String values, and strings to dates. It allows to customize the format of the final date string either by using some predefined date styles, or by manually describing the desired format for high customization. We’ll see several examples about that, and we’ll also see conversions towards both directions. A NSDateFormatter object supports localization as well; all we need is to provide it with a valid NSLocale object, and the final converted object will be represented properly based on the given locale settings.

A similar class is the NSDateComponentsFormatter, and it can be used for one single purpose: To take date and time units as input and produce human-readable, formatted strings of date as an output. It contains various methods for this job, and we’ll see a couple of them at the last part of the tutorial. To be honest, we won’t get into much details of this class; we’ll discuss only about the things we’re about to use in our examples.

So, by having said all the above, we’re ready to go straight to the action where you’ll see how everything mentioned here plays its role. Once again, I recommend you to create a new playground file and try out every single example I present. There’s no better way to learn something other than trying it out.

Converting Between NSDate and String

We’ll start working with the NSDate class by getting the current date and assigning it to a constant for easy access. Getting the current date doesn’t require to call any special method like now() or today(), like some others languages require. All you need is to initialize a NSDate object:

Here’s what you’ll get by writing the above in the Xcode playground:

t44_1_current_date

Note that we’re going to use the above value many times in the next code snippets. Now, let’s initialize a NSDateFormatter object. This is going to be our tool to make conversions from dates to strings and back. Here it is:

The dateFormatter is going to use the locale settings of the device by default, unless another locale explicitly set. Even though it’s not required to set the current locale manually, here’s how you can do it in case you need so:

Setting a different locale it’s easy: You just need to know and specify the locale identifier of the matching locale:

Those two lines demonstrate how to set a different locale to the date formatter (here Greek and French). Of course, setting subsequent locale values it’s pointless, as the last one will eventually apply. Are you wondering how the locale affects the conversion? You’ll find this out in a while.

Formatting the output using the date formatter styles

Before you convert a date object (NSDate) into a string, you need to “tell” the date formatter how you desire the output string to be formatted. There are two ways to do that. The first is to use some predefined values known as date formatter styles, and the second is to manually set the final formatting by using some certain specifiers.

We’ll begin here with the first case, and we’ll meet the NSDateFormatterStyle enum. Each single value of it represents a different type of formatting, and as they’re not too many, we’re going to see them all one by one right now. The first supported style is the FullStyle, and its results are shown in the following image.

t44_2_convert_fullstyle

Here’s the above code in text as well, so you can copy it if you wish so:

Besides the date style, equally important in the above two lines is the stringFromDate: method that performs the actual conversion. When talking for conversion, we actually mean that method. All the rest are just steps for customizing the results. If you plan to make date conversions in your projects, then this one will definitely become quite handy to you.

Now, let’s see the next style, which is the Long Style:

t44_3_convert_longstyle

And the code in text:

As you see in this type of style the day name is missing (comparing to the full style). The next is the Medium Style:

t44_4_convert_mediumstyle

And finally there’s the Short Style:

Now that you know what the available date formatter styles are, you can use them in your projects according to your needs. Each style produce a different result, and it’s quite possible that one of them will fit to you.

A little bit earlier I mentioned how the locale of the date formatter can be changed to a different, non-default value. Now that we’ve seen how conversions can be performed using the date formatter styles, let’s also see how different locale values affect the final string output of the original date. I’m going to use the Full style and the two locale identifiers (Greek and French) mentioned earlier for the sake of this example:

t44_5_date_locale_fullstyle

I think that now it’s pretty clear what the locale can do, so use it wisely.

Using date format specifiers

The date formatter styles presented right above are good enough for many cases, however they cannot be modified so we can achieve a different output. In such cases we have a different option available at our disposal, and that is the ability to set a custom date format that properly describes the desired format to the date formatter object. Setting a custom date format is mostly useful in two cases: When the date formatter styles are not suitable for the desired output (apparently), but also when you need to convert a complex date string (e.g. “Thu, 08 Oct 2015 09:22:33 GMT”) into a date object.

In order to set a date format properly, a combination of specifiers must be used. Specifiers is nothing more than simple characters that have a special meaning to the date formatter object. Before I give you specific examples, let me list first some of the format specifiers that we’ll meet in the following code snippets:

  • EEEE: The full name of the day (e.g. Monday). Use 1-3 letters for the abbreviated representation of the day name.
  • MMMM: The full name of the month (e.g. October). Use 1-3 letters for the abbreviated representation of the month name.
  • dd: The day number in the month (e.g. 09 or 15).
  • yyyy: The year with four digits (e.g. 2015)
  • HH: The hour representation with two digits (e.g. 08 or 19).
  • mm: The minutes representation with two digits (e.g. 05 or 54).
  • ss: The seconds representation with two digits.
  • zzz: The timezone presented with three letters (e.g. GMT)
  • GGG: BC or AD.

For full reference on the date format specifiers, I’m prompting you to visit the official technical specification, where you can find variations on the specifiers given above, as well as other not mentioned here.

Let’s continue now with our examples and let’s see how the format specifiers are actually used. This time, let’s convert the current date into a string and let’s get the full day and month name, the day number and the year:

t44_6_convert_custom_format1

I think there’s nothing further to comment on how to use the custom date formatting, as you can clearly see that it’s a really straightforward technique. Let’s have one more example, and let’s convert the time:

t44_7_convert_custom_format2

All the conversions we’ve seen so far regard NSDate objects that turn into a formatted string value. The opposite task is also interesting, where everything said before about the date formatter styles and the format specifiers apply here too. The key when converting formatted strings into NSDate objects is to properly set the value of the dateFormat property of the date formatter, and to use the dateFromString: method that will do the job. Let’s see a couple of examples on that:

t44_8_convert_string_to_date1

Let’s see a more complex string now, where the timezone is also included:

t44_9_convert_string_to_date2

Note how the time value (09:22) gets changed simply by using a timezone in the date string (becomes 12:22). There’s no actual change here, it’s just how the time in my timezone (EET) is represented in GMT timezone. Later we’ll see a few more samples that use different timezones, but feel free to explore more on your own based on the previous snippet.

At this point you’ve met pretty much all you need in order to perform conversions between dates and strings. You can try to write your own code to test what you’ve seen here and get a deeper taste on how everything works.

Working With NSDateComponents

Many times you’ll need in your projects to break a date into its parts, and fetch specific values out of it. For example, you might have to get the day and the month values from a date, or the hour and minutes from the time. In this case the tool you should use is the NSDateComponents class.

The NSDateComponents class is usually used in combination with the NSCalendar class. To be more specific, NSCalendar methods perform the actual conversion from NSDate to NSDateComponents objects, and as we’ll see later, convert date components into date objects. With that in mind, the first thing we’ll do in this part is to get the current calendar and assign it to a constant for easy access:

Now, let’s see a typical example of how a NSDate object can be converted into a NSDateComponents object, and then I’ll make some comments about it:

t44_10_date_to_datecomponents

The method used in the first line above, is the components(_:fromDate:) of the NSCalendar class. This method accepts two parameters: The second is the source date that we want to get the components from. The first parameter however is the interesting one; the method expects as a first parameter an array of NSCalendarUnit properties that describe the components we want to extract from the date.

The NSCalendarUnit is a struct, and you can see all the available properties here. In the above example, and as you can find out in the screenshot that precedes the code segment, the calendar unit values specified above return the following date components:

  • Day
  • Month
  • Year
  • Week of year
  • Hour
  • Minute
  • Second
  • Nanosecond

Note that calendar units that are not specified in the first parameter array are not available for use after the method call. For example, as we don’t include the NSCalendarUnit.TimeZone unit in the above list, we cannot access the timezone as we do with the rest of the fetched components (e.g. print(dateComponents.timezone)). A runtime error will be caused. In case you need additional components, you must call the method once again specifying the calendar units you additionally want.

Going from date components to date objects is easy too. This time no use of the calendar units is involved in the process. All it is needed is to initialize a new NSDateComponents object, then to explicitly specify all the required components (required by your app of course), and then call the dateFromComponents: method of the NSCalendar class to make the conversion. Let’s see that:

t44_11_datecomponents_to_date

In the previous part we saw an example of using the timezone while we were converting a formatted string into a date object. If you’re curious enough to see the results of setting different timezones to a date, let’s extend a bit the above snippet given right above and let’s set multiple values for the timezone:

t44_12_timezones

GMT = Greenwich Mean Time
CST = China Standard Time
CET = Central European Time

You can find a list with all the timezone abbreviations and some cool online tools here.

Now you know how to deal with NSDateComponents objects too, so let’s move ahead to other interesting stuff.

Comparing Date and Time

Another common scenario when dealing with dates is the necessity to compare two date objects, and decide what’s the earlier or later date, or even if two dates are the same. Generally, I’m going to provide you with three different ways to compare date objects, without telling you what’s the best or the worst option. That clearly depends on what you want to do in your app, and as each method is slightly different from the others, it’s up to you to pick what serves you the most.

Before I start presenting the comparing methods, we’ll create two custom date objects for the sake of the examples in this part. Initially, we’ll set the date format (dateFormat property of the date formatter), and we will convert two formatted strings into date objects:

Let’s see now the first method for comparing dates. In case you want to determine the earlier or the later between two dates, then the NSDate class can help you a lot towards this effort as it provides two methods named earlierDate: and laterDate: respectively. The syntax when using any of those methods is simple:

date1.earlierDate(date2)

And here’s how it works:

  • If the date1 object is earlier than date2, then the above method will return the value of the date1.
  • If the date2 object is earlier than date1, then the value of the date2 will be returned.
  • If the dates are equal, then the date1 is returned again.

All the above apply for the laterDate: as well.

Let’s turn to our example now, and let’s use the date objects we created previously. The following two commands display the earlier and the later date, as both of the methods I just mentioned are used:

t44_13_compare_dates_1

The second method of comparing two NSDate objects involves the use of the compare: method of the NSDate class and the NSComparisonResult enum. You’ll understand what I mean with the following example, but before that, let me say that the syntax of the method is similar to what I showed above. The result of the comparison is checked against all possible values, and that way it’s easy to determine if two dates are equal or not, and to find the earlier or later date. Needless to say more, the next code segment speaks of itself:

t44_14_compare_dates2

Here’s the result displayed in the playground:

t44_15_compare_method2_result

And the code so you can copy it:

The third way to compare two date objects is somehow different, as it involves the use of time intervals. Actually, it’s a really simple method, as all it takes is to get the time interval since each date (time interval between now and each date), and then perform simple comparisons:

t44_16_compare_dates3

What you’ve seen above can be applied in time too. Right next I give you one last example, but this time the date1 and date2 objects contain time representations. Once again I make use of the earlierDate: method, but in addition to that I present you one more, the idEqualToDate:, which is too obvious what is for:

t44_17_compare_time

If by looking at the “2000-01-01” date in the above results you become curious or suspicious, then don’t worry. The NSDate adds this by default when no specific date is given for conversion, and it doesn’t interfere by any means to the rest of the date parts (in this case the time).

So, at this point you know how to compare dates too!

Calculating Future and Past Dates

An interesting aspect when working with dates is to calculate a date either in the future or in the past. Things we’ve already seen will become handy here again, such as the NSCalendarUnit struct, or the NSDateComponents class. Actually, I’m going to show you two different methods to calculate other dates, where the first makes use the NSCalendar class and the NSCalendarUnit struct, and the second makes use of the NSDateComponents class. At the end I’ll provide you with a third, alternative way, but generally it’s not recommended (I’ll say why when we’ll be there).

At first let’s remember again what’s current date (during the time of the writing of this tutorial), as it will be used as our reference date:

t44_18_current_date2

Now, let’s suppose that we want to add to the current date 2 months and 5 days. Actually, we’d better write that in code:

Now we’re ready to see the first method that will let us find the desired new date. Let me give you the code first, and then I’ll explain more:

As you see, the method used here is the dateByAddingUnit:value:toDate:options: of the NSCalendar class. It’s job is to add a specific calendar unit (the one specified in the first parameter) to an existing date, and to return a new date that is the outcome of that addition. In our case we want to add two different calendar units to the current date, but obviously that’s not possible to happen. So, the key here is to make subsequent calls to that method, and set each time another calendar unit so we eventually get the final result.

Here’s what the playground displays next to each addition:

t44_19_add_calendar_units

The above way is good, but only if you have 1-2 calendar units to add, otherwise you’ll have to make enough calls to the above method.

The second and more preferable way when having more units to add, is to put in action the NSDateComponents class once again. For the sake of the example, we won’t use more units than the months and days specified above. What we will do here is simple: At first we’ll initialize a new NSDateComponents object, and we’ll set the given month and day value. Then, we’ll call another method of the NSCalendar class named dateByAddingComponents:toDate:options: and instantly we’ll get a new NSDate object that represents the desired final date.

t44_20_add_date_components_to_date

Notice that in both of the newly introduced methods in the two code snippets above I don’t set any options at all in the last parameter. However, if you want to see more about the options you can specify, just visit the official documentation of the NSCalendar class.

The third way to calculate another date that is not generally recommended for big periods of time, because it can produce wrong results because of leap seconds, leap years, daylight saving time, and so on. The idea here is to add a specific time interval to the current date. For this purpose, we’ll use the dateByAddingTimeInterval: of the NSDate class. In the following example, we calculate a time interval matching to 1.5 hours and we add it to the current date:

Once again, the first two methods are more secure so as to make any kind of date calculations. However, it’s up to you to select the method you prefer.

All the above three examples were adding units in the current date. How about to subtract now a number of days from the current date and calculate that way a date in the past?

The following example does that exactly. At first, a negative amount of days is added to the current date, so it’s possible to result in a past date. Then the outcome is converted to a string with the proper formatting and the final result is quite… interesting:

t44_21_date_in_the_past

All the small code snippets and examples above are good enough to show you the way to calculate new dates by adding positive or negative calendar unit values to a reference date. Feel free to extend the above code fragments and write your own calculations, so you familiarize yourself even more with the above techniques.

Calculating Date Difference

As the title suggests, calculating the difference between two dates is another task that you might have to perform at some point in your programming career, and certainly more than once. In this (last) part of the tutorial, I’m going to give you three ways to calculate the difference of two NSDate objects, and you’ll pick the most suitable to you depending on your needs.

First things first, and before we start let’s define two custom NSDate objects:

With the above date objects ready, let’s see how we can get the date difference as date components. Once again, we’ll use the NSCalendar class and one of its methods that we haven’t seen yet. At the end, we’ll print the components so we see the results. Apparently, it’s easy to do whatever you want or need once you have available at your disposal the date components that represent the date difference. Let’s see how all this works:

t44_22_date_difference1

The new method presented here is the components:fromDate:toDate:options:, and once again the first parameter is an array of NSCalendarUnit values. Note that in case the first date is later than the second date, then the values are returned as negative numbers.

For the other two methods that calculate the date difference, we’re going to use for first time the NSDateComponentsFormatter class, which offers various methods that automatically perform the calculation and return a formatted string. At first, let’s initialize a respective object, and let’s specify just one of its properties for now:

The unitsStyle property dictates the dateComponentsFormatter how the final string that describes the date difference should be formatted, and more specifically, what should be the style of the displayed date units. For example, by using the Full style, the day name, the month name, etc., will be displayed as normal, full-length words. If however we would have used the Abbreviated style, then an abbreviation of those names would appear. You can find a full list regarding the units style here.

Back to the date difference, this time we’re going to calculate the time interval between the two dates first. Then, this interval will be passed as a parameter to the stringFromTimeInterval: method of the NSDateComponentFormatter class, and a formatted string will be printed with the desired difference:

t44_23_date_difference2

Finally, in the last way that I’m presenting you for calculating date difference, both dates must be provided as parameters to a method called stringFromDate:toDate: of the NSDateComponentsFormatter class. However, there’s a requirement needed to be fulfilled before using that method: At least one calendar unit must be set in a property named allowedUnits, otherwise the method will return a nil value. So, let’s “tell” it what units we desire to have, and then let it give us the difference:

t44_24_date_difference3

Summary

As I said in the introduction, working with NSDate objects in your projects is something quite common, and definitely it cannot be avoided. Undeniably, it’s not one of the most favorite topics of the programmers, therefore I tried in the previous parts and through small examples to show to you that is actually easy to deal with dates. All the aspects of the NSDate and the other related classes presented in this tutorial had one common goal: To give you small and fast techniques that will get your job done in just two or three lines of code. I’d like to hope that this content will work as a guide for you, especially if you’re a new developer. Until next time, keep… “dating”!

iOS
Building a Text to Speech App Using AVSpeechSynthesizer
SwiftUI
Getting Started with SwiftData for SwiftUI Development
Tutorial
Passing Data in iOS: Delegates, Notifications, and Closures
Shares