-3

this is the code below. I appreciate any help . Thank you!

let dateFormatter = DateFormatter()

dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
               
let convertedDate = dateFormatter.date(from: "2021-05-23T12:09:18Z")
             
print("Converted Date -- \(convertedDate)")
Gereon
  • 17,258
  • 4
  • 42
  • 73
  • 2
    You have now a `Date`, so now use a new `DateFormatter` (or change previous one), and set its `dateFormat` to have something like `23rd June 12:09 pm`. What's in your opinion the `dateFormat` that would create that? The doc if you want http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns But the 'rd' might be tricky to get. – Larme Apr 02 '21 at 16:46
  • 1
    I hope it's a typo that you want 2021-05-23 to be formatted to 23rd June :) – Joakim Danielson Apr 02 '21 at 16:51
  • If the issue is with getting an ordinal number (23rd) then see [this answer](https://stackoverflow.com/a/64606168/9223839) – Joakim Danielson Apr 02 '21 at 17:00
  • Yes I need 23"rd" – sabaz shereef Apr 02 '21 at 17:34

2 Answers2

0

You already have the input formatter correctly defined but you will need two more, one date formatter for the output and one formatter to get the day of month correct

let outputFormatter = DateFormatter()
outputFormatter.locale = .current
outputFormatter.timeZone = TimeZone(secondsFromGMT: 0)
outputFormatter.dateFormat = "MMMM hh:mm a"

let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .ordinal
numberFormatter.locale = .current

Note that you need to set the time zone for the second date formatter and that it and the number formatter needs a Locale set, I am using the users current locale here since this should be respected.

With that set the whole conversion becomes

if let convertedDate = dateFormatter.date(from: "2021-05-23T12:09:18Z") {
    let day = Calendar.current.component(.day, from: convertedDate)

    if let dayString = numberFormatter.string(from: day as NSNumber) {
        let output = "\(dayString) \(outputFormatter.string(from: convertedDate))"
        print(output)
    }
}

The solution for formatting the day of month was taken from this answer

Output for this with an English locale is

23rd May 12:09 PM

and an example with a Swedish locale

23:e maj 12:09 em

Following a comment by @LeoDabus I decided to make a more localisable version that respects if day should be printed before or after the month. Assuming the formatters are the same as before and already declared this function can be used

func formatDate(_ date: String, locale: Locale = .current) -> String? {
    outputFormatter.locale = locale
    numberFormatter.locale = locale
    guard let inputDate = dateFormatter.date(from: date) else {
        return nil }
    let dayOfMonth = Calendar.current.component(.day, from: inputDate)
    
    guard let ordinalDay = numberFormatter.string(for: dayOfMonth),
          let output = outputFormatter.string(for: inputDate) else {
        return nil }
    
    return output.replacingOccurrences(of: "\\b\(dayOfMonth)\\b",
                                       with: ordinalDay,
                                       options: .regularExpression)
}

A simple test

for locale in [Locale(identifier: "en_US"), Locale(identifier: "sv_SE"),Locale(identifier: "pt_BR")] {
    if let date = formatDate("2021-05-23T12:09:18Z", locale: locale) {
        print("\(locale): \(date)")
    }
}

en_US (fixed): May 23rd, 2021
sv_SE (fixed): 23:e maj 2021
pt_BR (fixed): 23º de maio de 2021

And if we are going to respect what language/format etc the user has chosen completely then we ignore the ordinal number handling

func formatDate(_ date: String, locale: Locale = .current) -> String? {
    outputFormatter.locale = locale
    numberFormatter.locale = locale
    guard let inputDate = dateFormatter.date(from: date) else {
        return nil }

    return outputFormatter.string(for: inputDate)
}

and the same test would generate

en_US (fixed): May 23, 2021
sv_SE (fixed): 23 maj 2021
pt_BR (fixed): 23 de maio de 2021

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
  • 1
    Note that this will return UTC time. I know OP asked the same time as the original string but IMO you should warn him about it. The correct time should be displayed using the current timezone.Note also that in US the correct result should be `June 23rd`. Btw no need to cast your day to NSNumber. You can use `Formatter`'s `string(for: Any)` method `numberFormatter.string(for: day)` – Leo Dabus Apr 03 '21 at 08:44
  • I deliberately used UTC time here but maybe a comment about that is needed. The second part is interesting to look into, I would need to use a predefined format and then identify the day and replace it with a ordinal value. – Joakim Danielson Apr 03 '21 at 09:45
  • I don’t think OP should use ordinal. The correct is to respect the localized format based on a template where you only define the components – Leo Dabus Apr 03 '21 at 09:53
  • in Brazil the only day that you can use ordinal is the 1st – Leo Dabus Apr 03 '21 at 09:55
  • Fair point about using ordinal but that is what the question is about. I get "23º" when using Brazil locale for the number formatter, is this only for standalone numbers then and not for dates? – Joakim Danielson Apr 03 '21 at 09:59
  • We have ordinal as everybody else but it is not used when displaying dates other than the 1st day of the month. You can say `1º de Abril de 2021` but not `2º de Abril de 2021` – Leo Dabus Apr 03 '21 at 14:47
-2

It's very simple, you need second formatter, which format you Date to string. Example code

extension Date {
        func dateFormatWithSuffix() -> String {
            return "'\(self.daySuffix())' MMMM, h:mm a"
        }
    
        func daySuffix() -> String {
            let calendar = Calendar.current
            let components = (calendar as NSCalendar).components(.day, from: self)
            let dayOfMonth = components.day
            let numberFormatter = NumberFormatter()
            numberFormatter.numberStyle = .ordinal
            return numberFormatter.string(from: dayOfMonth as! NSNumber)!
        }
    }
    
    let dateFormatter = DateFormatter()
    
    dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
    dateFormatter.locale = Locale(identifier: "en_US_POSIX")
                   
    let convertedDate = dateFormatter.date(from: "2021-05-23T12:09:18Z")
    
    let dateFormatterNormal = DateFormatter()
    dateFormatterNormal.dateFormat = convertedDate?.dateFormatWithSuffix()
    dateFormatterNormal.locale = Locale(identifier: "en_US_POSIX")
    dateFormatterNormal.timeZone = TimeZone.current
    let endDate = dateFormatterNormal.string(from: convertedDate ?? Date())
    
    print("Converted Date -- \(endDate)")

Result
For detail about dateFormat visit this site and go to Reference
For adding rd, you need to add rd in quotes in dateFormat

Higherous
  • 92
  • 1
  • 6