23

从文档:

fireDate 中指定的日期将根据此属性的值进行解释。如果您指定 nil(默认值),则触发日期被解释为绝对 GMT 时间,这适用于倒计时计时器等情况。如果您为该属性分配一个有效的 NSTimeZone 对象,则触发日期将被解释为挂钟时间,当时区发生变化时会自动调整该时间;适合这种情况的一个例子是闹钟。

假设我在格林威治标准时间明天中午(以绝对时间)安排本地通知。我安排在西雅图下午 1 点(太平洋时间,GMT-8),然后立即前往芝加哥,晚上 11 点(中部时间,GMT-6)到达。我的设备从太平洋时间调整到中部时间。请帮助我了解我的通知何时会在以下三种情况下发生:

  1. UILocalNotification timeZone 设置为 nil。
  2. UILocalNotification 时区设置为 GMT。
  3. UILocalNotification timeZone 设置为太平洋时间。
4

3 回答 3

43

我刚刚在 iOS 6.1.3 上运行了一些测试。这是我得到的:

我在西雅图,下午 1:00(太平洋夏令时间,GMT-7)。我创建了一个NSDate

NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
// 2013-08-31 @ 12:00:00 (noon)
dateComponents.year = 2013;
dateComponents.month = 8;
dateComponents.day = 31;
dateComponents.hour = 12;
dateComponents.minute = 0;
dateComponents.second = 0;

NSDate *fireDate = [gregorianCalendar dateFromComponents:dateComponents];

我现在有

fireDate = 2013-08-31 19:00:00 +0000 (2013-08-31 12:00:00 -0700)

然后我创建并安排了通知:

notification1 = [[UILocalNotification alloc] init];
notification1.fireDate = fireDate;
// notification1.timeZone is nil by default

NSLog(@"%@", notification1);

notification2 = [[UILocalNotification alloc] init];
notification2.fireDate = fireDate;
notification2.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];

NSLog(@"%@", notification2);

notification3 = [[UILocalNotification alloc] init];
notification3.fireDate = fireDate;
notification3.timeZone = [NSTimeZone defaultTimeZone];

NSLog(@"%@", notification3);

刚刚在西雅图(太平洋夏令时间,GMT-7)创建的通知日志:

notification1:
fire date = Saturday, August 31, 2013, 12:00:00 PM Pacific Daylight Time,
time zone = (null),
next fire date = Saturday, August 31, 2013, 12:00:00 PM Pacific Daylight Time

notification2:
fire date = Saturday, August 31, 2013, 7:00:00 PM GMT,
time zone = GMT (GMT) offset 0,
next fire date = Saturday, August 31, 2013, 7:00:00 PM Pacific Daylight Time

notification3:
fire date = Saturday, August 31, 2013, 12:00:00 PM Pacific Daylight Time,
time zone = US/Pacific (PDT) offset -25200 (Daylight),
next fire date = Saturday, August 31, 2013, 12:00:00 PM Pacific Daylight Time

我将手机的时区更改为芝加哥,现在是下午 3:00(中央夏令时间,GMT-5)。

芝加哥的通知日志(中央夏令时间,GMT-5)

notification1:
fire date = Saturday, August 31, 2013, 2:00:00 PM Central Daylight Time,
time zone = (null),
next fire date = Saturday, August 31, 2013, 2:00:00 PM Central Daylight Time

notification2:
fire date = Saturday, August 31, 2013, 7:00:00 PM GMT,
time zone = GMT (GMT) offset 0,
next fire date = Saturday, August 31, 2013, 7:00:00 PM Central Daylight Time

notification3:
fire date = Saturday, August 31, 2013, 12:00:00 PM Pacific Daylight Time,
time zone = US/Pacific (PDT) offset -25200 (Daylight),
next fire date = Saturday, August 31, 2013, 12:00:00 PM Central Daylight Time

结论:

  1. 当 UILocalNotificationtimeZone为 nil 时,触发日期在时间上是固定的。这意味着通知将在格林威治标准时间 7 点下午 12:00、格林威治标准时间 5 点下午 2:00 或格林威治标准时间 7:00 触发。
  2. 当 UILocalNotificationtimeZone设置为 GMT 时,触发日期以 GMT 时间计算,并且如果用户转到另一个时区,将自动更新。在此示例中,时间 12:00 GMT-7 转换为 19:00 GMT,并且通知设置为本地时间 19:00,无论我们在哪个时区(格林威治标准时间 19:00、格林威治标准时间 19:00 或19:00 GMT-7)。
  3. 当 UILocalNotificationtimeZone设置为本地时区(太平洋夏令时间,GMT-7)时,触发日期以本地时间计算,如果用户转到另一个时区,将自动更新。在此示例中,时间为 12:00 GMT-7,因此无论我们在哪个时区(格林威治标准时间 12:00、格林威治标准时间 12:00 或格林威治标准时间 12:00),通知都将在当地时间 12:00 触发7)。
