0

I need to return date string is same format I retrieve it, but after converting to Date and back it lose few characters

var dateStr = "2019-08-02T11:46:46.5117312Z"

let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"

let date = formatter.date(from: dateStr)

 var str = formatter.string(from: date!) // ===>>> "2019-08-02T11:46:46.511Z"
  • 2
    `Date` is just not accurate enough. – Sweeper Aug 02 '19 at 13:30
  • 2
    Compare https://stackoverflow.com/q/23684727/1187415: (NS)DateFormatter works only with millisecond resolution – Martin R Aug 02 '19 at 13:32
  • See also [How to configure DateFormatter to capture microseconds](https://stackoverflow.com/q/43123944/1187415). – Martin R Aug 02 '19 at 13:34
  • @JoakimDanielson: You are right that SSSSSS would be the correct format for microseconds. However, the output would be 2019-08-02T11:46:46.511000Z, due to the above mentioned limited resolution of DateFormatter. – Martin R Aug 02 '19 at 13:36
  • @MartinR i've tried to use "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'". It worked but set nanoseconds to "0". so i got "2019-08-02T11:46:46.5110000Z" instead "2019-08-0211:46:46.5117312Z". so it not very good for me – Mykhailo Zabarin Aug 02 '19 at 17:07

1 Answers1

0

You can do it with custom formatter. But note that there not enough Double precision to store date. Result is 2019-08-02T11:46:46.5117311Z. Code:

class CustomDateFormatter {
    private let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
        return formatter
    }()

    func date(fromString str: String) -> Date? {
        let strs = str.components(separatedBy: CharacterSet(charactersIn: ".Z"))
        if strs.count != 3 {
            return nil
        }

        let dateStr = strs[0]
        let secondsStr = strs[1]
        guard let date = dateFormatter.date(from: dateStr),
            let seconds = Double("0."+secondsStr) else {
            return nil
        }

        let timeinteval = date.timeIntervalSince1970 + seconds
        return Date(timeIntervalSince1970: timeinteval)
    }

    func string(fromDate date: Date) -> String {
        let clippedDate = Date(timeIntervalSince1970: floor(date.timeIntervalSince1970))
        let seconds = date.timeIntervalSince1970.truncatingRemainder(dividingBy: 1)
        var lastPart = String(format: "%.7f", seconds)
        lastPart = (lastPart as NSString).substring(from: 1)
        return "\(dateFormatter.string(from: clippedDate))\(lastPart)Z"
    }
}

let dateStr = "2019-08-02T11:46:46.5117312Z"
let formatter = CustomDateFormatter()
let date = formatter.date(fromString: dateStr)!

print(formatter.string(fromDate: date)) // =====>> 2019-08-02T11:46:46.5117311Z
Gralex
  • 4,285
  • 7
  • 26
  • 47