サマータイムや渡航によって、保存されている時間データと、現在時刻のタイムゾーンにズレが生じる。それによって、所定の時間に通知がこない。コンテンツが更新されない。などはよくある話です。
今回、そのよくある話に見事はまったので、そのテストを書きました。
サマータイムは同じ場所に居ながら、時差が変更される
サマータイムとは、夏は早く明るくなるんだから、一日をちょっと早く開始すればみんな活動時間伸びていいじゃん。っていうアレです。
システム的には、サマータイム中とサマータイム外だと、同じ場所にいるのに時差が変わります
# シドニーの場合
2016/11/19 00:00:00 UTC+11
2017/06/20 00:00:00 UTC+10
# シドニーの場合(UTCで保存)
2016/11/18 13:00:00 UTC+0
2017/06/20 14:00:00 UTC+0
"Australia/Sydney"のサマータイム中に登録したデータのサマータイム外での挙動をXCTestで書く
NSDateFormatterのtimeZoneを設定することで、サマータイムを発生させます。
class TimezoneTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testTimezoneChange {
let formatter = NSDateFormatter()
formatter.timeZone = NSTimeZone.init(name: "Australia/Sydney")
formatter.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
formatter.dateFormat = "yyyy/MM/dd"
let registerDate = formatter.dateFromString("2016/11/19")
/*
* ここにregisterDateをDBに保存するコードを記載
*/
let targetDate = formatter.dateFromString("2017/06/20")
timeTravel(to: targetDate) {
print(registerDate) //=> 2016-11-18 13:00:00 +0000
print(targetDate) //=> 2017-06-19 14:00:00 +0000
/*
* ここにタイムゾーンが変わったとき、どうあるべきかを記載
*/
}
}
private func timeTravel(to date: NSDate, block: () -> Void) {
let customDateBlock: @convention(block) (AnyObject) -> NSDate = { _ in date }
let implementation = imp_implementationWithBlock(unsafeBitCast(customDateBlock, AnyObject.self))
let method = class_getInstanceMethod(NSClassFromString("__NSPlaceholderDate"), #selector(NSObject.init))
let oldImplementation = method_getImplementation(method)
method_setImplementation(method, implementation)
block()
method_setImplementation(method, oldImplementation)
}
}