Return to site

Swift Date From String

broken image


Episode #367 | 18 minutes | published on December 13, 2018 | Uses swift-4.2, Xcode-10.1

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 Video
Working with dates is a task that is universally applicable to Swift developers. Particularly when dealing with an API, dates can arrive in all shapes and sizes. We‘ll examine some of the common ones such as ISO 8601, show how to parse these formats into Date instances, and how to use DateFormatter to display them back again as a string. We‘ll also cover the importance of using en_US_POSIX and honoring the user‘s Locale when displaying dates.

Want 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 use DateComponents.
  • Episode 219 - NSCalendar - Use NSCalendar if you ever need to do date math, like Add 1 day to this Date. Doing this without NSCalendar 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

Date

The following table's sample column are mostly based on the time December 14th, 2008 4:35 PM UTC.

CharacterExampleDescription
Year
yy082-digit year
yyyy20084-digit year
Quarter
Q4The quarter of the year. Use QQ if you want zero padding.
QQQQ4Quarter including 'Q'
QQQQ4th quarterQuarter spelled out
Month
M12The numeric month of the year. A single M will use '1' for January.
MM12The numeric month of the year. A double M will use '01' for January.
MMMDecThe shorthand name of the month
MMMMDecemberFull name of the month
MMMMMDNarrow name of the month
Day
d14The day of the month. A single d will use 1 for January 1st.
dd14The day of the month. A double d will use 01 for January 1st.
F3rd Tuesday in DecemberThe day of week in the month
ETuesThe day of week in the month
EEEETuesdayThe full name of the day
EEEEETThe narrow day of week
Hour
h4The 12-hour hour.
hh04The 12-hour hour padding with a zero if there is only 1 digit
H16The 24-hour hour.
HH16The 24-hour hour padding with a zero if there is only 1 digit.
aPMAM / PM for 12-hour time formats
Minute
m35The minute, with no padding for zeroes.
mm35The minute with zero padding.
Second
s8The seconds, with no padding for zeroes.
ss08The seconds with zero padding.
Time Zone
zzzCSTThe 3 letter name of the time zone. Falls back to GMT-08:00 (hour offset) if the name is not known.
zzzzCentral Standard TimeThe expanded time zone name, falls back to GMT-08:00 (hour offset) if name is not known.
zzzzCST-06:00Time zone with abbreviation and offset
Z-0600RFC 822 GMT format. Can also match a literal Z for Zulu (UTC) time.
ZZZZZ-06:00ISO 8601 time zone format
Please enable JavaScript to view the comments powered by Disqus.blog comments powered by Disqus

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.

Date

The following table's sample column are mostly based on the time December 14th, 2008 4:35 PM UTC.

CharacterExampleDescription
Year
yy082-digit year
yyyy20084-digit year
Quarter
Q4The quarter of the year. Use QQ if you want zero padding.
QQQQ4Quarter including 'Q'
QQQQ4th quarterQuarter spelled out
Month
M12The numeric month of the year. A single M will use '1' for January.
MM12The numeric month of the year. A double M will use '01' for January.
MMMDecThe shorthand name of the month
MMMMDecemberFull name of the month
MMMMMDNarrow name of the month
Day
d14The day of the month. A single d will use 1 for January 1st.
dd14The day of the month. A double d will use 01 for January 1st.
F3rd Tuesday in DecemberThe day of week in the month
ETuesThe day of week in the month
EEEETuesdayThe full name of the day
EEEEETThe narrow day of week
Hour
h4The 12-hour hour.
hh04The 12-hour hour padding with a zero if there is only 1 digit
H16The 24-hour hour.
HH16The 24-hour hour padding with a zero if there is only 1 digit.
aPMAM / PM for 12-hour time formats
Minute
m35The minute, with no padding for zeroes.
mm35The minute with zero padding.
Second
s8The seconds, with no padding for zeroes.
ss08The seconds with zero padding.
Time Zone
zzzCSTThe 3 letter name of the time zone. Falls back to GMT-08:00 (hour offset) if the name is not known.
zzzzCentral Standard TimeThe expanded time zone name, falls back to GMT-08:00 (hour offset) if name is not known.
zzzzCST-06:00Time zone with abbreviation and offset
Z-0600RFC 822 GMT format. Can also match a literal Z for Zulu (UTC) time.
ZZZZZ-06:00ISO 8601 time zone format
Please enable JavaScript to view the comments powered by Disqus.blog comments powered by Disqus

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:

  1. c[a-z]*d
  2. c[a-z]+d
  3. 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!





broken image