DST, DateEncodingStrategy.iso8601, and UTC Fun

Hello,

My code calls a macOS system library which returns Foundation Date properties. I have a program that will run every night, and output the data via the Swift JSONEncoder and uses DateEncodingStrategy.iso8601. As you likely know, a DST shift happened over the weekend here in the US. In my output, every single Date changed by 1 hour, despite the fact that nothing in the underlying data changed overnight. Here is an example diff in the output. I see the "Z", which I think should not be affected by DST changes.

-    "dateAdded" : "2003-12-15T17:02:56Z",
-    "dateModified" : "2007-03-07T04:31:16Z",
+    "dateAdded" : "2003-12-15T18:02:56Z",
+    "dateModified" : "2007-03-07T05:31:16Z",

Here is a sample of the data:

public struct Track: Codable, Hashable {
  var dateAdded: Date?
  var dateModified: Date?
}

And the encoding is here:

extension Array where Element == Track {
  public func jsonData() throws -> Data {
    let encoder = JSONEncoder()
    encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
    encoder.dateEncodingStrategy = .iso8601

    return try encoder.encode(self)
  }
}

Pretty basic stuff overall. So my questions are:

  • Am I correct in my assumption that .iso8601 is UTC, and that UTC is daylight savings shift agnostic?
  • Is this the right way to ensure the my JSON is encoded in UTC?
  • If the library I am calling is building its Date incorrectly, how may I work around the problem?

I'm not reporting the library name right now, in order to ensure that my code is doing the right thing without assumptions.

Thanks for any tips!

Am I correct in my assumption that .iso8601 is UTC, and that UTC is daylight savings shift agnostic?

GMT [1] definitely doesn’t have DST.

Our ISO-8601 support uses GMT by default. You can override this in some contexts but, in this context, the JSONEncoder.DateEncodingStrategy.iso8601 strategy will always get you GMT.

Is this the right way to ensure the my JSON is encoded in UTC?

Yes.

If the library I am calling is building its Date incorrectly, how may I work around the problem?

That depends on exactly what it’s doing wrong.

Do you have code for that library?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Technically, Foundation using GMT, not UTC, but that’s a very fine distinction that’s irrelevant to your issue.

That depends on exactly what it’s doing wrong. Do you have code for that library?

No, it's iTunesLibrary in macOS. All of my code is on my GitHub.

Adding to the debugging clues, last night it returned dateModified values back in line with what they were before the DST change! I'm guessing that somewhere deep in that code it was not fully aware DST has changed. Strangely, the dateAdded changes remain.

I know this will sound crazy, but I think iTunes has had this bug since at least 2007, when I started dumping its data regularly!

No, it's iTunesLibrary in macOS.

Awkward (-:

So, we’re talking about those properties on ITLibMediaItem, right?

Those return an NSDate, or Date in Swift. Under the covers a Date is the count of the number of seconds from the reference date (the beginning of 2001 in GMT). So the date values you get back from the API should not vary across DST changes. If they do, I’d consider that a bug and, if you can reproduce this, I recommend that you file a bug about it. Please post your bug number, just for the record.

As you strive to reproduce this, one good option is to get, say, the dateAdded property and print its timeIntervalSinceReferenceDate property. That shouldn’t change regardless of what’s going on with your local time zone.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for your suggestion of changing my Mac's Time Zone to reproduce the bug! I filed FB15767197 with a simple program attached to that bug.

The bad Dates occur with both MusicKit and iTunesLibrary, so hopefully the underlying bug can be fixed for them both.

DST, DateEncodingStrategy.iso8601, and UTC Fun
 
 
Q