2

I am trying to get the hour and minute values from a UIDatePicker for use in my server, but the value from the UIDatePicker is an hour off. My local timezone currently uses daylight savings time, so I'm assuming that the UIDatePicker is not respecting that.

Here is the code I'm using to convert the date provided by the UIDatePicker to its hour and minute values:

struct MyTimeSettings {

    var time: Date!

    init(from json: [String : Any]) {
        var calendar = Calendar.current
        calendar.timeZone = TimeZone(abbreviation: "UTC")!

        self.time = calendar.date(from: DateComponents(timeZone: TimeZone(abbreviation: "UTC")!, year: 0, month: 0, day: 0, hour: (json["Hour"] as! Int), minute: (json["Minute"] as! Int)))
    }

    init() {}

    func getJSON() -> [String : Any] {
        var calendar = Calendar.current
        calendar.timeZone = TimeZone(abbreviation: "UTC")!
        let components = calendar.dateComponents(in: TimeZone(abbreviation: "UTC")!, from: self.time)

        return [
            "Hour" : components.hour!,
            "Minute" : components.minute!
        ]
    }

    static func ==(lhs: MyTimeSettings, rhs: MyTimeSettings) -> Bool {
        return (lhs.time == rhs.time)
    }
}

To test it, I gave it a Date which evaluates to 10:15 PM EDT:

var settings = MyTimeSettings()
let date = Date(timeIntervalSince1970: 1522894500)
settings.time = date

print(settings.getJSON()) // ["Hour": 2, "Minute": 15]

It also works properly with input JSON:

let json = ["Hour": 2, "Minute": 15]
print(MyTimeSettings(from: json).getJSON()) // ["Hour": 2, "Minute": 15]

My problem is that the same code does not work properly whilst getting the date from the UIDatePicker. I am using the Eureka library for displaying the UIDatePicker in a table view cell:

<<< TimePickerRow() { row in
    row.cell.datePicker.timeZone = TimeZone.current
    row.cell.datePicker.locale = Locale.current
    row.value = self.myTimeSettings.time
}.onChange({ (row) in
    self.myTimeSettings.time = row.value
})

I then set the time on the date picker to 10:15 PM (EDT), but I do not get 2:15 AM UTC:

print(myTimeSettings.getJSON()) // ["Hour": 3, "Minute": 12]

Why is the date picker returning the wrong time?

Wilson Gramer
  • 702
  • 8
  • 23
  • 1
    Before diving deeper into what might be wrong, does [this](https://stackoverflow.com/questions/2532729/daylight-saving-time-and-time-zone-best-practices) help with any clarifications or advice? – Aaron Apr 04 '18 at 12:29
  • @Aaron I'm not having trouble with time zones or date objects, I am trying to understand why the `UIDatePicker` is returning the wrong time when I have set the correct time zone. – Wilson Gramer Apr 04 '18 at 13:34
  • What do you get if you simply `print(datePicker.date)`? – DonMag Apr 04 '18 at 14:13
  • @DonMag I still get 3:12 AM: `-0001-11-30 03:12:00 +0000` – Wilson Gramer Apr 04 '18 at 15:13
  • You are getting the correct date/time. UTC does not have "daylight saving time", so (for example) in U.S. Eastern time zone, `10:45 PM on March 10, 2018` is `3:45 AM on March 11 UTC`, and `10:45 PM on March 11, 2018` is `2:45 AM on March 12 UTC` – DonMag Apr 04 '18 at 15:44

2 Answers2

2

According to Apple's Documentation you'll want to call this method:

Declaration

func daylightSavingTimeOffset(for date: Date = default) -> TimeInterval

Parameters

date

The date to use for the calculation. The default value is the current date.

Jake
  • 2,126
  • 1
  • 10
  • 23
0

Thanks to Jake's answer, I was able to get the correct UTC time by adding the daylightSavingTimeOffset function to MyTimeSettings:

init(from json: [String : Any]) {
    var calendar = Calendar.current
    calendar.timeZone = TimeZone(abbreviation: "UTC")!

    self.enabled = json["Enabled"] as! Bool
    self.daysToNotify = (json["Interval"] as! [String]).map { SHNotificationIntervalType(rawValue: $0)! }
    self.time = calendar.date(from: DateComponents(timeZone: TimeZone(abbreviation: "UTC")!, year: 0, month: 0, day: 0, hour: (json["Hour"] as! Int), minute: (json["Minute"] as! Int)))
    if TimeZone.current.isDaylightSavingTime() {
        let offset = TimeZone.current.daylightSavingTimeOffset()
        self.time = self.time + offset
    }
}

init() {}

func getJSON() -> [String : Any] {
    var calendar = Calendar.current
    calendar.timeZone = TimeZone(abbreviation: "UTC")!

    var components: DateComponents
    if TimeZone.current.isDaylightSavingTime() {
        let offset = TimeZone.current.daylightSavingTimeOffset()
        components = calendar.dateComponents(in: TimeZone(abbreviation: "UTC")!, from: self.time - offset)
    } else {
        components = calendar.dateComponents(in: TimeZone(abbreviation: "UTC")!, from: self.time)
    }

    return [
        "Enabled" : self.enabled!,
        "Interval" : (self.daysToNotify.map { $0.rawValue }),
        "Hour" : components.hour!,
        "Minute" : components.minute!
    ]
}
Wilson Gramer
  • 702
  • 8
  • 23