于 2013-08-30T19:34:28.750 回答
2

iOS 13 上带有 UNCalendarNotificationTrigger 的 Swift 5.2

我使用@brnunes 代码作为灵感来使用UNCalendarNotificationTrigger.

TimeZone.autoupdatingCurrent如果您想在本地时间发送通知,请使用。示例:您在格林威治标准时间下午 6 点安排通知,然后将您设备上的时区更改为 CET,通知仍将安排在下午 6 点在您的设备上。

使用任何其他时区,TimeZone.current或者TimeZone.init(abbreviation: "GMT")如果您想要一个及时固定的开火日期。示例:您在东部夏令时间 (EDT GMT-4) 下午 2 点安排通知,然后将您设备上的时区更改为 CEST (GMT+2),现在通知将安排在您设备上的晚上 8 点。这就像在格林威治标准时间下午 6 点开会。会议时间没有改变,只有 EDT 是下午 2 点,CEST 是晚上 8 点。

我使用以下代码添加通知:

func addNotification(identifier: String, timeZone: TimeZone?) {
    let content = UNMutableNotificationContent()
    content.title = "Title \(identifier)"
    content.body = "Body"

    let trigger = UNCalendarNotificationTrigger(
        dateMatching: DateComponents(
            calendar: Calendar.current,
            timeZone: timeZone,
            year: 2020,
            month: 04,
            day: 01,
            hour: 18,
            minute: 30,
            second: 0),
        repeats: false)

    let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)

    UNUserNotificationCenter
        .current()
        .add(request) { _ in
            print("Scheduled \(identifier)")
    }
}

我添加了四个不同的通知。

addNotification(identifier: "1", timeZone: nil)
addNotification(identifier: "2", timeZone: TimeZone.init(abbreviation: "GMT")!)
addNotification(identifier: "3", timeZone: TimeZone.autoupdatingCurrent)
addNotification(identifier: "4", timeZone: TimeZone.current)

我使用以下代码打印预定的请求。

UNUserNotificationCenter.current().getPendingNotificationRequests(completionHandler: { notificationRequests in
    let dateFormatter = DateFormatter()
    dateFormatter.dateStyle = .medium
    dateFormatter.timeStyle = .medium
    dateFormatter.timeZone = TimeZone.current

    print(TimeZone.current)
    notificationRequests.forEach({
        let nextTriggerDate = ($0.trigger as! UNCalendarNotificationTrigger).nextTriggerDate()!
        print("\($0.identifier): \(dateFormatter.string(from: nextTriggerDate)) (\(nextTriggerDate))")
    })
})

首先,我使用 CEST (GMT+2) 运行代码。然后,我转到我的 iOS 设置并将我的时区更改为美国东部夏令时间 (GMT-4) 的迈阿密。这是结果。

Europe/Berlin (current)
1: 1. Apr 2020 at 18:30:00 (2020-04-01 16:30:00 +0000)
2: 1. Apr 2020 at 20:30:00 (2020-04-01 18:30:00 +0000)
3: 1. Apr 2020 at 18:30:00 (2020-04-01 16:30:00 +0000)
4: 1. Apr 2020 at 18:30:00 (2020-04-01 16:30:00 +0000)

US/Eastern (current)
1: 1. Apr 2020 at 12:30:00 (2020-04-01 16:30:00 +0000)
2: 1. Apr 2020 at 14:30:00 (2020-04-01 18:30:00 +0000)
3: 1. Apr 2020 at 18:30:00 (2020-04-01 22:30:00 +0000)
4: 1. Apr 2020 at 12:30:00 (2020-04-01 16:30:00 +0000)

正如您在 1、2 和 4 中看到的那样,时间日期永远不会改变。两次都是2020-04-01 16:30:00 +00002020-04-01 18:30:00 +00002020-04-01 16:30:00 +0000。只有触发通知的本地时间会更改和更新。

使用 3,实际日期从2020-04-01 16:30:00 +0000更改为2020-04-01 22:30:00 +0000。但是,本地时间不会改变并保持在18:30:00

正如您在此处看到的,@brnunes 的答案中时区的工作方式与UILocalNotification和存在差异UNCalendarNotifactionTrigger。在他的第二个结论中,他说不UILocalNotifictions同时区的自动更新。随着UNCalendarNotificationTrigger,情况不再如此。正如@Nicolas Buquet 所指出的,TimeZone.autoupdatingCurrent相当于defaultTimeZone.

于 2020-03-29T23:25:56.397 回答
0

在 Swift 3 中,使用TimeZone.autoupdatingCurrent的行为与 Objective-C 相同[NSTimeZone defaultTimeZone]

于 2016-11-15T10:43:31.357 回答