Thursday, February 29, 2024
HomeiOS DevelopmentWorking with dates and Codable in Swift – Donny Wals

Working with dates and Codable in Swift – Donny Wals


If you’re decoding JSON, you’ll run into conditions the place you’ll should decode dates each now and again. Mostly you’ll in all probability be coping with dates that conform to the ISO-8601 normal however there’s additionally a great likelihood that you just’ll should cope with totally different date codecs.

On this publish, we’ll check out how one can leverage a few of Swift’s built-in date codecs for en- and decoding information in addition to offering your personal date format. We’ll have a look at a few of the up- and drawbacks of how Swift decodes dates, and the way we will presumably work round a few of the downsides.

This publish is a part of a sequence I’ve on Swift’s codable so I extremely suggest that you just check out my different posts on this subject too.

Exploring the default JSON en- and decoding habits

After we don’t do something, a JSONDecoder (and JSONEncoder) will anticipate dates in a JSON file to be formatted as a double. This double ought to signify the variety of seconds which have handed since January 1st 2001 which is a reasonably non-standard technique to format a timestamp. The commonest technique to arrange a timestamp can be to make use of the variety of seconds handed since January 1st 1970.

Nonetheless, this methodology of speaking about dates isn’t very dependable while you take complexities like timezones under consideration.

Normally a system will use its personal timezone because the timezone to use the reference date to. So a given variety of seconds since January 1st 2001 could be fairly ambiguous as a result of the timestamp doesn’t say by which timezone we ought to be including the given timestamp to January 1st 2001. Totally different elements of the world have a special second the place January 1st 2001 begins so it’s not a steady date to check towards.

In fact, we have now some greatest practices round this like most servers will use UTC as their timezone which signifies that timestamps which can be returned by these servers ought to all the time be utilized utilizing the UTC timezone whatever the shopper’s timezone.

After we obtain a JSON file just like the one proven beneath, the default habits for our JSONDecoder might be to only decode the offered timestamps utilizing the system’s present timezone.

var jsonData = """
[
    {
        "title": "Grocery shopping",
        "date": 730976400.0
    },
    {
        "title": "Dentist appointment",
        "date": 731341800.0
    },
    {
        "title": "Finish project report",
        "date": 731721600.0
    },
    {
        "title": "Call plumber",
        "date": 732178800.0
    },
    {
        "title": "Book vacation",
        "date": 732412800.0
    }
]
""".information(utilizing: .utf8)!

struct ToDoItem: Codable {
  let title: String
  let date: Date
}

do {
  let decoder = JSONDecoder()
  let todos = attempt decoder.decode([ToDoItem].self, from: jsonData)
  print(todos)
} catch {
  print(error)
}

This is likely to be advantageous in some instances however as a rule you’ll need to use one thing that’s extra standardized, and extra specific about which timezone the date is in.

Earlier than we have a look at what I believe is probably the most wise resolution I need to present you how one can configure your JSON Decoder to make use of a extra normal timestamp reference date which is January 1st 1970.

Setting a date decoding technique

