naoty / Timepiece

Intuitive date handling in Swift
MIT License
2.63k stars 147 forks source link

NSDate.beginningOfHour is not compatible with Daylight Saving Time. #31

Closed norio-nomura closed 8 years ago

norio-nomura commented 9 years ago

Sample code is following:

//: Playground - noun: a place where people can play

import Foundation
import Timepiece

let timeZone = NSTimeZone(name: "Australia/Adelaide")!
timeZone.daylightSavingTime // true
NSTimeZone.setDefaultTimeZone(timeZone)

let calendar = NSCalendar.currentCalendar()

let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")

// This Year
let comp = calendar.components(.CalendarUnitEra | .CalendarUnitYear, fromDate: NSDate())
let startOfThisYear = calendar.dateFromComponents(comp)!

var prevDate = startOfThisYear
// transition
while let transition = timeZone.nextDaylightSavingTimeTransitionAfterDate(prevDate)
    where calendar.isDate(transition, equalToDate: startOfThisYear, toUnitGranularity: .CalendarUnitYear) {

        println("transition: \(formatter.stringFromDate(transition))(\(transition))")

        let twoHourBefore = transition - 2.hours
        let twoHourAfter = transition + 2.hours

        var time = twoHourBefore
        while time <= twoHourAfter {

            let beginningOfHour = time.beginningOfHour

            // check equality by hour
            if calendar.isDate(time, equalToDate: beginningOfHour, toUnitGranularity: .CalendarUnitHour) {
                println("\(formatter.stringFromDate(time))(\(time)) is in \(formatter.stringFromDate(beginningOfHour))(\(beginningOfHour))")
            } else {
                println("\(formatter.stringFromDate(time))(\(time)) is not in \(formatter.stringFromDate(beginningOfHour))(\(beginningOfHour))")
            }

            time = time + 5.minutes
        }

        prevDate = transition
}

result is following:

