0

How to deal with the new year and ISO8601 returning last year as year component.

To my horror, I realized ISO8601DateFormatter was returning 1977 as a year to the 1978-01-01 00:00:00

It took a while to realize this. That turned out is not wrong. Nonetheless, given the specific year of 1978, for the formatted to return 1977 is shocking.

I don't even need the timestamp. How can I reliably retrieve the specified year without having to add a second to every calendar date?

import Foundation

let datestring = "1978/1/1"
var formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(abbreviation: "UTC")
formatter.formatOptions = [.withFullDate]
let date2 = formatter.date(from: datestring) ?? Date()
print(date2)
var calendar = Calendar(identifier: .iso8601)
var year = calendar.component(.year, from: date2)
var month = calendar.component(.month, from: date2)
var day = calendar.component(.day, from: date2)
var era = calendar.component(.era, from: date2)
print("year \(year) month \(month) day \(day) era: \(era)")

===
1978-01-01 00:00:00 +0000
year 1977 month 12 day 31 era: 1
jonkimsr
  • 31
  • 1
  • 6

1 Answers1

1

By default the Calendar instance will have your local timeZone. You can see this by printing print(calendar.timeZone.abbreviation() ?? "UNKNOWN"). In my case (in Seattle, WA, USA) it prints "PDT". If you simply set your calendar timezone to UTC it prints exactly what you expect:

year 1978 month 1 day 1 era: 1

creeperspeak
  • 5,403
  • 1
  • 17
  • 38
  • formatter.timeZone = TimeZone(abbreviation: "PDT") 1978-01-01 08:00:00 +0000 year 1978 month 1 day 1 era: 1 datestring2 : 1978-01-01 It did. Thank you. I actually added "UTC" only as a test. When timeZone is not set, shouldn't the app default to the device's local setting automatically? But If I remove UTC, I still get error. – jonkimsr Jun 08 '21 at 22:51
  • I see that for both reading and formatting local timezone gets used. Both end has to sync. Thank you!! https://stackoverflow.com/questions/50052873/using-dateformatter-with-timezone-to-format-dates-in-swift – jonkimsr Jun 08 '21 at 23:01
  • formatter.timeZone = TimeZone(abbreviation: "UTC") calendar.timeZone = TimeZone.init(abbreviation: "UTC") – jonkimsr Jun 08 '21 at 23:04
  • just don't set the timezone. It is already set at UTC and it is a heavy operation – Leo Dabus Jun 08 '21 at 23:16
  • /* Please note that there can be a significant performance cost when resetting these properties. Resetting each property can result in regenerating the entire CFDateFormatterRef, which can be very expensive. */ I see what you mean by heavy. Thank You!. – jonkimsr Jun 09 '21 at 21:50
  • open var timeZone: TimeZone! // The default time zone is GMT. * ISO8601DateFormatter default is GMT. Not UTC. – jonkimsr Jun 09 '21 at 21:54