-1

I have a date format like this from the API result:

dd-MM-yyyy HH:mm:ss

What I want to do is to get the remaining days/hours/minutes from the date formatter. So my case are like this:

  1. If it's 7 days or less days remaining from the date, returns "x days remaining"
  2. If it's less than 24 hours remaining from the date, returns "x hours remaining"
  3. If it's less than an hour remaining from the date, returns "x minutes remaining"
  4. If else, returns "dd-MM-yyyy"

Here's my date formatter function:

private func convertDate(dateString: String) -> String {
        let dateFormatterGet = DateFormatter()
        dateFormatterGet.dateFormat = "dd-MM-yyyy HH:mm:ss"
        let dateFormatterPrint = DateFormatter()
        dateFormatterPrint.dateFormat = "dd MMM yyyy"
        
        if let date = dateFormatterGet.date(from: dateString) {
            return dateFormatterPrint.string(from: date)
        } else {
            return " - "
        }
}

I'm not sure how to achieve this because I'm still new to programming. Any help would be appreciated, thank you.

cleanrun
  • 549
  • 6
  • 20
  • It doesn't make sense. Remaining time until when? – El Tomato Jul 06 '20 at 03:03
  • @ElTomato for example, if today is 6 July 2020, and the date i got from the api is "2020-07-10 00:00:00" that means i have 4 days left until 10 July 2020, so the function returns "4 days remaining", another example is if today is 9 July 2020 at 6 am, the function returns "18 hours remaining" – cleanrun Jul 06 '20 at 03:09
  • There are many ways to do it. One way of doing it is to convert two dates into the numbers of seconds since Jan. 1, 1970. And you can compare those two numbers. – El Tomato Jul 06 '20 at 03:11

2 Answers2

2

DateComponentsFormatter builds “remaining” strings:

let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.maximumUnitCount = 1                  // or use 2 if you want
formatter.includesTimeRemainingPhrase = true
guard let string = formatter.string(from: date, to: now) else { return }

3 weeks remaining

Or, RelativeDateTimeFormatter

let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .full
let string = formatter.localizedString(for: now, relativeTo: date)

in 3 weeks

Rob
  • 415,655
  • 72
  • 787
  • 1,044
1

Your first steps are mostly correct. The next step is to check the difference between that time and now, which you can do with dateComponents(_:from:to:):

// you only need one date formatter!
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy HH:mm:ss"
guard let date = dateFormatter.date(from: "7-07-2020 06:00:00") else {
    // the date can't be parsed! Return something sensible...
}
let now = Date()
// There is a reason why I used all three of [.day, .hour, .minute] instead of just .day... 
let dateComponents = Calendar.current.dateComponents([.day, .hour, .minute], from: now, to: date)
let daysFromNow = dateComponents.day!

if daysFromNow < 7 && daysFromNow >= 0 {
    // format the "xxx remaining" phrase
} else {
    // reuse the same date formatter!
    dateFormatter.dateFormat = "dd-MM-yyyy"
    return dateFormatter.string(from: date)
}

To format the xxx remaining phrase, we can actually use DateComponentsFormatter! We can just give it a bunch of options, and the dateComponents, which already contains all three date components that we want to format! The key here is setting maximumUnitCount to 1, so that it only outputs the largest unit.

let componentFormatter = DateComponentsFormatter()
componentFormatter.allowedUnits = [.day, .hour, .minute]
componentFormatter.unitsStyle = .full
componentFormatter.maximumUnitCount = 1
componentFormatter.includesTimeRemainingPhrase = true
return componentFormatter.string(from: dateComponents)!
Sweeper
  • 213,210
  • 22
  • 193
  • 313