Date formatter syntax is a bit weird the first time you see it, but you can learn more about different date formats from the Apple Developer Documentation here. Finally, our extension returns a date from a string in the specified format. If the conversion from string to date fails, the extension will simply return today's date. Could not cast value of type ‘Swift.Optional' (0x1192bf4a8) to ‘NSTimeZone' (0x1192c0270). The value of rowEvents.date is '.0' Im trying to pull out a Unix timestamp from Firebase saved as a string. Convert it to Date and again save it as a string so I can post it on a cell label. I got this code from StackOverflow.
Free VideoWant more? Subscribers can view all 466 episodes. New episodes are released regularly.
Episode Links
- NSDateFormatter.com - A useful website that uses
DateFormatter
live on the server. Use it to play around with different formats and locales to test your format strings. - Working with Date and Time - a fantastic blog post covering tons of useful (and esoteric) concepts relating to dates, times, and calendars. Read it.
Related Screencasts
- Episode 171 - NSDateComponents - If you need to extract the day, year, month, etc from a
Date
instance, you useDateComponents
. - Episode 219 - NSCalendar - Use
NSCalendar
if you ever need to do date math, like Add 1 day to this Date. Doing this withoutNSCalendar
is probably going to bite you in the long run.
Parsing Dates
Parsing dates is what is referred to when we take a raw value (say a String
or Int
) and convert it into a Date
instance we can work with in our application. This is because most of the time we have to transfer these values to and from databases, files on disk, JSON representations from APIs and so on.
To parse a date, we'll use a DateFormatter
: Blackmagic design fusion studio 16 1 0 download free.
How did I know what date format to use? Check the table above or go to NSDateFormatter.com.
A more common date format we'll see are those that come from APIs in a format like this:
This is in ISO 8601 format, which is the most common standard that we'll run into.
For the format string, we'll use:
The 'Z'
here refers to the time zone, and if the date
Setting the locale to en_US_POSIX
is strongly recommended when parsing dates from a server to avoid issues with the device's local settings. For some background on why, read this Tech note from Apple.
Displaying dates to the user
Once you have a Date
, you might be tempted to do something like this:
This will produce a result that might look okay in the US, but international users will be annoyed (and worse, this date could be ambiguous.. is 12/10/2018 December 10th, or October 12th?).
Instead, utilize the built-in formats for displaying that will honor the user's locale:
But if we're in the UK:
Note the 2 digit year.
And if we're in Germany?
Turns out the periods are the accepted standard. In addition, DateFormatter
has already translated names for you, so you don't have to worry about it:
Here not only are the words translated, but the month isn't capitalized.
There are dozens of difference in how users expect their dates to be displayed. Let DateFormatter
do the hard work and don't use a custom format string for displaying dates.
Codable
Let's say we have a model locally and we need to produce JSON:
This prints:
That date looks weird.. How can we support ISO 8601? Turns out that JSONEncoder
has a built-in way to customize the date formats:
Now we get:
Perfect!
ISO 8601 With Milliseconds
I have run into a variant of ISO 8601 that includes milliseconds. How would we produce this?
Do do this we have to provide our own date formatter and include this in the format string:
Here we added .SSS
to our format string to include 3 decimal places for fractional seconds.
There's also a lesser known type called ISO8601DateFormatter
. This looks handy! Use it like this:
Swift Convert Date To String
There are some other interesting options for formatOptions
so take a look at how you can customize it further.
Unfortunately, ISO8601DateFormatter
doesn't inherit from DateFormatter
, so we can't use this as a formatter like this:
Instead, we'd have to use the .custom((Date, Encoder) -> Void)
and encode the date inside the block.
Common Date Formats
The following table's sample column are mostly based on the time December 14th, 2008 4:35 PM UTC
.
Character | Example | Description |
---|---|---|
Year | ||
yy | 08 | 2-digit year |
yyyy | 2008 | 4-digit year |
Quarter | ||
Q | 4 | The quarter of the year. Use QQ if you want zero padding. |
QQQ | Q4 | Quarter including 'Q' |
QQQQ | 4th quarter | Quarter spelled out |
Month | ||
M | 12 | The numeric month of the year. A single M will use '1' for January. |
MM | 12 | The numeric month of the year. A double M will use '01' for January. |
MMM | Dec | The shorthand name of the month |
MMMM | December | Full name of the month |
MMMMM | D | Narrow name of the month |
Day | ||
d | 14 | The day of the month. A single d will use 1 for January 1st. |
dd | 14 | The day of the month. A double d will use 01 for January 1st. |
F | 3rd Tuesday in December | The day of week in the month |
E | Tues | The day of week in the month |
EEEE | Tuesday | The full name of the day |
EEEEE | T | The narrow day of week |
Hour | ||
h | 4 | The 12-hour hour. |
hh | 04 | The 12-hour hour padding with a zero if there is only 1 digit |
H | 16 | The 24-hour hour. |
HH | 16 | The 24-hour hour padding with a zero if there is only 1 digit. |
a | PM | AM / PM for 12-hour time formats |
Minute | ||
m | 35 | The minute, with no padding for zeroes. |
mm | 35 | The minute with zero padding. |
Second | ||
s | 8 | The seconds, with no padding for zeroes. |
ss | 08 | The seconds with zero padding. |
Time Zone | ||
zzz | CST | The 3 letter name of the time zone. Falls back to GMT-08:00 (hour offset) if the name is not known. |
zzzz | Central Standard Time | The expanded time zone name, falls back to GMT-08:00 (hour offset) if name is not known. |
zzzz | CST-06:00 | Time zone with abbreviation and offset |
Z | -0600 | RFC 822 GMT format. Can also match a literal Z for Zulu (UTC) time. |
ZZZZZ | -06:00 | ISO 8601 time zone format |
Regular expressions allow us to run complex search and replace operations across thousands of text files in just a handful of seconds, so it's no surprise they have been popular for over 50 years. Apple provides support for regular expressions on all of its platforms – iOS, macOS, tvOS, and even watchOS – all using the same class, NSRegularExpression
. It's an extremely fast and efficient way to search and replace complex text tens of thousands of times, and it's all available for Swift developers to use.
In this tutorial you'll learn how to create regular expressions using NSRegularExpression
, and how to match a variety of regular expressions using the most important syntax. For more advanced regular expression work, I've written a separate article that follows on from this one: Advanced regular expression matching with NSRegularExpression.
First, the basics
Let's start with a couple of easy examples for folks who haven't used regular expressions before. Regular expressions – regexes for short – are designed to let us perform fuzzy searches inside strings. For example, we know that 'cat'.contains('at')
is true but what if we wanted to match any three-letter word that ends in 'at'?
This is what regexes are designed to solve, although they use slightly clumsy syntax thanks to their Objective-C roots.
First you define the string you want to check:
Next you create an NSRange
instance that represents the full length of the string:
That uses the utf16
count to avoid problems with emoji and similar.
The following table's sample column are mostly based on the time December 14th, 2008 4:35 PM UTC
.
Character | Example | Description |
---|---|---|
Year | ||
yy | 08 | 2-digit year |
yyyy | 2008 | 4-digit year |
Quarter | ||
Q | 4 | The quarter of the year. Use QQ if you want zero padding. |
QQQ | Q4 | Quarter including 'Q' |
QQQQ | 4th quarter | Quarter spelled out |
Month | ||
M | 12 | The numeric month of the year. A single M will use '1' for January. |
MM | 12 | The numeric month of the year. A double M will use '01' for January. |
MMM | Dec | The shorthand name of the month |
MMMM | December | Full name of the month |
MMMMM | D | Narrow name of the month |
Day | ||
d | 14 | The day of the month. A single d will use 1 for January 1st. |
dd | 14 | The day of the month. A double d will use 01 for January 1st. |
F | 3rd Tuesday in December | The day of week in the month |
E | Tues | The day of week in the month |
EEEE | Tuesday | The full name of the day |
EEEEE | T | The narrow day of week |
Hour | ||
h | 4 | The 12-hour hour. |
hh | 04 | The 12-hour hour padding with a zero if there is only 1 digit |
H | 16 | The 24-hour hour. |
HH | 16 | The 24-hour hour padding with a zero if there is only 1 digit. |
a | PM | AM / PM for 12-hour time formats |
Minute | ||
m | 35 | The minute, with no padding for zeroes. |
mm | 35 | The minute with zero padding. |
Second | ||
s | 8 | The seconds, with no padding for zeroes. |
ss | 08 | The seconds with zero padding. |
Time Zone | ||
zzz | CST | The 3 letter name of the time zone. Falls back to GMT-08:00 (hour offset) if the name is not known. |
zzzz | Central Standard Time | The expanded time zone name, falls back to GMT-08:00 (hour offset) if name is not known. |
zzzz | CST-06:00 | Time zone with abbreviation and offset |
Z | -0600 | RFC 822 GMT format. Can also match a literal Z for Zulu (UTC) time. |
ZZZZZ | -06:00 | ISO 8601 time zone format |
Regular expressions allow us to run complex search and replace operations across thousands of text files in just a handful of seconds, so it's no surprise they have been popular for over 50 years. Apple provides support for regular expressions on all of its platforms – iOS, macOS, tvOS, and even watchOS – all using the same class, NSRegularExpression
. It's an extremely fast and efficient way to search and replace complex text tens of thousands of times, and it's all available for Swift developers to use.
In this tutorial you'll learn how to create regular expressions using NSRegularExpression
, and how to match a variety of regular expressions using the most important syntax. For more advanced regular expression work, I've written a separate article that follows on from this one: Advanced regular expression matching with NSRegularExpression.
First, the basics
Let's start with a couple of easy examples for folks who haven't used regular expressions before. Regular expressions – regexes for short – are designed to let us perform fuzzy searches inside strings. For example, we know that 'cat'.contains('at')
is true but what if we wanted to match any three-letter word that ends in 'at'?
This is what regexes are designed to solve, although they use slightly clumsy syntax thanks to their Objective-C roots.
First you define the string you want to check:
Next you create an NSRange
instance that represents the full length of the string:
That uses the utf16
count to avoid problems with emoji and similar.
Next you create an NSRegularExpression
instance using some regex syntax:
[a-z]
is regex's way of specifying any letter from 'a' through 'z'. This is a throwing initializer because you might attempt to provide an invalid regular expression, but here we have hard-coded a correct regex so there's no need to try to catch errors.
Finally, you call firstMatch(in:)
on the regex you created, passing the string to search, any special options, and what range of the string to look inside. If your string matches the regex then you'll get data back, otherwise nil. So, if you just want to check that the string matched at all, compare the result of firstMatch(in:)
against nil, like this:
The use of NSRange
is unfortunate, but sadly required right now – this API was designed for NSString
and bridges poorly to Swift. The Swift String Manifesto does mention possible replacements, but these seem quite far away at the time of writing.
The regex '[a-z]at' will successfully match 'hat', as well as 'cat', 'sat', 'mat', 'bat', and so on – we focus on what we want to match, and NSRegularExpression
does the rest.
SPONSORED Ever ask for help and your reviewer immediately notices issues you missed? Fernando Olivares is a 10-year veteran from Big Nerd Ranch and Lambda School who can help hone your app building skills, and he's just launched a new book that does just that – use the code 'hacking' to save $5!
Making NSRegularExpression easier to use
We'll look at more regex syntax in a moment, but first let's see if we can make NSRegularExpression
a little friendlier.
Right now our code takes three lines of non-trivial Swift to match a simple string:
We can improve this in a variety of ways, but probably the most sensible is to extend NSRegularExpression
to make creating and matching expressions easier.
First, this line:
Date Time Formatter Swift
Seo checker 1 5 – seo checker. As I said, creating an instance of NSRegularExpression
can throw errors because you might try to provide an illegal regular expression – [a-zat
, for example, is illegal because we haven't closed the ]
.
However, most of the time your regular expressions will be hard-coded by you: there are specific things you want to search for, and they are either correct or incorrect at compile time. If you make a mistake with these it's not something you should really try to correct for at runtime, because you're just hiding a coding error.
As a result, it's common to create NSRegularExpression
instances using try!
. However, that can cause havoc with linting tools like SwiftLint, so a better idea is to create a convenience initializer that either creates a regex correctly or creates an assertion failure when you're developing:
Note: If your app relies on regular expressions that were entered by your user, you should stick with the regular NSRegularExpression(pattern:)
initializer so you can handle the inevitable errors gracefully.
Second, these lines:
The first one creates an NSRange
encompassing our entire string, and the second looks for the first match in our test string. This is clumsy: most of the time you're going to want to search the entire input string, and using firstMatch(in:)
along with a nil check really muddies your intent.
So, let's replace that with a second extension that wraps those lines up in a single matches()
method:
If we put these two extensions together we can now make and check regexes much more naturally:
We could take things further by using operator overloading to make Swift's contains operator, ~=
, work with regular expressions:
That code lets us use any string on the left and a regex on the right, all in one:
Note: There is a cost to creating an instance of NSRegularExpression
, so if you intend to use a regex repeatedly it's probably better to store the NSRegularExpression
instance.
A tour of regular expression syntax
We already used [a-z]
to mean 'any letter from 'a' through 'z', and in regex terms this is a character class. This lets you specify a group of letters that should be matched, either by specifically listing each of them or by using a character range.
Regex ranges don't have to be the full alphabet if you prefer. You can use [a-t]
to exclude the letters 'u' through 'z'. On the other hand, if you want to be specific about the letters in the class just list them individually like this:
Regexes are case-sensitive by default, which means 'Cat' and 'Mat' won't be matched by '[a-z]at'. If you wanted to ignore letter case then you can either use '[a-zA-Z]at' or create your NSRegularExpression
object with the flag .caseInsensitive
.
As well as the uppercase and lowercase ranges, you can also specify digit ranges with character classes. This is most commonly [0-9]
to allow any number, or [A-Za-z0-9]
to allow any alphanumerical letter, but you might also use [A-Fa-f0-9]
to match hexadecimal numbers, for example.
If you want to match sequences of character classes you need a regex concept called quantification: the ability to say how many times something ought to appear.
One of the most common is the asterisk quantifier, *
, which means 'zero or more matches.' Quantifiers always appear after the thing they are modifying, so you might write something like this:
That looks for 'ca', then zero or more characters from 'a' through 'z', then 'd' – it matches 'cad', 'card', 'camped', and more.
As well as *
, there are two other similar quantifiers: +
and ?
. If you use +
it means 'one or more', which is ever so slightly different from the 'zero or more' of *
. And if you use ?
it means 'zero or one.'
These quantifiers are really fundamental in regexes, so I want to make sure you really understand the difference between them. So, consider these three regexes:
c[a-z]*d
c[a-z]+d
c[a-z]?d
I want you to look at each of those three regexes, then consider this: when given the test string 'cd' what will each of those three match? What about when given the test string 'camped'?
The first regex c[a-z]*d
Cardhop 1 0 5 – manage your contacts address book. means 'c then zero or more lowercase letters, then d,' so it will match both 'cd' and 'camped'.
The second regex c[a-z]+d
means 'c then one or more lowercase letters, then d,' so it won't match 'cd' but will match 'camped'.
Finally, the third regex c[a-z]?d
means 'c then zero or one lowercase letters, then d,' so it will match 'cd' but not 'camped'.
Quantifiers aren't just restricted to character classes. For example, if you wanted to match the word 'color' in both US English ('color') and International English ('colour'), you could use the regex colou?r
. That is, 'match the exact string ‘colo', the match zero or one ‘u's, then an ‘r'.'
If you prefer, you can also be more specific about your quantities: 'I want to match exactly three characters.' This is done using braces, {
and }
. For example [a-z]{3}
means 'match exactly three lowercase letters.'
Consider a phone number formatted like this: 111-1111. We want to match only that format, and not '11-11', '1111-111', or '11111111111', which means a regex like [0-9-]+
would be insufficient. Instead, we need to a regex like this: [0-9]{3}-[0-9]{4}
: precisely three digits, then a dash, then precisely four digits.
Swift Format Date
You can also use braces to specify ranges, either bounded or unbounded. For example, [a-z]{1,3}
means 'match one, two, or three lowercase letters', and [a-z]{3,}
means 'match at least three, but potentially any number more.'
Finally, meta-characters are special characters that regexes give extra meaning, and at least three of them are used extensively.
First up, the most used, most overused, and most abused of these is the .
character – a period – which will match any single character except a line break. So, the regex c.t
will match 'cat' but not 'cart'. If you use .
with the *
quantifier it means 'match one or more of anything that isn't a line break,' which is probably the most common regex you'll come across.
The reason for its use should be easy to recognize: you don't need to worry about crafting a specific regex, because .*
will match almost everything. The problem is, being specific is sort of the point of regular expressions: you can search for precise variations of text in order to apply some processing – too many people rely on .*
as a crutch, without realizing it can introduce subtle mistakes into their expressions.
As an example, consider the regex we wrote to match phone numbers like 555-5555: [0-9]{3}-[0-9]{4}
. You might think 'maybe some people will write '555 5555' or '5555555', and try to make your regex looser by using .*
instead, like this: [0-9]{3}.*[0-9]{4}
.
But now you have a problem: that will match '123-4567', '123-4567890', and even '123-456-789012345'. In the first instance, the .*
will match '-'; in the second, it will match '-456'; and in the third it will match '-456-78901' – it will take as much as needed in order for the [0-9]{3}
and [0-9]{4}
matches to work.
Instead, you can use character classes with quantifiers, for example [0-9]{3}[ -]*[0-9]{4}
means 'find three digits, then zero or more spaces and dashes, then four digits.' or negated character classes. You can also use negated character classes to match anything that isn't a digit, so [0-9]{3}[^0-9]+[0-9]{4}
will match a space, a dash, a slash, and more – but it won't match numbers.
Where next?
This has been a brief introduction to regular expressions, but I hope it's given you a taste of what they are capable of – and how to make them a little friendlier in Swift.
If you're keen to learn more about regular expression functionality – including grouping, lookahead, and lazy matching – you should check out my book Beyond Code. It covers all those and a heck of a lot more, and includes a massive collection of videos demonstrating techniques.
I also have an article that goes into more detail on how the options for NSRegularExpression
work: Advanced regular expression matching with NSRegularExpression.
Swift Date From Utc String
SPONSORED Ever ask for help and your reviewer immediately notices issues you missed? Fernando Olivares is a 10-year veteran from Big Nerd Ranch and Lambda School who can help hone your app building skills, and he's just launched a new book that does just that – use the code 'hacking' to save $5!