3

I'm trying to convert a string:

2018-01-18 13:04:42 +0000

to something like

January, 18, 2018

using DateFormatter but it fails. I have tried other questions (this, this and this).

This is my simple code which prints nil:

let str = "2018-01-18 13:04:42 +0000" 
let dateFormatter = DateFormatter() 
dateFormatter.dateFormat = "MMMM, dd, YYYY" 
dateFormatter.locale = Locale.current 
let mydate = dateFormatter.date(from: str) 
print(mydate)
Tamás Sengel
  • 55,884
  • 29
  • 169
  • 223
Maysam
  • 7,246
  • 13
  • 68
  • 106
  • The provided string does not contain a *single* comma. This is a pretty clear reason for failure in its own. – Tamás Sengel Jan 18 '18 at 13:18
  • 1
    @the4kman What does it have to with a comma? would you please tell me why you thumb it down?! – Maysam Jan 18 '18 at 13:20
  • `2018-01-18 13:04:42 +0000" ` vs `"MM, dd, YYYY" `. In which word the format look like the string? None. You need to use the format used by the string, then convert it to date, then use your target format `"MM, dd, YYYY"` and transform that date into the target string. – Larme Jan 18 '18 at 13:23
  • `dateFormatter.dateFormat = "MM, dd, YYYY" ` this line tells the dateFormatter what format the string is in that you are *reading*, not what output you want. you first need to convert the string date into a Date object. – Scriptable Jan 18 '18 at 13:24
  • @Maysam You have to use the format as used in the string. – Akbar Khan Sep 25 '19 at 13:01

2 Answers2

5

Your DateFormatter expects the original string to be in the January, 18, 2018 format. You should convert it to a Date first and only convert it to another format after that.

Also, you should not use YYYY when referring to an ordinary calendar year. See this question for details.

let str = "2018-01-18 13:04:42 +0000" 
let dateFormatter = DateFormatter() 
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z" 
dateFormatter.locale = Locale(identifier: "en_US_POSIX") 

guard let date = dateFormatter.date(from: str) else {
    return
}

let newDateFormatter = DateFormatter() 
newDateFormatter.dateFormat = "MMMM, dd, yyyy" 
let newStr = newDateFormatter.string(from: date)
print(newStr) /*January, 18, 2018*/
Tamás Sengel
  • 55,884
  • 29
  • 169
  • 223
  • 1
    The locale is `en_US_POSIX`, not `EN_US_POSIX`. – rmaddy Jan 18 '18 at 15:01
  • @the4kman You shouldn't use a fixed date format when displaying a date to the user. The date should be displayed using date formatter dateStyle property (`.long`). – Leo Dabus Jan 18 '18 at 15:26
  • @LeoDabus I agree with this in most cases, however, the intent of the OP in this scenario is using a specific date formatting, regardless of the locale of the user. – Tamás Sengel Jan 18 '18 at 15:31
  • I still disagree. Note that you have to set the locale to en_US_POSIX when using a fixed date format – Leo Dabus Jan 18 '18 at 15:39
  • @LeoDabus If the OP wants to display a localized month name but decides to keep this proprietary format, `en_US_POSIX` is not the option to choose. – Tamás Sengel Jan 18 '18 at 15:49
  • Again I don't care what OP wants. He shouldn't force a certain date format to be displayed to the user. If the date will be localized to a different language it should be done correctly using dateStyle property. – Leo Dabus Jan 18 '18 at 15:53
  • https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/DataFormatting/Articles/dfDateFormatting10_4.html – Leo Dabus Jan 18 '18 at 15:54
2

A DateFormatter can convert a string into a date only if the format of the date string matches the dateFormat—which isn’t the case in your example. For this reason it correctly responds with a nil reply.

Tom E
  • 1,530
  • 9
  • 17
  • Thanks @Tom E. For me "2021-10-14T11:40:26.000Z" this type of date need to use "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" this Date format. Then converted to "dd-MM-yyyy" this format to get String Date – KrishnDip Nov 10 '22 at 18:33