1

I'm receiving a String from my API which is the object creation time. The format is specific so I can't determine how it can be converted.

2021-07-07T15:03:21.409Z

I tried to convert it to a Date like this :

extension String {
 func toDate(withFormat format: String = "yyyy-MM-dd HH:mm:ss") -> 
 Date? {
        let dateFormatter = DateFormatter()
        dateFormatter.timeZone = TimeZone(identifier: "Europe/Paris")
        dateFormatter.locale = Locale(identifier: "fr-FR")
        dateFormatter.calendar = Calendar(identifier: .gregorian)
        dateFormatter.dateFormat = format
        let date = dateFormatter.date(from: self)

        return date
    }
}

But it's returning nil. I guess the withFormat part isn't good in my toDate() function but I'm unsure about it.

Then I would like to convert it again to a time ago String like this (found on SO):

extension Date {
 func timeAgoDisplay() -> String {

        let calendar = Calendar.current
        let minuteAgo = calendar.date(byAdding: .minute, value: -1, to: Date())!
        let hourAgo = calendar.date(byAdding: .hour, value: -1, to: Date())!
        let dayAgo = calendar.date(byAdding: .day, value: -1, to: Date())!
        let weekAgo = calendar.date(byAdding: .day, value: -7, to: Date())!

        if minuteAgo < self {
            let diff = Calendar.current.dateComponents([.second], from: self, to: Date()).second ?? 0
            return "\(diff) sec ago"
        } else if hourAgo < self {
            let diff = Calendar.current.dateComponents([.minute], from: self, to: Date()).minute ?? 0
            return "\(diff) min ago"
        } else if dayAgo < self {
            let diff = Calendar.current.dateComponents([.hour], from: self, to: Date()).hour ?? 0
            return "\(diff) hrs ago"
        } else if weekAgo < self {
            let diff = Calendar.current.dateComponents([.day], from: self, to: Date()).day ?? 0
            return "\(diff) days ago"
        }
        let diff = Calendar.current.dateComponents([.weekOfYear], from: self, to: Date()).weekOfYear ?? 0
        return "\(diff) weeks ago"
    }
}
Mathieu Rios
  • 350
  • 1
  • 17
  • 1
    Call your function like this `toDate(withFormat: "yyyy-MM-dd'T'HH:mm:ss.SSSZ")` and it will work. Also when posting extensions to types then I think you should include what it is an extension to for clarity even if it is easy to guess. – Joakim Danielson Jul 12 '21 at 15:03
  • 1
    Look at your format string. Where is the `T`, the fractional seconds and the trailing `Z`? A more convenient formatter is [ISO8601DateFormatter](https://developer.apple.com/documentation/foundation/iso8601dateformatter). And for the *ago* stuff there is [RelativeDateTimeFormatter](https://developer.apple.com/documentation/foundation/relativedatetimeformatter) – vadian Jul 12 '21 at 15:05
  • 1
    In a text editor, put your format `"yyyy-MM-dd HH:mm:ss"` ABOVE `2021-07-07T15:03:21.409Z`, see what's supposed to match which letter with which part: `"yyyy"` with `"2021"`, "MM" with `"07"`, do no forget also the `"-"` etc. You'll see what's wrong, like what about the `T`? The `Z`? – Larme Jul 12 '21 at 15:08
  • The format wasn't good, thanks. I'll check on RelativeDateTimeFormatter @vadian – Mathieu Rios Jul 12 '21 at 15:10

1 Answers1

-2

This is actually quite simple... The answer is simply using a formatter like so:

let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd H:mm:ss.SSSS"
let currentTime = df.string(from: Date())
//currentTime is your string. You can change date formatter as you wish!

In this example DateFormatter() formats dates into a certain format and then converts it!

The different parts mean: yyyy is a four digit year, MM is the month like 08 or 12 or something, dd is a two-digit date, H is the military time hours 0-24 and hh is the hours from 0-12 and again, mm are the minutes, ss.SSSS are the seconds and the fraction seconds up to four decimal places.

If you want the letters you can do something like this instead:

let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd'T'H:mm:ss.SSSS'Z'"
let currentTime = df.string(from: Date())
  • 2
    *quite simple* but quite wrong. It doesn't match the ISO date in the question. – vadian Jul 12 '21 at 16:37
  • hey @vadian just because the question has an extra 'T' and 'Z' that doesnt make it wrong... I have it in the EXACT SAME format without the letters... its called reformatting :) – App Developer Jul 12 '21 at 16:42
  • @AppDeveloper your post still wrong after your edit. Do you know what Z in a date string means? It means UTC time. If you escape the Z the date formatter will ignore it and parse the date string using the current timezone. – Leo Dabus Jul 12 '21 at 17:14
  • Second issue you are not setting the locale while parsinfg a fixed date format. You should always set its locale to "en_US_POSIX". This would prevent your dateFormat reflecting the device's locale and settings. Your parsing might fail depending on the device's 12-24h setting. – Leo Dabus Jul 12 '21 at 17:14
  • Third issue `H` is not military time. `H` means 0-23. You should use `HH` 00-23. – Leo Dabus Jul 12 '21 at 17:15
  • Fourth DateFormatter will ignore the fourth fraction digit. You can have up to 3 fraction digits when converting the date to a string. When parsing it you just need a single S to parse from 1 to 3 fraction digits. In other words `S`, `SS` or `SSS` will achieve the same results when parsing a date string with any number of fraction digits. – Leo Dabus Jul 12 '21 at 17:18
  • Fifth when converting a Date to String using your dateFormat it will result in a date string with the current timezone and it will add a Z to the resulting string which doesn't make any sense. – Leo Dabus Jul 12 '21 at 17:20
  • 2
    _"try to be a little kinder"_ note that it's the answer that got downvoted and not you personally. – Joakim Danielson Jul 12 '21 at 20:07