Search code examples
swiftdatensdate

How to find midnight for a given Date in Swift


I creating an itinerary generation app where the user is required to enter the dates of his/her trip. The only problem is, using UIDatePicker the dates are always given as the current time for a given day/month/year.

In a separate file I've extended Date class to try and write a simple method that will return midnight for a given date.

First I tried

    var midnight:Date{
    let cal = Calendar(identifier: .gregorian)
    return cal.startOfDay(for: self)
}

However this always gave me either 04:00 or 05:00 depending on daylights savings, which gave me the idea that I should simply remove 4 or 5 hours depending on daylight savings, and so I created the following methods:

    var timezone:TimeZone{
    return TimeZone.current
}
///Returns the first instance of the date, e.g. 2018-02-26 00:00:00
var trueMidnight:Date{
    let cal = Calendar(identifier: .gregorian)
    let midnight = cal.startOfDay(for: self)
    let secondsFromGMT = TimeZone.current.secondsFromGMT()
    print("Daylight savings? \(daylightSavings)")
    return midnight.addingTimeInterval(Double(secondsFromGMT))
}
///If this var returns true, then daylight savings time is active and an hour of daylight is gained (during the summer).
var isDaylightSavings:Bool{
    return timezone.daylightSavingTimeOffset(for: self) == 0 ? false : true
}
var daylightSavings:Double{
    return isDaylightSavings ? 3600.0 : 0.0
}

However these methods sometimes return midnight, 23:00, or even 22:00 the previous day.

I'm a relatively inexperienced programmer so I feel like I'm lacking a basic understanding for the date class or missing a large concept. Why is it so difficult for me to simply find midnight on a given date?

I even forsook the idea of returning midnight and tried to just find noon on a given day with the code:

    var noon:Date{
    let gregorian = Calendar(identifier: .gregorian)
    var components = gregorian.dateComponents([.year, .month, .day, .hour, .minute, .second], from: self)

    components.hour = 12
    components.minute = 0
    components.second = 0
    return gregorian.date(from: components)!
}

But this returns 16:00 or 17:00 as opposed to noon. Any help would be appreciated.


Solution

  • When you print a date, it is printed in UTC time. So when you print your Dates, they differ from your local time by 4/5 hours.

    If you use the following code instead

    print(yourDate.description(with: .current))
    

    Where yourDate is your date, it will be in the correct time zone.