transition: 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 01:05:00 +1030(2015-04-04 14:35:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 01:10:00 +1030(2015-04-04 14:40:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 01:15:00 +1030(2015-04-04 14:45:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 01:20:00 +1030(2015-04-04 14:50:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 01:25:00 +1030(2015-04-04 14:55:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 01:30:00 +1030(2015-04-04 15:00:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 01:35:00 +1030(2015-04-04 15:05:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 01:40:00 +1030(2015-04-04 15:10:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 01:45:00 +1030(2015-04-04 15:15:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 01:50:00 +1030(2015-04-04 15:20:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 01:55:00 +1030(2015-04-04 15:25:00 +0000) is in 2015-04-05 01:00:00 +1030(2015-04-04 14:30:00 +0000)
2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:05:00 +1030(2015-04-04 15:35:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:10:00 +1030(2015-04-04 15:40:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:15:00 +1030(2015-04-04 15:45:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:20:00 +1030(2015-04-04 15:50:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:25:00 +1030(2015-04-04 15:55:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:30:00 +1030(2015-04-04 16:00:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:35:00 +1030(2015-04-04 16:05:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:40:00 +1030(2015-04-04 16:10:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:45:00 +1030(2015-04-04 16:15:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:50:00 +1030(2015-04-04 16:20:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:55:00 +1030(2015-04-04 16:25:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:05:00 +0930(2015-04-04 16:35:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:10:00 +0930(2015-04-04 16:40:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:15:00 +0930(2015-04-04 16:45:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:20:00 +0930(2015-04-04 16:50:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:25:00 +0930(2015-04-04 16:55:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:30:00 +0930(2015-04-04 17:00:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:35:00 +0930(2015-04-04 17:05:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:40:00 +0930(2015-04-04 17:10:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:45:00 +0930(2015-04-04 17:15:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:50:00 +0930(2015-04-04 17:20:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:55:00 +0930(2015-04-04 17:25:00 +0000) is not in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 03:05:00 +0930(2015-04-04 17:35:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 03:10:00 +0930(2015-04-04 17:40:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 03:15:00 +0930(2015-04-04 17:45:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 03:20:00 +0930(2015-04-04 17:50:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 03:25:00 +0930(2015-04-04 17:55:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 03:30:00 +0930(2015-04-04 18:00:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 03:35:00 +0930(2015-04-04 18:05:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 03:40:00 +0930(2015-04-04 18:10:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 03:45:00 +0930(2015-04-04 18:15:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 03:50:00 +0930(2015-04-04 18:20:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 03:55:00 +0930(2015-04-04 18:25:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)
2015-04-05 04:00:00 +0930(2015-04-04 18:30:00 +0000) is in 2015-04-05 04:00:00 +0930(2015-04-04 18:30:00 +0000)
transition: 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 00:05:00 +0930(2015-10-03 14:35:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 00:10:00 +0930(2015-10-03 14:40:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 00:15:00 +0930(2015-10-03 14:45:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 00:20:00 +0930(2015-10-03 14:50:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 00:25:00 +0930(2015-10-03 14:55:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 00:30:00 +0930(2015-10-03 15:00:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 00:35:00 +0930(2015-10-03 15:05:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 00:40:00 +0930(2015-10-03 15:10:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 00:45:00 +0930(2015-10-03 15:15:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 00:50:00 +0930(2015-10-03 15:20:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 00:55:00 +0930(2015-10-03 15:25:00 +0000) is in 2015-10-04 00:00:00 +0930(2015-10-03 14:30:00 +0000)
2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 01:05:00 +0930(2015-10-03 15:35:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 01:10:00 +0930(2015-10-03 15:40:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 01:15:00 +0930(2015-10-03 15:45:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 01:20:00 +0930(2015-10-03 15:50:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 01:25:00 +0930(2015-10-03 15:55:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 01:30:00 +0930(2015-10-03 16:00:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 01:35:00 +0930(2015-10-03 16:05:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 01:40:00 +0930(2015-10-03 16:10:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 01:45:00 +0930(2015-10-03 16:15:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 01:50:00 +0930(2015-10-03 16:20:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 01:55:00 +0930(2015-10-03 16:25:00 +0000) is in 2015-10-04 01:00:00 +0930(2015-10-03 15:30:00 +0000)
2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 03:05:00 +1030(2015-10-03 16:35:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 03:10:00 +1030(2015-10-03 16:40:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 03:15:00 +1030(2015-10-03 16:45:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 03:20:00 +1030(2015-10-03 16:50:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 03:25:00 +1030(2015-10-03 16:55:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 03:30:00 +1030(2015-10-03 17:00:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 03:35:00 +1030(2015-10-03 17:05:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 03:40:00 +1030(2015-10-03 17:10:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 03:45:00 +1030(2015-10-03 17:15:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 03:50:00 +1030(2015-10-03 17:20:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 03:55:00 +1030(2015-10-03 17:25:00 +0000) is in 2015-10-04 03:00:00 +1030(2015-10-03 16:30:00 +0000)
2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 04:05:00 +1030(2015-10-03 17:35:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 04:10:00 +1030(2015-10-03 17:40:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 04:15:00 +1030(2015-10-03 17:45:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 04:20:00 +1030(2015-10-03 17:50:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 04:25:00 +1030(2015-10-03 17:55:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 04:30:00 +1030(2015-10-03 18:00:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 04:35:00 +1030(2015-10-03 18:05:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 04:40:00 +1030(2015-10-03 18:10:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 04:45:00 +1030(2015-10-03 18:15:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 04:50:00 +1030(2015-10-03 18:20:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 04:55:00 +1030(2015-10-03 18:25:00 +0000) is in 2015-10-04 04:00:00 +1030(2015-10-03 17:30:00 +0000)
2015-10-04 05:00:00 +1030(2015-10-03 18:30:00 +0000) is in 2015-10-04 05:00:00 +1030(2015-10-03 18:30:00 +0000)

On above result, "2015-04-05 02:00:00" appear twice on +1030 and +0930 before transition. beginningOfHour should return +1030 value when receiver was +1030

naoty commented 9 years ago

@norio-nomura Thank you for reporting! Do you mean that a NSDate object which has own time zone is not compatible with daylight-saving time?

norio-nomura commented 9 years ago

beginningOfHour should return +1030 value when receiver was +1030

Sorry, above is not correct. Maybe result should be as following:

2015-04-05 02:55:00 +1030(2015-04-04 16:25:00 +0000) is in 2015-04-05 02:00:00 +1030(2015-04-04 15:30:00 +0000)
2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 02:05:00 +0930(2015-04-04 16:35:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 02:10:00 +0930(2015-04-04 16:40:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 02:15:00 +0930(2015-04-04 16:45:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 02:20:00 +0930(2015-04-04 16:50:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 02:25:00 +0930(2015-04-04 16:55:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 02:30:00 +0930(2015-04-04 17:00:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 02:35:00 +0930(2015-04-04 17:05:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 02:40:00 +0930(2015-04-04 17:10:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 02:45:00 +0930(2015-04-04 17:15:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 02:50:00 +0930(2015-04-04 17:20:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 02:55:00 +0930(2015-04-04 17:25:00 +0000) is in 2015-04-05 02:00:00 +0930(2015-04-04 16:30:00 +0000)
2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000) is in 2015-04-05 03:00:00 +0930(2015-04-04 17:30:00 +0000)

I don't know about Timepiece's NSDate extension for supporting timezone. But, following code gets above result.

//: Playground - noun: a place where people can play

import Foundation
import Timepiece

extension NSCalendar {
    public func startOfHourForDate(date: NSDate) -> NSDate {
        let comp = components(.CalendarUnitMinute | .CalendarUnitSecond | .CalendarUnitNanosecond, fromDate: date)
        comp.minute *= -1
        comp.second *= -1
        comp.nanosecond *= -1
        return dateByAddingComponents(comp, toDate: date, options: .MatchNextTime)!
    }
}

let timeZone = NSTimeZone(name: "Australia/Adelaide")!
timeZone.daylightSavingTime // true
NSTimeZone.setDefaultTimeZone(timeZone)

let calendar = NSCalendar.currentCalendar()

let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")

// This Year
let comp = calendar.components(.CalendarUnitEra | .CalendarUnitYear, fromDate: NSDate())
let startOfThisYear = calendar.dateFromComponents(comp)!

var prevDate = startOfThisYear
// transition
while let transition = timeZone.nextDaylightSavingTimeTransitionAfterDate(prevDate)
    where calendar.isDate(transition, equalToDate: startOfThisYear, toUnitGranularity: .CalendarUnitYear) {

        println("transition: \(formatter.stringFromDate(transition))(\(transition))")

        let twoHourBefore = transition - 2.hours
        let twoHourAfter = transition + 2.hours

        var time = twoHourBefore
        while time <= twoHourAfter {

            let beginningOfHour = calendar.startOfHourForDate(time)

            // check equality by hour
            if calendar.isDate(time, equalToDate: beginningOfHour, toUnitGranularity: .CalendarUnitHour) {
                println("\(formatter.stringFromDate(time))(\(time)) is in \(formatter.stringFromDate(beginningOfHour))(\(beginningOfHour))")
            } else {
                println("\(formatter.stringFromDate(time))(\(time)) is not in \(formatter.stringFromDate(beginningOfHour))(\(beginningOfHour))")
            }

            time = time + 5.minutes
        }

        prevDate = transition
}
naoty commented 9 years ago

@norio-nomura What problem does your code demonstrate?

norio-nomura commented 9 years ago

Sorry, my code is too complex for describing issue. I make it simple.

//: Playground - noun: a place where people can play

import Foundation
import Timepiece

let timeZone = NSTimeZone(name: "Australia/Adelaide")!
timeZone.daylightSavingTime // true
NSTimeZone.setDefaultTimeZone(timeZone)

let calendar = NSCalendar.currentCalendar()
let transitionDay = calendar.dateWithEra(1, year: 2015, month: 4, day: 5, hour: 0, minute: 0, second: 0, nanosecond: 0)!

let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"

var stepBy1Hour = transitionDay
println("step by 1 hour | beginningOfHour | NG?")
println("-------------- | --------------- | ---")
while calendar.isDate(stepBy1Hour, equalToDate: transitionDay, toUnitGranularity: .CalendarUnitDay) {
    let beginningOfHour = stepBy1Hour.beginningOfHour
    print("\(formatter.stringFromDate(stepBy1Hour))|\(formatter.stringFromDate(beginningOfHour))")
    if calendar.isDate(stepBy1Hour, equalToDate: beginningOfHour, toUnitGranularity: .CalendarUnitHour) {
        println("|")
    } else {
        println("|<- NG")
    }
    stepBy1Hour = stepBy1Hour + 1.hour
}
step by 1 hour beginningOfHour NG?
2015-04-05 00:00:00 +1030 2015-04-05 00:00:00 +1030
2015-04-05 01:00:00 +1030 2015-04-05 01:00:00 +1030
2015-04-05 02:00:00 +1030 2015-04-05 02:00:00 +1030
2015-04-05 02:00:00 +0930 2015-04-05 02:00:00 +1030 <- NG
2015-04-05 03:00:00 +0930 2015-04-05 03:00:00 +0930
2015-04-05 04:00:00 +0930 2015-04-05 04:00:00 +0930
2015-04-05 05:00:00 +0930 2015-04-05 05:00:00 +0930
2015-04-05 06:00:00 +0930 2015-04-05 06:00:00 +0930
2015-04-05 07:00:00 +0930 2015-04-05 07:00:00 +0930
2015-04-05 08:00:00 +0930 2015-04-05 08:00:00 +0930
2015-04-05 09:00:00 +0930 2015-04-05 09:00:00 +0930
2015-04-05 10:00:00 +0930 2015-04-05 10:00:00 +0930
2015-04-05 11:00:00 +0930 2015-04-05 11:00:00 +0930
2015-04-05 12:00:00 +0930 2015-04-05 12:00:00 +0930
2015-04-05 13:00:00 +0930 2015-04-05 13:00:00 +0930
2015-04-05 14:00:00 +0930 2015-04-05 14:00:00 +0930
2015-04-05 15:00:00 +0930 2015-04-05 15:00:00 +0930
2015-04-05 16:00:00 +0930 2015-04-05 16:00:00 +0930
2015-04-05 17:00:00 +0930 2015-04-05 17:00:00 +0930
2015-04-05 18:00:00 +0930 2015-04-05 18:00:00 +0930
2015-04-05 19:00:00 +0930 2015-04-05 19:00:00 +0930
2015-04-05 20:00:00 +0930 2015-04-05 20:00:00 +0930
2015-04-05 21:00:00 +0930 2015-04-05 21:00:00 +0930
2015-04-05 22:00:00 +0930 2015-04-05 22:00:00 +0930
2015-04-05 23:00:00 +0930 2015-04-05 23:00:00 +0930
naoty commented 9 years ago

@norio-nomura Thanks! I will try to write tests and fix the problem.