Challenges of DateFormatters
Working with DateFormatters is tough - At least on iOS. Today I will show with an example how I shot myself in the foot while working with simple DateFormatters problem.
Here's the problem statement:
I had an UI where user would choose month and year through a simple picker and those values get sent to the server. So I created a date picker like this,
let formatter = DateFormatter()
formatter.dateFormat = "MM/YYYY"
In essence, we give this formatter an input string containing both month and year value and formatter spits out the `Date` object. Let's try to verify with some examples,
// Prints Optional(2017-12-24 05:00:00 +0000)
print(formatter.date(from: "12/2018"))
// Prints Optional(2017-12-24 05:00:00 +0000)
print(formatter.date(from: "11/2018"))
// Prints Optional(2017-12-24 05:00:00 +0000)
print(formatter.date(from: "10/2018"))
Hey!!! what's going on here? Looks like our string didn't get converted to expected Date
object. Answer lies somewhere else. Fortunately I found this post which explains the difference between yyyy
and YYYY
formatter values. To say, it in Apple words,
A common mistake is to use YYYY. yyyy specifies the calendar year whereas YYYY specifies the year (of “Week of Year”), used in the ISO year-week calendar. In most cases, yyyy and YYYY yield the same number, however they may be different. Typically you should use the calendar year.
And to quote X-Factor,
Also when using a date format string using the correct format is important.
@"YYYY" is week-based calendar year.
@"yyyy" is ordinary calendar year.
So in this case we certainly want a regular calendar year which necessitates the use of yyyy
instead. Let's fix the problem now,
let formatter = DateFormatter()
formatter.dateFormat = "MM/yyyy"
And verify the previous logic with new DateFormatter
// Prints Optional(2018-12-01 05:00:00 +0000)
print(formatter.date(from: "12/2018"))
// Prints Optional(2018-11-01 05:00:00 +0000)
print(formatter.date(from: "11/2018"))
// Prints Optional(2018-10-01 05:00:00 +0000)
print(formatter.date(from: "10/2018"))
Which is what we wanted and it worked like a charm!
It was a very silly mistake besides the fact that Apple has made it more confusing by using such nomenclature. We has a hard time figuring this out especially when this code was the least suspected. Something to keep in mind when I am dealing with DateFormatters
next time.