1

I have created the following, simple Swift function to convert a String into a Date object. However, the dateFormatter always returns nil, even on valid inputs like 2020-02-27

func date(fromString str: String?) -> Date? {
    if let dateStr = str {
        if dateStr.count == 0 {
            return nil
        }

        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: "en_US_POSIX")
        dateFormatter.dateFormat = "yyyy-MM-dd"

        let result = dateFormatter.date(from: dateStr)         // --> nil
        //let result = dateFormatter.date(from: "2020-02-27")  // --> nil as well

        return result
    }

This is (more or less) a ported version some Objectiv-C code where everything works fine.

How to fix this?

UPDATE:

As mentioned in the comments the problem does NOT show when I execute the code in Swift Playground. It seems that this is some wired problem with Xcode and the simulator. I will re-check this!

Andrei Herford
  • 17,570
  • 19
  • 91
  • 225
  • 2
    I cannot reproduce the issue: `print(date(fromString: "2020-02-27")) // Optional(2020-02-26 23:00:00 +0000)` – Martin R Feb 27 '20 at 14:11
  • 1
    Are you sure your input, `str`, isn't nil? Off-topic but I would recommend using `guard` at the beginning, `guard let dateStr = str, !str.isEmpty else {return nil}` to increase readability – Joakim Danielson Feb 27 '20 at 14:12
  • 1
    Not related, but `guard let dateStr = str, dateStr.isEmpty == false else { return nil }` might be clearer. – Larme Feb 27 '20 at 14:15
  • First check your input, is it the correct string or not?. after that check your input, is it actually "yyyy-MM-dd" format or not? – AMIT Feb 27 '20 at 14:18
  • I cannot reproduce this as well. Putting this code into a Swift Playground successfully returns `Optional(2020-02-27 05:00:00 +0000)`. – Ben Myers Feb 27 '20 at 14:19
  • Also unrelated to your question, but creating a `DateFormatter` is quite expensive, so you shouldn't do that inside a function. Store it as a property of your class instead. – Dávid Pásztor Feb 27 '20 at 14:24
  • Note that you should always set timezone as well to solve problems with DST changes, e.g. `TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT()`. – Sulthan Feb 27 '20 at 14:33
  • If the question was correctly answered, why do you not accept that answer? – matt Feb 27 '20 at 16:39
  • @Sulthan DateFormatter's default timezone it is already the current one. `TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT)` is pointless. What you need is to set its calendar. – Leo Dabus Feb 27 '20 at 23:42
  • @LeoDabus Not at all. The thing is that you want to avoid a time zone with DST changes. If you don't do that then your parsing starts falling on specific days. Setting the time zone is also mentioned in the famous Technical Note about parsing internet dates. When you are parsing a date without actual time information, the problem gets even more interesting. – Sulthan Feb 28 '20 at 08:43
  • Check the duplicate question – Leo Dabus Feb 28 '20 at 12:26

1 Answers1

0

Set the calendar too:

dateFormatter.calendar = Calendar(identifier: .iso8601)
DungeonDev
  • 1,176
  • 1
  • 12
  • 16
  • Thank! I do not understand why, but this solved the problem... – Andrei Herford Feb 27 '20 at 14:17
  • @AndreiHerford that's because you haven't provided the time components on your string. Not every day starts at 12am. Depending on your location and day it might be the start of daylight savings time https://stackoverflow.com/questions/32408898/dateformatters-method-datefrom-string-returns-nil-for-specific-dates-in-spec – Leo Dabus Feb 27 '20 at 23:36