Home > Software design >  DateFormatter returns previous day
DateFormatter returns previous day

Time:08-07

I've looked around and people have had problems with different years, random and changing results, and nil dates, but nothing like what I have, so I am asking here. Note I am in Playground right now.

I am taking strings in the format of "yyyy-mm-dd" and converting them to a different date format. Here is the code:

let example = "2001-11-03"

let dateFormatterInput = ISO8601DateFormatter()
dateFormatterInput.formatOptions = [.withFullDate, .withDashSeparatorInDate]

let date = dateFormatterInput.date(from: example)

let dateFormatterOutput = DateFormatter()
dateFormatterOutput.dateFormat = "MMMM dd, yyyy"
let output = dateFormatterOutput.string(from: date!)

The sidebar in Playground shows that the first reference to the previous day's date happens on the let date line. Also, this behavior happens on every date I've tried. In this example, it returns "November 2, 2001." I've tried different months, days, and years (1900s and 2000s) and it gives me the same result every time.

What am I doing wrong?

CodePudding user response:

The key thing here is that ISO8601DateFormatter by default thinks that the time zone of your date string is GMT:

ISO8601DateFormatter.timeZone:

The time zone used to create and parse date representations. When unspecified, GMT is used.

However, the timeZone of DateFormatter by default (and also the side bar of the playground) assumes your device's local time zone:

DateFormatter.timeZone

The time zone for the receiver. If unspecified, the system time zone is used.

If your system time zone has a negative UTC offset on the start of the day 2001-11-03 UTC, then when seen from your time zone, that moment is actually in the day 2001-11-02. Hence the output you see.

Assuming you don't care about the actual value of date, and just care about the final string output, you can just set the timeZone of DateFormatter to GMT:

dateFormatterOutput.timeZone = TimeZone(identifier: "GMT")

Side note: You should also set locale when using a fixed format to avoid localisation issues:

dateFormatterOutput.locale = Locale(identifier: "en_US_POSIX")

Or better, just use one of the built-in, locale sensitive formats instead:

dateFormatterOutput.dateStyle = .medium
dateFormatterOutput.timeStyle = .none
  • Related