Search code examples
iosswift4dateformatterjsondecoder

change date format iso-8601 to custom format


I have a json file being parsed using JSONDecoder(). However, I receive the variable timestamp of type Date in iso-8601-format ("yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX") but on my view, I want to display it in a custom format: "dd/mm/yy HH:mm:ss".

I have written the following code, but I get nil for timestamp and furthermore I assume "date" is not the correct type to use when timestamp comes in iso-8601 format:

Error json: typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "timestamp", intValue: nil)], debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil))

swift4

import UIKit

enum Type : String, Codable {
    case organizational, planning
}

// structure from json file
struct News: Codable{
    let type: Type
    let timestamp: Date //comes in json with ISO-8601-format
    let title: String
    let message: String

    enum  CodingKeys: String, CodingKey { case type, timestamp, title, message}

    let dateFormatter : DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "dd/MM/yy HH:mm:ss"  // change format ISO-8601 to dd/MM/yy HH:mm:ss
        return formatter
    }()

    var dateString : String {
        return dateFormatter.string(from:timestamp) // take timestamp variable of type date and make it a string -> lable.text
    }
}

Solution

  • When you are decoding a Date the decoder expects an UNIX timestamp (a Double) by default, this is what the error message tells you.

    However you can indeed decode an ISO8601 string as Date if you add the decoder.dateDecodingStrategy = .iso8601 but this decodes only standard ISO8601 strings without milliseconds.

    There are two options:

    1. Add a formatted dateDecodingStrategy with a DateFormatter.

      let dateFormatter = DateFormatter()
      dateFormatter.locale = Locale(identifier: "en_US_POSIX")
      dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
      let decoder = JSONDecoder() 
      decoder.dateDecodingStrategy = .formatted(dateFormatter)
      try decoder.decode(...
      
    2. Declare timestamp as

      let timestamp: String
      

      and convert the string back and forth with two formatters or two date formats in dateString.