1

I'm converting date strings from a JSON file to Date format and most the time it works, but this example fails and I can't figure out why. Any ideas appreciated! Thank you.

    let input = "2015-06-20T00:47:00.484Z"
    
    let dateFormatter = DateFormatter()
    dateFormatter.calendar = Calendar(identifier: .iso8601)
    dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.sssZ"
    dateFormatter.locale = Locale(identifier: "en_US_POSIX")
    
    print("ConvertedOutput: \(dateFormatter.date(from: input))")
FlatDog
  • 2,685
  • 2
  • 16
  • 19
  • 2
    It's not `sss`, it's `SSS`, it's fractional seconds, not second. Because `484` translated into seconds, that fail. – Larme Jun 23 '21 at 21:06
  • If `s` is seconds, how could `s` also be fractional seconds? – vadian Jun 23 '21 at 21:07
  • 1
    Does this answer your question? [I get nil when using NSDateFormatter in swift](https://stackoverflow.com/questions/28750048/i-get-nil-when-using-nsdateformatter-in-swift) It's not the only "sss" vs "SSS" on that quesiton, but that issue is also present... – Larme Jun 23 '21 at 21:08
  • Whoops! Thank you! dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" – FlatDog Jun 23 '21 at 21:08

2 Answers2

1

Your input is a date string which corresponds to ISO8601 standard. For such date strings, the Foundation has a ISO8601DateFormatter class which helps you avoid many edge cases which can lead to wrong date parsing and that's why it's suggested by Apple to use for such date strings this dedicated class than using DateFormatter.

Code with ISO8601DateFormatter

let dateFormatterIso = ISO8601DateFormatter()
dateFormatterIso.formatOptions = [.withFullDate, .withFullTime, .withFractionalSeconds]
let inputDate = dateFormatterIso.date(from: input)

Code with DateFormatter

If you can't use ISO8601DateFormatter then you have to correct the date format which has wrong mask for fractional seconds: .SSS instead .sss

let dateFormatter = DateFormatter()
dateFormatter.calendar = Calendar(identifier: .iso8601)
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")

Both formatters returns:

▿ Optional<Date>
  ▿ some : 2015-06-20 00:47:00 +0000
    - timeIntervalSinceReferenceDate : 456454020.48399997
Blazej SLEBODA
  • 8,936
  • 7
  • 53
  • 93
0

For milliseconds, you should use SSS instead of sss like this -

dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
Tarun Tyagi
  • 9,364
  • 2
  • 17
  • 30
  • I'll leave this downvoted to show what kind of stupidity you have to expect - but the answer is exactly the correct one. See https://unicode-org.github.io/icu/userguide/format_parse/datetime/ – gnasher729 Jun 23 '21 at 21:17
  • FlatDog, I strongly recommend you accept this answer because it is the correct one. Lowercase s for seconds, uppercase S for fractional seconds. – gnasher729 Jun 23 '21 at 21:18