Working with dates in Swift
Swift has powerful built-in functions which makes it easy to work with dates
Let’s start with the basics
Getting current date
let date = Date()
This gives the system date using the current user locale
Getting date components
To get different components from the date (i.e. day, month, year etc.) we can use dateComponents function from current Calendar instance
let components = Calendar.current.dateComponents(
[.day, .month, .year], from: date)
This gives the requested components in this case day, month, year from the given date. We can access them as below
let day = components.day
let month = components.month
let year = components.year
These are optionals so make sure to properly unwrap them before using
In addition to day, month & year there are several others components that can be obtained from a given date
Some of the most commonly used are
- .timezone to get Timezone information
- .hour, .minute, .second to get time information
- .weekday to get the number indicating the current day of the week
- .weekOfYear to get week number in the year
We can also use component(_:from:) function to get a single component from the given date
Creating date from Date Components
You can also create a new date from Date Components
var components = DateComponents()
components.timeZone = TimeZone(abbreviation: “GMT”)
components.day = 2
components.month = 8
components.year = 2021let date = Calendar.current.date(from: components)
Calendar.current.date(from:) returns an optional
You can also create components using DateComponents constructor. But I prefer the above approach 😬
let components = DateComponents(
timeZone: TimeZone(abbreviation: “GMT”),
year: 2021,
month: 8,
day: 2)
Comparing & advancing dates
You can compare the dates using the comparison operators (<, >, ≤, ≥, ==, !=)
To advance the date by a specific interval we can use either addTimeInterval or addingTimeInterval instance methods on date object. While the former changes the date in place, the later gives a new date object.
We need to pass no. of seconds to advance as the parameter to both these functions.
// Changing date in-place
var date = Date()// advancing by one day
date.addTimeInterval(86400) // Creating new date
var date = Date()let newDate = date.addingTimeInterval(-86400)
If we pass negative number as parameter then the date goes backwards. There is also one more method advanced(by:) which is same as addTimeInterval
Difference between two dates
Most often we want to know difference between two given dates. Swift has an instance method called distance(to:) just for this purpose. This method gives the difference in number of seconds
let today = Date()let date = Calendar.current.date(
from: DateComponents(timeZone: TimeZone(abbreviation: “GMT”),
year: 2021, month: 8, day: 2))!date.distance(to: today)
This will give the no. of seconds as output. We can divide it by 86400 i.e. no. of seconds in a day to get the difference in days
Getting next / previous dates
We can find the next or previous date matching a certain criteria using Calendar’s nextDate function. It return an optional Date
nextDate(after:, matching:, matchingPolicy:, repeatedTimePolicy:, direction:) -> Date?
Let’s explore in detail how this function works
after → starting date from which the next / previous date need to be calculated
matching → date components used to search
matchingPolicy → matching technique used by the search algorithm, it is defaulted to .nextTime
repeatedTimePolicy → when multiple dates are found by search algorithm this attribute specify which date to return, it is defaulted to .first
direction → indicate whether to search forward or backward from the given date, it is defaulted to .forward
It might be daunting to look, but it’s easy to understand in code. Let’s see it in action.
Finding next date
The following example finds the next date matching the day component of the given date. For example if today date is September 5th 2021 then nextDate will give us October 5th 2021 as the result when matching day component
let today = Date()let components = Calendar.current.dateComponents([.day],
from: today)let nextDate = Calendar.current.nextDate(
after: today,
matching: components,
matchingPolicy: .nextTime,
repeatedTimePolicy: .first,
direction: .forward)
Finding previous date
If we want to go back from the given date we just need to specify the direction parameter as .backward.
let lastDate = Calendar.current.nextDate(
after: today,
matching: components,
matchingPolicy: .nextTime,
repeatedTimePolicy: .first,
direction: .backward)
Finding list of matching dates
As we have seen in the previous example we can find next or previous date using nextDate function. But what if we want to find let’s say next 10 dates that match the criteria. How about looping through nextDate function 10 times?
Swift has a much cleaner way to achieve this. We can use enumerateDates Calendar function
It is similar to nextDate function except it takes an additional parameter a closure.
Let’s see it in action
let today = Date()let components = Calendar.current.dateComponents(
[.day], from: today)var count = 0Calendar.current.enumerateDates(
startingAfter: today,
matching: components,
matchingPolicy: .nextTime,
repeatedTimePolicy: .first,
direction: .forward) { (date, strict, stop) in count += 1 print(date) if count == 10 {
stop = true
}
}
The trailing closure has 3 parameters
The 1st parameter is the date that matched the criteria. It is an optional.
The 2nd parameter is the matching policy
The 3rd parameter is an inout Bool. If we want to stop the search we need to set its value to true inside the closure. Failing to set it may result in an infinite loop.
Conclusion
Swift’s Calendar and Date structs have many functions and properties that you can use to make your life easy when working with dates
Pro Tip: When you are comparing two dates make sure they are in the same timezone :)