1

I'm currently trying to call an Api which then returns me some information along with a change date. Afterwards I want to display the Date in the format "dd.MM.yyyy". The Date I get from the Api looks like this: "2020-03-20T19:30:00". Therefore, I used the solution in this question: How to get time from YYYY-MM-dd'T'HH:mm:ss.sssZ to make it look like the format I want.

Unfortunally when I try to parse the date which I get from the Api I always get a nil value.

The code I wrote looks as follows:

let inputFormatter : DateFormatter = DateFormatter()
inputFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let dateFormatter : DateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd.MM.yyyy"

//date is always nil 
let date = inputFormatter.date(from: content?.DateTime ?? "2020-03-20T19:30:00")

dateLabel.text = dateFormatter.string(from: date ?? Date())

Does somebody know why I always get a nil value and if the way I'm converting the dates is a good/bad practice?

Benipro98
  • 183
  • 2
  • 14
  • Make sure to set your DateFormatter locale to `"en_US_POSIX"` before setting the dateFormat. If you don't do that your DateFormatter will reflect the user locale and settings and will fail is you set your device time settings to 12h – Leo Dabus Mar 29 '20 at 18:06
  • Btw using the nil coalescing operator to set the date to now when failing it is definitely bad practice – Leo Dabus Mar 29 '20 at 18:09
  • @LeoDabus thanks for your advice. I have added locale to the DateFormatter and will change the operator. Do you also know why my date variable is still nil when I try to parse the date? – Benipro98 Mar 29 '20 at 18:18
  • You are getting `date` being `nil` not because of issues with the date formatter, but due to problems with the content you are providing. If the `content.DateTime()` doesn't match the formatting string the `date(from:)` will return nil. You sure there isn't a `Z` on the end of the date string? (and if there is you'd be better with the ISO8601DateFormatter) – flanker Mar 29 '20 at 18:18
  • 1
    Yep, set the `locale` of the `inputFormatter` to `en_US_POSIX` is good idea. Or, better, use [`ISO8601DateFormatter`](https://developer.apple.com/documentation/foundation/iso8601dateformatter), which takes care of all of this, instead of `DateFormatter`, and then you don’t have to set the `locale` or the `dateFormat`. – Rob Mar 29 '20 at 18:18
  • First unwrap your content date, and add its value to your post. Without knowing what is your date string we will be guessing. – Leo Dabus Mar 29 '20 at 18:22
  • 1
    @Rob ISO8601DateFormatter won't work without the timezone `Z` at the end – Leo Dabus Mar 29 '20 at 18:24
  • On your `dd.MM.yyyy` output format, I might suggest not setting `dateFormat` at all, and instead using, for example, `dateStyle` of `.short` or `.medium`, so you get localized output formatted in accordance with the user’s device’s preferences (e.g., where US users will see the day after the month, and most other locales will see the day before the the month). – Rob Mar 29 '20 at 18:24
  • 1
    As Rob just mentioned to display your date respecting the user's device locale and settings https://stackoverflow.com/questions/28332946/how-do-i-get-the-current-date-in-short-format-in-swift/28347285 – Leo Dabus Mar 29 '20 at 18:26
  • @LeoDabus - Good catch. I didn’t see that. Personally, I’d still use `ISO8601DateFormatter`, but with `formatter.formatOptions.remove(.withTimeZone)` – Rob Mar 29 '20 at 18:27
  • @Rob Yes but the Target need to be restricted to iOS11 or above. And if fractional seconds is added iOS11.2.1 or above – Leo Dabus Mar 29 '20 at 18:28
  • 1
    @LeoDabus Of course. But it’s the right tool for the job for iOS 11 and later. – Rob Mar 29 '20 at 18:29
  • 1
    BTW, in the absence of the timezone qualifier, it’s a bit unclear what timezone this represents (e.g. is that 7:30pm GMT, 7:30pm local, 7:30pm in server’s time zone?). By definition, ISO8601 strings assume that in the absence of a timezone qualifier (e.g., a `Z` for example) that it’s in your local timezone. But most web services generally report date strings in GMT/UTC/Zulu. You might want to confirm precisely what your web service is doing. And if this is your own web service, you might consider shifting to using fully qualified ISO 8601/RFC 3339 date strings with timezone information. – Rob Mar 29 '20 at 20:09

1 Answers1

1

@Leo Dabus gave very good points. Interestingly, I have tested your code in playground using the string "2020-03-20T19:30:00" and it works perfectly even without setting locale. I think something is wrong with content?.DateTime. The sample code you should probably use:

`

let dateFormatter : DateFormatter = DateFormatter()
let locale = Locale(identifier: "en_US_POSIX")

dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
dateFormatter.locale = locale

guard let date = dateFormatter.date(from: "2020-03-20T19:30:00") else {
  fatalError("Could not create date")
}
print(date)

`

kerim.ba
  • 276
  • 1
  • 8
  • Thank to all of you guys to point out the problem. What causes this problem was the content.DateTime. In my code this variable was an optional value. After I unwrapped this value the date was read correctly. Maybe some of you have an explanation why the optional value causes the nil value. But as @Rob states I'm trying to use the ISO8601DateFormatter in the future. – Benipro98 Mar 29 '20 at 18:37
  • ModernMantra - “tested your code in playground ... and it works perfectly even without setting locale” ... Sure, it may have worked fine on your particular device, but on a different device with a different locale, it can still fail if you don’t manually set the formatter’s `locale` to `en_US_POSIX`. If you use `DateFormatter` to parse ISO 8601 or RFC 3339 date strings, you really must set `locale` to ensure it works correctly regardless of device settings. – Rob Mar 29 '20 at 19:54