Android AlarmManager 通过时区或夏令时进行调度
Android AlarmManager scheduling through time zone or daylight shifts
我有一个使用 AlarmManager 安排提醒的逻辑。我需要执行以下操作:
逻辑1:当用户改变时区时,例如他从英国(UTC+0)到中欧(UTC+1)旅行,警报应该跟随时区.
例如,安排在下午 3 点 UTC+0 的提醒应该在下午 4 点 UTC+1
逻辑2:当时间偏移发生时,例如时间偏移到spring的夏令时(从UTC+1到UTC+2),告警应该保持原来的时间
例如,安排在下午 3 点 UTC+1 的提醒应该在下午 3 点 UTC+2
触发
我怎样才能做到这一点?截至目前,我没有特定的逻辑,所有警报都遵循 逻辑 1。我找不到确定时移何时发生的方法。
调度逻辑很简单:
LocalDateTime reminderTime = LocalDateTime.of(...)
ZoneOffset currentOffsetForMyZone = ZoneId.systemDefault().getRules().getOffset(Instant.now());
reminderTime.toInstant(currentOffsetForMyZone).toEpochMilli();
alarmManager.setExact(AlarmManager.RTC_WAKEUP, reminderTime, pendingIntent);
为每个闹钟存储一天中的时间和设置闹钟的时区。这足以在正确的时间触发警报,无论用户当前是否处于不同的时区。 Java 将考虑夏令时 (DST)。
您的示例时间和 UTC 偏移对应于那些时区的标准时间,所以让我们从标准时间的示例日期开始,即使现在是几天前:
LocalTime alarmTime = LocalTime.of(15, 0);
ZoneId alarmTimeZone = ZoneId.of("Europe/London");
// Travel to Paris and see the alarm go off at 4, assuming standard time
ZoneId currentTimeZone = ZoneId.of("Europe/Paris");
Instant actualAlarmTime = LocalDate.of(2021, Month.MARCH, 18)
.atTime(alarmTime)
.atZone(alarmTimeZone)
.toInstant();
ZonedDateTime timeOnLocation = actualAlarmTime.atZone(currentTimeZone);
System.out.format("Scheduled at %s or %d millis, goes off at %s local time%n",
actualAlarmTime, actualAlarmTime.toEpochMilli(), timeOnLocation);
代码打印:
Scheduled at 2021-03-18T15:00:00Z or 1616079600000 millis, goes off at
2021-03-18T16:00+01:00[Europe/Paris] local time
让我们也尝试在一年中的夏令时约会。我已将 Paris
更改为 London
并将 MARCH
更改为 APRIL
:
// Stay back home in the UK
ZoneId currentTimeZone = ZoneId.of("Europe/London");
Instant actualAlarmTime = LocalDate.of(2021, Month.APRIL, 18)
.atTime(alarmTime)
.atZone(alarmTimeZone)
.toInstant();
Scheduled at 2021-04-18T14:00:00Z or 1618754400000 millis, goes off at
2021-04-18T15:00+01:00[Europe/London] local time
基本技巧是:不要对设置闹钟的时区使用当前偏移量。让 Java 自动应用警报响起的日期和时间的偏移量。
如果有人感兴趣,修复方法是为警报发出的日期和时间应用正确的偏移量,正如 Ole 所指出的那样。我的愚蠢错误是始终应用 当前 时区。
LocalDateTime alarmTime = LocalDateTime.of(...)
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime zoneDateTime = ZonedDateTime.of(alarmTime , zone);
long startAtMillis = zoneDateTime.toInstant().toEpochMilli();
//Fire alarm
notificationAlarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, startAtMillis, pendingIntent);
我有一个使用 AlarmManager 安排提醒的逻辑。我需要执行以下操作:
逻辑1:当用户改变时区时,例如他从英国(UTC+0)到中欧(UTC+1)旅行,警报应该跟随时区. 例如,安排在下午 3 点 UTC+0 的提醒应该在下午 4 点 UTC+1
逻辑2:当时间偏移发生时,例如时间偏移到spring的夏令时(从UTC+1到UTC+2),告警应该保持原来的时间 例如,安排在下午 3 点 UTC+1 的提醒应该在下午 3 点 UTC+2
触发我怎样才能做到这一点?截至目前,我没有特定的逻辑,所有警报都遵循 逻辑 1。我找不到确定时移何时发生的方法。
调度逻辑很简单:
LocalDateTime reminderTime = LocalDateTime.of(...)
ZoneOffset currentOffsetForMyZone = ZoneId.systemDefault().getRules().getOffset(Instant.now());
reminderTime.toInstant(currentOffsetForMyZone).toEpochMilli();
alarmManager.setExact(AlarmManager.RTC_WAKEUP, reminderTime, pendingIntent);
为每个闹钟存储一天中的时间和设置闹钟的时区。这足以在正确的时间触发警报,无论用户当前是否处于不同的时区。 Java 将考虑夏令时 (DST)。
您的示例时间和 UTC 偏移对应于那些时区的标准时间,所以让我们从标准时间的示例日期开始,即使现在是几天前:
LocalTime alarmTime = LocalTime.of(15, 0);
ZoneId alarmTimeZone = ZoneId.of("Europe/London");
// Travel to Paris and see the alarm go off at 4, assuming standard time
ZoneId currentTimeZone = ZoneId.of("Europe/Paris");
Instant actualAlarmTime = LocalDate.of(2021, Month.MARCH, 18)
.atTime(alarmTime)
.atZone(alarmTimeZone)
.toInstant();
ZonedDateTime timeOnLocation = actualAlarmTime.atZone(currentTimeZone);
System.out.format("Scheduled at %s or %d millis, goes off at %s local time%n",
actualAlarmTime, actualAlarmTime.toEpochMilli(), timeOnLocation);
代码打印:
Scheduled at 2021-03-18T15:00:00Z or 1616079600000 millis, goes off at 2021-03-18T16:00+01:00[Europe/Paris] local time
让我们也尝试在一年中的夏令时约会。我已将 Paris
更改为 London
并将 MARCH
更改为 APRIL
:
// Stay back home in the UK
ZoneId currentTimeZone = ZoneId.of("Europe/London");
Instant actualAlarmTime = LocalDate.of(2021, Month.APRIL, 18)
.atTime(alarmTime)
.atZone(alarmTimeZone)
.toInstant();
Scheduled at 2021-04-18T14:00:00Z or 1618754400000 millis, goes off at 2021-04-18T15:00+01:00[Europe/London] local time
基本技巧是:不要对设置闹钟的时区使用当前偏移量。让 Java 自动应用警报响起的日期和时间的偏移量。
如果有人感兴趣,修复方法是为警报发出的日期和时间应用正确的偏移量,正如 Ole 所指出的那样。我的愚蠢错误是始终应用 当前 时区。
LocalDateTime alarmTime = LocalDateTime.of(...)
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime zoneDateTime = ZonedDateTime.of(alarmTime , zone);
long startAtMillis = zoneDateTime.toInstant().toEpochMilli();
//Fire alarm
notificationAlarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, startAtMillis, pendingIntent);