7

What do we got: Date+time (format yyyy-mm-dd hh:mm a)

What are we looking for: Time difference in minutes

What operation: NewDate - OldDate

So, I wonder how I could accomplish above goal? I would like to format the date and time to US, regardless from which locale the user has. How can I do that?

Then I will save the 'oldTime' into UserDefaults, and use it for later calculation. The goal is to put the user on delay for 5 minutes and the calculations will be performed to determine if user should be on delay or not.

  • possible duplicate of https://stackoverflow.com/a/27184261/2303865 – Leo Dabus Jun 23 '19 at 00:52
  • Thanks, I wonder how I could format the date to be the same format regardless the users locale language? – iOS_Android_Flutter_PRO Jun 23 '19 at 00:54
  • 2
    for fixed locale you can use `Locale(identifier: "en_US_POSIX")`. If you can change your date format you should use ISO8601 https://stackoverflow.com/questions/28016578/how-to-create-a-date-time-stamp-and-format-as-iso-8601-rfc-3339-utc-time-zone/28016692?r=SearchResults&s=1|69.4335#28016692 – Leo Dabus Jun 23 '19 at 01:15

3 Answers3

11

Just make a function that takes two dates and compares them like this.

import UIKit


func minutesBetweenDates(_ oldDate: Date, _ newDate: Date) -> CGFloat {

    //get both times sinces refrenced date and divide by 60 to get minutes
    let newDateMinutes = newDate.timeIntervalSinceReferenceDate/60
    let oldDateMinutes = oldDate.timeIntervalSinceReferenceDate/60

    //then return the difference
    return CGFloat(newDateMinutes - oldDateMinutes)
}


//Usage:

let myDateFormatter = DateFormatter()
myDateFormatter.dateFormat = "yyyy-MM-dd HH:mm"

//You'll need both dates to compare, you can get them by just storing a Date object when you first start the timer.
//Then when you need to check it, compare it to Date()
let oldDate: Date = myDateFormatter.date(from: String("2019-06-22 11:25"))

func validateRefresh() {

    //do the comparison between the old date and the now date like this.
    if minutesBetweenDates(oldDate, Date()) > 5 {
        //Do whatever
    }
}

You can, of course, change the .dateFormat value on the date formatter to be whatever format you'd like. A great website for finding the right format is: https://nsdateformatter.com/.

thecoolwinter
  • 861
  • 7
  • 22
  • You probably don't want `HH` and `a`. That mixes 24-hour format and am/pm. Either use `a` with `h` or use just `HH` without `a`. – rmaddy Jun 23 '19 at 03:19
  • totally! you can just change the string given for the dateFormat property on the date formatter. Here's a good cheatsheet for date formats http://nsdateformatter.com/ – thecoolwinter Mar 04 '20 at 02:42
5

You say:

I would like to format the date and time to US, regardless from which locale the user has. How can I do that?

Specify a Locale of en_US_POSIX:

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd hh:mm a"
formatter.locale = Locale(identifier: "en_US_POSIX")

The locale is not the only question.

  • There’s also a timezone question. For example, you're driving out of Chicago and go from Central to Eastern timezones; do you really want to consider that one hour has passed?

  • Do you really want to discard seconds? If you do that, the 59 seconds between going from 8:00:00pm to 8:00:59pm will be considered “zero minutes” but the one second between 8:00:59pm and 8:01:00pm will be considered “one minute”.

Frankly, if I wanted to save a locale and timezone invariant date string, I’d suggest using ISO8601DateFormatter.

Then I will save the 'oldTime' into UserDefaults, and use it for later calculation.

If that’s why you’re using this DateFormatter, I’d suggest saving the Date object directly.

UserDefaults.standard.set(oldTime, forKey: "oldTime")

And to retrieve it:

if let oldTime = UserDefaults.standard.object(forKey: "oldTime") as? Date {
    ...
}

In terms of calculating the number of minutes between two Date objects

let minutes = Calendar.current
    .dateComponents([.minute], from: date1, to: date2)
    .minute

If you want the number of seconds, you can also use timeIntervalSince:

let seconds = date2.timeIntervalSince(date1)

And if you wanted to show the amount of elapsed time as a nice localized string:

let intervalFormatter = DateComponentsFormatter()
intervalFormatter.allowedUnits = [.minute, .second]
intervalFormatter.unitsStyle = .full
let string = intervalFormatter.string(from: date1, to: date2)
Rob
  • 415,655
  • 72
  • 787
  • 1,044
0

I'm not convinced that your question is the best way to go about accomplishing your aim, but the code below will work.

let dateFormatterNow = DateFormatter()
dateFormatterNow.dateFormat = "yyyy-MM-dd hh:mm a"
dateFormatterNow.timeZone = TimeZone(abbreviation: "EST")

let oldDateString = "2019-06-23 12:44 p"
let oldDate = dateFormatterNow.date(from: oldDateString)

let newDateString = "2019-06-23 12:54 p"
let newDate = dateFormatterNow.date(from: newDateString)

if let oldDate = oldDate, let newDate = newDate {
    let diffInMins = Calendar.current.dateComponents([.minute], from: oldDate, to: newDate).minute
    print(diffInMins)
}
Daniel
  • 129
  • 9
  • Thanks! Could you explain why that would be a bad way of accomplishing the aim? I would like to save the dateTime when user performs an action, and then use that dateTime to calculate difference with newTime when use tries to perform same action again. What is a better way? – iOS_Android_Flutter_PRO Jun 23 '19 at 01:40
  • You probably don't want `HH` and `a`. That mixes 24-hour format and am/pm. Either use `a` with `h` or use just `HH` without `a`. – rmaddy Jun 23 '19 at 03:19
  • Sorry I misunderstood your use case. The above will work for what you describe. I've changed to hh from HH as suggested by rmaddy; (you could also go the other way and use HH without a). – Daniel Jun 23 '19 at 03:41