5

When I compute the start of a day, a time difference of one hour is obtained. Why is not corrected for GMT+1?

let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
cal.timeZone = NSTimeZone.localTimeZone()

let startOfToday = cal.startOfDayForDate(NSDate())

print(NSTimeZone.localTimeZone())
print(startOfToday)

Output:

"Local Time Zone (Europe/Amsterdam (GMT+1) offset 3600)\n"
"2016-01-14 23:00:00 +0000\n"
Gerard
  • 349
  • 2
  • 16
  • Are you trying to get the start of day at GMT time ? Why do you need midnight? You probably should use noon instead (12pm) – Leo Dabus Jan 15 '16 at 18:21
  • Yes, just the time of the start of the day in my timezone (which is GMT+1) – Gerard Jan 15 '16 at 18:22
  • Your code works fine for me "Jan 15, 2016, 12:00 AM" GMT "2016-01-15 02:00:00 +0000\n" 2 hours ahead. Note: even if you omit the `cal.timeZone = NSTimeZone.localTimeZone()` you would get the same result. Local timezone it is the default. – Leo Dabus Jan 15 '16 at 18:24
  • Hm.. I would also expect correct functioning with this code. Do you live at GMT +0? My day normally starts at 24.00 and not at 23.00, so there is still a time difference of 1 hour with this code when I execute it. I need this value in a predicate for Core Data so the exact (midnight) time is of importance to fetch the correct data. – Gerard Jan 15 '16 at 18:30
  • you shouldn't care about time zone. If you don't care about the time just use 12pm as I said – Leo Dabus Jan 15 '16 at 18:31
  • I live at minus 2 hours from GMT, so when the day starts here GMT time it is 2AM – Leo Dabus Jan 15 '16 at 18:34
  • 1
    NSDate is an absolute point in time and does not have a timezone. Printing an NSDate *always* uses GMT. The result is correct because "2016-01-14 23:00:00 +0000" is the same point in time as "2016-01-15 00:00:00 +0200" – Martin R Jan 15 '16 at 18:39
  • Typo in my last comment, it should be *"... same point in time as "2016-01-15 00:00:00 +0100""* – If you search for "NSDate wrong" or "NSDateFormatter wrong" then you'll find name similar questions, this is asked regularly :) – Martin R Jan 15 '16 at 18:47
  • 1
    Clear! I wasn't aware of the duplicate question. However, the answer below helps to set to noon time, – Gerard Jan 15 '16 at 18:50
  • @Gerard: Well, it depends on what you want. If you want to fetch all Core Data entries which are (for example) from today *at your location/timezone*, then your code is correct. Leo's code will give you the entries which are from today *at GMT*. – Martin R Jan 15 '16 at 18:53

1 Answers1

6

Your code should work fine, you shouldn't care about time zones. As already mentioned by Martin R "NSDate is an absolute point in time and does not have a timezone". If really need to use UTC time you can set the calendar property to UTC to obtain the startOfDay or noon at UTC time for any date as follow:

extension Calendar {
    static let utc: Calendar  = {
        var calendar = Calendar.current
        calendar.timeZone = TimeZone(identifier: "UTC")!
        return calendar
    }()
    static let localTime: Calendar  = {
        var calendar = Calendar.current
        calendar.timeZone = .current
        return calendar
    }()
}

extension Date {
    var noon: Date {
        return Calendar.localTime.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
    }
    var startOfDay: Date {
        return Calendar.localTime.startOfDay(for: self)
    }
    var noonAtUTC: Date {
        return Calendar.utc.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
    }
    var startOfDayAtUTC: Date {
        return Calendar.utc.startOfDay(for: self)
    }
}

print(Date().noon)               // "2018-04-30 15:00:00 +0000\n"
print(Date().startOfDay)         // "2018-04-30 03:00:00 +0000\n"

print(Date().noonAtUTC)          // "2018-04-30 12:00:00 +0000\n"
print(Date().startOfDayAtUTC)    // "2018-04-30 00:00:00 +0000\n"
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571