If you wish to change how a JSONEncoder or JSONDecoder offers along with your date, it is best to just be sure you set its date decoding technique. You are able to do this by assigning an acceptable technique to the thing’s dateDecodingStrategy property (or dateEncodingStrategy for JSONEncoder. The default technique is named deferredToDate and also you’ve simply seen the way it works.

If we need to change the date decoding technique so it decodes dates primarily based on timestamps in seconds since January 1st 1970, we will do this as follows:

do {
  let decoder = JSONDecoder()
  decoder.dateDecodingStrategy = .secondsSince1970
  let todos = attempt decoder.decode([ToDoItem].self, from: jsonData)
  print(todos)
} catch {
  print(error)
}

Some servers work with timestamps in milliseconds since 1970. You’ll be able to accommodate for that through the use of the .millisecondsSince1970 configuration as a substitute of .secondsSince1970 and the system will deal with the remainder.

Whereas this lets you use a standardized timestamp format, you’re nonetheless going to run into timezone associated points. To work round that, we want to check out dates that use the ISO-8601 normal.

Working with dates that conform to ISO-8601

As a result of there are numerous methods to signify dates so long as you could have some consistency amongst the techniques the place these dates are used, a normal was created to signify dates as strings. This normal is named ISO-8601 and it describes a number of conventions round how we will signify dates as strings.

We will signify something from only a yr or a full date to a date with a time that features details about which timezone that date exists in.

For instance, a date that represents 5pm on Feb fifteenth 2024 in The Netherlands (UTC+1 throughout February) would signify 9am on Feb fifteenth 2024 in New York (UTC-5 in February).

It may be vital for a system to signify a date in a person’s native timezone (for instance while you’re publishing a sports activities occasion schedule) in order that the person doesn’t should do the timezone math for themselves. For that motive, ISO-8601 tells us how we will signify Feb fifteenth 2024 at 5pm in a standardized means. For instance, we may use the next string:

2024-02-15T17:00:00+01:00

This technique incorporates details about the date, the time, and timezone. This enables a shopper in New York to translate the offered time to an area time which on this case signifies that the time can be proven to a person as 9am as a substitute of 5pm.

We will inform our JSONEncoder or JSONDecoder to find which one of many a number of totally different date codecs from ISO-8601 our JSON makes use of, after which decode our fashions utilizing that format.

Let’s have a look at an instance of how we will set this up:

var jsonData = """
[
    {
        "title": "Grocery shopping",
        "date": "2024-03-01T10:00:00+01:00"
    },
    {
        "title": "Dentist appointment",
        "date": "2024-03-05T14:30:00+01:00"
    },
    {
        "title": "Finish project report",
        "date": "2024-03-10T23:59:00+01:00"
    },
    {
        "title": "Call plumber",
        "date": "2024-03-15T08:00:00+01:00"
    },
    {
        "title": "Book vacation",
        "date": "2024-03-20T20:00:00+01:00"
    }
]
""".information(utilizing: .utf8)!

struct ToDoItem: Codable {
  let title: String
  let date: Date
}

do {
  let decoder = JSONDecoder()
  decoder.dateDecodingStrategy = .iso8601
  let todos = attempt decoder.decode([ToDoItem].self, from: jsonData)
  print(todos)
} catch {
  print(error)
}

The JSON within the snippet above is barely modified to make it use ISO-8601 date strings as a substitute of timestamps.

The ToDoItem mannequin is totally unchanged.

The decoder’s dateDecodingStrategy has been modified to .iso8601 which can permit us to not fear in regards to the precise date format that’s utilized in our JSON so long as it conforms to .iso8601.

In some instances, you might need to take some extra management over how your dates are decoded. You are able to do this by setting your dateDecodingStrategy to both .customized or .formatted.

Utilizing a customized encoding and decoding technique for dates

Generally, a server returns a date that technically conforms to the ISO-8601 normal but Swift doesn’t decode your dates accurately. On this case, it would make sense to offer a customized date format that your encoder / decoder can use.

You are able to do this as follows:

do {
  let decoder = JSONDecoder()

  let formatter = DateFormatter()
  formatter.dateFormat = "yyyy-MM-dd"
  formatter.locale = Locale(identifier: "en_US_POSIX")
  formatter.timeZone = TimeZone(secondsFromGMT: 0)

  decoder.dateDecodingStrategy = .formatted(formatter)

  let todos = attempt decoder.decode([ToDoItem].self, from: jsonData)
  print(todos)
} catch {
  print(error)
}

Alternatively, you may must have some extra complicated logic than you possibly can encapsulate in a date formatter. If that’s the case, you possibly can present a closure to the customized configuration on your date decoding technique as follows:

decoder.dateDecodingStrategy = .customized({ decoder in
  let container = attempt decoder.singleValueContainer()
  let dateString = attempt container.decode(String.self)

  if let date = ISO8601DateFormatter().date(from: dateString) {
    return date
  } else {
    throw DecodingError.dataCorruptedError(in: container, debugDescription: "Can not decode date string (dateString)")
  }
})

This instance creates its personal ISO-8601 date formatter so it’s not probably the most helpful instance (you possibly can simply use .iso8601 as a substitute) but it surely reveals how it is best to go about decoding and making a date utilizing customized logic.

In Abstract

On this publish, you noticed a number of methods to work with dates and JSON.

You realized in regards to the default method to decoding dates from a JSON file which requires your dates to be represented as seconds from January 1st 2001. After that, you noticed how one can configure your JSONEncoder or JSONDecoder to make use of the extra normal January 1st 1970 reference date.

Subsequent, we checked out how one can use ISO-8601 date strings as that optionally embody timezone data which tremendously improves our scenario.

Lastly, you be taught how one can take extra management over your JSON through the use of a customized date formatter and even having a closure that means that you can carry out rather more complicated decoding (or encoding) logic by taking full management over the method.

I hope you loved this publish!



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments