Linux 夏令时通知
Linux daylight savings notification
我试图找到一种在应用夏令时时从系统 (Linux) 接收通知的方法,但我似乎无法找到类似的方法。
考虑一个程序在 pselect()
上等待多个计时器 fd
,所有计时器都有 24 小时的间隔,但开始时间不同,由用户定义; "07:00 ON
, 07:25 OFF
"(例如,如果它是咖啡机)。
因为用户在本地时间提供这些时间并且 Linux 在 UTC 上运行,所以时区调整计时器 fd
需要在每次夏令时重新调整。 (当符合夏令时标准的闹钟把他叫醒时,用户想要咖啡......)
按照我的想象,解决此问题的明智方法是注册到 system/kernel/init/whatever 以在应用夏令时时收到通知,并避免陷入试图确定此类日期的混乱业务并自己计时,并希望系统同意您的结果(即您的重新同步操作和实际夏令时同时发生)。
是否有任何方式可以在夏令时更改时收到通知?或者可能对当地时间进行任何更改(假设 DST 更改对其进行了修改)?
Consider a program sits on a pselect() waiting for a number of timer fd's, all which have exactly 24-hour intervals, but differing start times
这就是你的根本问题。所有的日子都不完全是 24 小时——有时它们会相差一个小时(夏令时),或相差几秒(闰秒);就像不是每个二月都有28天一样。
一种更简单和轻量级(消耗更少的资源)的方法是使用 UTC 中未来事件的最小堆,例如
struct trigger {
/* Details on how the event is defined;
for example, "each day at 07:00 local time".
*/
};
struct utc_event {
struct trigger *trigger;
time_t when;
};
struct event_min_heap {
size_t max_events;
size_t num_events;
struct utc_event event[];
};
struct event_min_heap
中的 event
C99 灵活数组成员是一个包含 num_events
个事件的数组(为 max_events
分配的内存;如果需要更多事件,可以重新分配)在由每个 event
条目中的 when
字段键入的 min heap 中。也就是说,最早的事件总是在根部。
每当当前时间至少为 event[0].when
时,它就是 "triggered" -- 意味着无论要采取什么行动,都被采取 --,并且基于它所指的 struct trigger
到,该事件下一次发生的时间更新为 event[0]
,然后它在堆中向下渗透到适当的位置。请注意,您只需使用 mktime()
从分解的本地时间字段中获取 UTC 时间。
(如果这是一个多用户服务,那么您可以支持多个并发时区,每个触发器一个,方法是将 TZ
环境变量设置为相应的时区定义,并调用 tzset()
在调用 mktime()
之前。因为环境由进程中的所有线程共享,如果你有一个多线程进程,你需要确保一次只有一个线程执行此操作。通常,像这样的东西是使用单线程进程可以完美实现。)
当根 (event[0]
) 中的事件被删除或过滤(筛选)时,具有下一个最小 when
的事件将位于根中。如果 when
等于或小于 UTC 中的当前时间,它也会被触发。
当下一个 when
在未来时,进程可以休眠剩余的时间间隔。
仅此而已。您不需要多个计时器——这是系统范围内的有限资源——您也不需要担心某些本地时间是否是夏令时; C 库 mktime()
将为您处理这些细节。
现在,如果您不喜欢这种方法(同样,它使用的资源少于您在问题中概述的方法),请联系 SystemD 开发人员。如果你足够讨好他们,我相信他们会为你提供一个 dbus 信号。它目前的设计并没有任何理智,多一个缺点肯定不会让它变得更糟。切换到 C# 可能会被认为是一个优势。
了解 mktime()
计算指定时刻的 Unix 纪元时间 (time_t
) 至关重要,如果夏令时适用于该特定时刻,则应用夏令时。函数调用时是否生效夏令时无关紧要!
此外,UTC 时间是协调世界时,不受时区或夏令时的限制。
考虑以下程序,mktime-example.c
:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
static time_t epoch(struct tm *const tm,
const int year, const int month, const int day,
const int hour, const int minute, const int second,
const int isdst)
{
struct tm temp;
time_t result;
memset(&temp, 0, sizeof temp);
temp.tm_year = year - 1900;
temp.tm_mon = month - 1;
temp.tm_mday = day;
temp.tm_hour = hour;
temp.tm_min = minute;
temp.tm_sec = second;
temp.tm_isdst = isdst;
result = mktime(&temp);
if (isdst >= 0 && isdst != temp.tm_isdst) {
/* The caller is mistaken about DST, and mktime()
* adjusted the time. We readjust it. */
temp.tm_year = year - 1900;
temp.tm_mon = month - 1;
temp.tm_mday = day;
temp.tm_hour = hour;
temp.tm_min = minute;
temp.tm_sec = second;
/* Note: tmp.tm_isdst is kept unchanged. */
result = mktime(&temp);
}
if (tm)
memcpy(tm, &temp, sizeof temp);
return result;
}
static void show(const time_t t, const struct tm *const tm)
{
printf("(time_t)%lld = %04d-%02d-%02d %02d:%02d:%02d",
(long long)t, tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
if (tm->tm_isdst == 1)
printf(", DST in effect");
else
if (tm->tm_isdst == 0)
printf(", DST not in effect");
else
if (tm->tm_isdst == -1)
printf(", Unknown if DST in effect");
if (tzname[0] && tzname[0][0])
printf(", %s timezone", tzname[0]);
printf("\n");
fflush(stdout);
}
int main(int argc, char *argv[])
{
struct tm tm;
time_t t;
long long secs;
int arg, year, month, day, hour, min, sec, isdst, n;
char ch;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s [ :REGION/CITY | =TIMEZONE ] @EPOCH | YYYYMMDD-HHMMSS[+-] ...\n", argv[0]);
fprintf(stderr, "Where:\n");
fprintf(stderr, " EPOCH is in UTC seconds since 19700101T000000,\n");
fprintf(stderr, " + after time indicates you prefer daylight savings time,\n");
fprintf(stderr, " - after time indicates you prefer standard time.\n");
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
for (arg = 1; arg < argc; arg++) {
if (argv[arg][0] == ':') {
if (argv[arg][1])
setenv("TZ", argv[arg], 1);
else
unsetenv("TZ");
tzset();
continue;
}
if (argv[arg][0] == '=') {
if (argv[arg][1])
setenv("TZ", argv[arg] + 1, 1);
else
unsetenv("TZ");
tzset();
continue;
}
if (argv[arg][0] == '@') {
if (sscanf(argv[arg] + 1, " %lld %c", &secs, &ch) == 1) {
t = (time_t)secs;
if (localtime_r(&t, &tm)) {
show(t, &tm);
continue;
}
}
}
n = sscanf(argv[arg], " %04d %02d %02d %*[-Tt] %02d %02d %02d %c",
&year, &month, &day, &hour, &min, &sec, &ch);
if (n >= 6) {
if (n == 6)
isdst = -1;
else
if (ch == '+')
isdst = +1; /* DST */
else
if (ch == '-')
isdst = 0; /* Not DST */
else
isdst = -1;
t = epoch(&tm, year, month, day, hour, min, sec, isdst);
if (t != (time_t)-1) {
show(t, &tm);
continue;
}
}
fflush(stdout);
fprintf(stderr, "%s: Cannot parse parameter.\n", argv[arg]);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
使用例如
编译它
gcc -Wall -O2 mktime-example.c -o mktime-example
运行 不带参数看命令行用法。 运行
./mktime-example :Europe/Helsinki 20161030-035959+ 20161030-030000- 20161030-030000+ 20161030-035959- 20161030-040000-
检查 2016 年夏令时在芬兰赫尔辛基结束时的 Unix 时间戳。该命令将输出
(time_t)1477789199 = 2016-10-30 03:59:59, DST in effect, EET timezone
(time_t)1477789200 = 2016-10-30 03:00:00, DST not in effect, EET timezone
(time_t)1477785600 = 2016-10-30 03:00:00, DST in effect, EET timezone
(time_t)1477792799 = 2016-10-30 03:59:59, DST not in effect, EET timezone
(time_t)1477792800 = 2016-10-30 04:00:00, DST not in effect, EET timezone
无论在 运行 时这个夏令时是否在某个时区生效,输出都是相同的!
当用 .tm_isdst = 0
或 .tm_isdst = 1
调用 mktime()
时,mktime()
改变了它,它也改变了指定的时间(按夏令时)。当.tm_isdst = -1
时,表示调用者不知道是否应用夏令时,库会发现;但是如果同时存在有效的标准时间和 DST 时间,C 库将选择一个(您应该假设它是随机选择的)。上面的 epoch()
函数会在必要时对此进行更正,如果用户对 DST 不正确,则取消调整时间。
Unix/linux 系统只处理 UTC,它们使用 time_t
数据(从 00:00h 1970 年 1 月 1 日到现在的秒数)作为内部时间.仅在向用户显示信息时才转换为本地时间(由于异常、夏季-冬季的变化等而导致复杂性),因此仅在转换为本地时间时才完成。如前所述,在 unix 系统中没有安排任何事情的安排或准备。
从 zdump(1)
您可以获得每个时区所需的所有信息,并使用它构建一个 crontab 以在进行切换时通知您。它查询本地时区数据库并提取有关从冬季到夏季或相反的切换(包括历史)的所有信息。
$ zdump -v Europe/Madrid
Europe/Madrid Fri Dec 13 20:45:52 1901 UTC = Fri Dec 13 20:45:52 1901 WET isdst=0 gmtoff=0
Europe/Madrid Sat Dec 14 20:45:52 1901 UTC = Sat Dec 14 20:45:52 1901 WET isdst=0 gmtoff=0
Europe/Madrid Sat May 5 22:59:59 1917 UTC = Sat May 5 22:59:59 1917 WET isdst=0 gmtoff=0
Europe/Madrid Sat May 5 23:00:00 1917 UTC = Sun May 6 00:00:00 1917 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 6 22:59:59 1917 UTC = Sat Oct 6 23:59:59 1917 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 6 23:00:00 1917 UTC = Sat Oct 6 23:00:00 1917 WET isdst=0 gmtoff=0
Europe/Madrid Mon Apr 15 22:59:59 1918 UTC = Mon Apr 15 22:59:59 1918 WET isdst=0 gmtoff=0
Europe/Madrid Mon Apr 15 23:00:00 1918 UTC = Tue Apr 16 00:00:00 1918 WEST isdst=1 gmtoff=3600
Europe/Madrid Sun Oct 6 22:59:59 1918 UTC = Sun Oct 6 23:59:59 1918 WEST isdst=1 gmtoff=3600
Europe/Madrid Sun Oct 6 23:00:00 1918 UTC = Sun Oct 6 23:00:00 1918 WET isdst=0 gmtoff=0
Europe/Madrid Sat Apr 5 22:59:59 1919 UTC = Sat Apr 5 22:59:59 1919 WET isdst=0 gmtoff=0
Europe/Madrid Sat Apr 5 23:00:00 1919 UTC = Sun Apr 6 00:00:00 1919 WEST isdst=1 gmtoff=3600
Europe/Madrid Mon Oct 6 22:59:59 1919 UTC = Mon Oct 6 23:59:59 1919 WEST isdst=1 gmtoff=3600
Europe/Madrid Mon Oct 6 23:00:00 1919 UTC = Mon Oct 6 23:00:00 1919 WET isdst=0 gmtoff=0
Europe/Madrid Wed Apr 16 22:59:59 1924 UTC = Wed Apr 16 22:59:59 1924 WET isdst=0 gmtoff=0
Europe/Madrid Wed Apr 16 23:00:00 1924 UTC = Thu Apr 17 00:00:00 1924 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 4 22:59:59 1924 UTC = Sat Oct 4 23:59:59 1924 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 4 23:00:00 1924 UTC = Sat Oct 4 23:00:00 1924 WET isdst=0 gmtoff=0
Europe/Madrid Sat Apr 17 22:59:59 1926 UTC = Sat Apr 17 22:59:59 1926 WET isdst=0 gmtoff=0
Europe/Madrid Sat Apr 17 23:00:00 1926 UTC = Sun Apr 18 00:00:00 1926 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 2 22:59:59 1926 UTC = Sat Oct 2 23:59:59 1926 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 2 23:00:00 1926 UTC = Sat Oct 2 23:00:00 1926 WET isdst=0 gmtoff=0
Europe/Madrid Sat Apr 9 22:59:59 1927 UTC = Sat Apr 9 22:59:59 1927 WET isdst=0 gmtoff=0
...
顺便说一句,如果您想收到即将发生的本地时间更改的通知,您可以使用以前的信息来构建一个包含所有信息的 crontab 文件,或者简单地构建一个包含适用规则的 crontab 文件在你的地方。例如,如果我想在西班牙的交换机更改前一天收到通知(它在 march/october 的最后一个星期日 02/03h 更改),您可以在 crontab 文件中添加一些规则:
0 0 24-30 3,10 5 echo Time daylight savings change scheduled for tomorrow | mail $USER@your.domain.com
并且会在每个星期六 (5) 向您发送一封邮件,恰好是每年 3 月 24 日至 30 日和每年 10 月(3,10 部分)的那一周 00:00h (当地时间)。我相信您将能够根据您所在的地区或提前时间调整此示例(因此,在时间更改发生的前一天)。
我试图找到一种在应用夏令时时从系统 (Linux) 接收通知的方法,但我似乎无法找到类似的方法。
考虑一个程序在 pselect()
上等待多个计时器 fd
,所有计时器都有 24 小时的间隔,但开始时间不同,由用户定义; "07:00 ON
, 07:25 OFF
"(例如,如果它是咖啡机)。
因为用户在本地时间提供这些时间并且 Linux 在 UTC 上运行,所以时区调整计时器 fd
需要在每次夏令时重新调整。 (当符合夏令时标准的闹钟把他叫醒时,用户想要咖啡......)
按照我的想象,解决此问题的明智方法是注册到 system/kernel/init/whatever 以在应用夏令时时收到通知,并避免陷入试图确定此类日期的混乱业务并自己计时,并希望系统同意您的结果(即您的重新同步操作和实际夏令时同时发生)。
是否有任何方式可以在夏令时更改时收到通知?或者可能对当地时间进行任何更改(假设 DST 更改对其进行了修改)?
Consider a program sits on a pselect() waiting for a number of timer fd's, all which have exactly 24-hour intervals, but differing start times
这就是你的根本问题。所有的日子都不完全是 24 小时——有时它们会相差一个小时(夏令时),或相差几秒(闰秒);就像不是每个二月都有28天一样。
一种更简单和轻量级(消耗更少的资源)的方法是使用 UTC 中未来事件的最小堆,例如
struct trigger {
/* Details on how the event is defined;
for example, "each day at 07:00 local time".
*/
};
struct utc_event {
struct trigger *trigger;
time_t when;
};
struct event_min_heap {
size_t max_events;
size_t num_events;
struct utc_event event[];
};
struct event_min_heap
中的 event
C99 灵活数组成员是一个包含 num_events
个事件的数组(为 max_events
分配的内存;如果需要更多事件,可以重新分配)在由每个 event
条目中的 when
字段键入的 min heap 中。也就是说,最早的事件总是在根部。
每当当前时间至少为 event[0].when
时,它就是 "triggered" -- 意味着无论要采取什么行动,都被采取 --,并且基于它所指的 struct trigger
到,该事件下一次发生的时间更新为 event[0]
,然后它在堆中向下渗透到适当的位置。请注意,您只需使用 mktime()
从分解的本地时间字段中获取 UTC 时间。
(如果这是一个多用户服务,那么您可以支持多个并发时区,每个触发器一个,方法是将 TZ
环境变量设置为相应的时区定义,并调用 tzset()
在调用 mktime()
之前。因为环境由进程中的所有线程共享,如果你有一个多线程进程,你需要确保一次只有一个线程执行此操作。通常,像这样的东西是使用单线程进程可以完美实现。)
当根 (event[0]
) 中的事件被删除或过滤(筛选)时,具有下一个最小 when
的事件将位于根中。如果 when
等于或小于 UTC 中的当前时间,它也会被触发。
当下一个 when
在未来时,进程可以休眠剩余的时间间隔。
仅此而已。您不需要多个计时器——这是系统范围内的有限资源——您也不需要担心某些本地时间是否是夏令时; C 库 mktime()
将为您处理这些细节。
现在,如果您不喜欢这种方法(同样,它使用的资源少于您在问题中概述的方法),请联系 SystemD 开发人员。如果你足够讨好他们,我相信他们会为你提供一个 dbus 信号。它目前的设计并没有任何理智,多一个缺点肯定不会让它变得更糟。切换到 C# 可能会被认为是一个优势。
了解 mktime()
计算指定时刻的 Unix 纪元时间 (time_t
) 至关重要,如果夏令时适用于该特定时刻,则应用夏令时。函数调用时是否生效夏令时无关紧要!
此外,UTC 时间是协调世界时,不受时区或夏令时的限制。
考虑以下程序,mktime-example.c
:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
static time_t epoch(struct tm *const tm,
const int year, const int month, const int day,
const int hour, const int minute, const int second,
const int isdst)
{
struct tm temp;
time_t result;
memset(&temp, 0, sizeof temp);
temp.tm_year = year - 1900;
temp.tm_mon = month - 1;
temp.tm_mday = day;
temp.tm_hour = hour;
temp.tm_min = minute;
temp.tm_sec = second;
temp.tm_isdst = isdst;
result = mktime(&temp);
if (isdst >= 0 && isdst != temp.tm_isdst) {
/* The caller is mistaken about DST, and mktime()
* adjusted the time. We readjust it. */
temp.tm_year = year - 1900;
temp.tm_mon = month - 1;
temp.tm_mday = day;
temp.tm_hour = hour;
temp.tm_min = minute;
temp.tm_sec = second;
/* Note: tmp.tm_isdst is kept unchanged. */
result = mktime(&temp);
}
if (tm)
memcpy(tm, &temp, sizeof temp);
return result;
}
static void show(const time_t t, const struct tm *const tm)
{
printf("(time_t)%lld = %04d-%02d-%02d %02d:%02d:%02d",
(long long)t, tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
if (tm->tm_isdst == 1)
printf(", DST in effect");
else
if (tm->tm_isdst == 0)
printf(", DST not in effect");
else
if (tm->tm_isdst == -1)
printf(", Unknown if DST in effect");
if (tzname[0] && tzname[0][0])
printf(", %s timezone", tzname[0]);
printf("\n");
fflush(stdout);
}
int main(int argc, char *argv[])
{
struct tm tm;
time_t t;
long long secs;
int arg, year, month, day, hour, min, sec, isdst, n;
char ch;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s [ :REGION/CITY | =TIMEZONE ] @EPOCH | YYYYMMDD-HHMMSS[+-] ...\n", argv[0]);
fprintf(stderr, "Where:\n");
fprintf(stderr, " EPOCH is in UTC seconds since 19700101T000000,\n");
fprintf(stderr, " + after time indicates you prefer daylight savings time,\n");
fprintf(stderr, " - after time indicates you prefer standard time.\n");
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
for (arg = 1; arg < argc; arg++) {
if (argv[arg][0] == ':') {
if (argv[arg][1])
setenv("TZ", argv[arg], 1);
else
unsetenv("TZ");
tzset();
continue;
}
if (argv[arg][0] == '=') {
if (argv[arg][1])
setenv("TZ", argv[arg] + 1, 1);
else
unsetenv("TZ");
tzset();
continue;
}
if (argv[arg][0] == '@') {
if (sscanf(argv[arg] + 1, " %lld %c", &secs, &ch) == 1) {
t = (time_t)secs;
if (localtime_r(&t, &tm)) {
show(t, &tm);
continue;
}
}
}
n = sscanf(argv[arg], " %04d %02d %02d %*[-Tt] %02d %02d %02d %c",
&year, &month, &day, &hour, &min, &sec, &ch);
if (n >= 6) {
if (n == 6)
isdst = -1;
else
if (ch == '+')
isdst = +1; /* DST */
else
if (ch == '-')
isdst = 0; /* Not DST */
else
isdst = -1;
t = epoch(&tm, year, month, day, hour, min, sec, isdst);
if (t != (time_t)-1) {
show(t, &tm);
continue;
}
}
fflush(stdout);
fprintf(stderr, "%s: Cannot parse parameter.\n", argv[arg]);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
使用例如
编译它gcc -Wall -O2 mktime-example.c -o mktime-example
运行 不带参数看命令行用法。 运行
./mktime-example :Europe/Helsinki 20161030-035959+ 20161030-030000- 20161030-030000+ 20161030-035959- 20161030-040000-
检查 2016 年夏令时在芬兰赫尔辛基结束时的 Unix 时间戳。该命令将输出
(time_t)1477789199 = 2016-10-30 03:59:59, DST in effect, EET timezone
(time_t)1477789200 = 2016-10-30 03:00:00, DST not in effect, EET timezone
(time_t)1477785600 = 2016-10-30 03:00:00, DST in effect, EET timezone
(time_t)1477792799 = 2016-10-30 03:59:59, DST not in effect, EET timezone
(time_t)1477792800 = 2016-10-30 04:00:00, DST not in effect, EET timezone
无论在 运行 时这个夏令时是否在某个时区生效,输出都是相同的!
当用 .tm_isdst = 0
或 .tm_isdst = 1
调用 mktime()
时,mktime()
改变了它,它也改变了指定的时间(按夏令时)。当.tm_isdst = -1
时,表示调用者不知道是否应用夏令时,库会发现;但是如果同时存在有效的标准时间和 DST 时间,C 库将选择一个(您应该假设它是随机选择的)。上面的 epoch()
函数会在必要时对此进行更正,如果用户对 DST 不正确,则取消调整时间。
Unix/linux 系统只处理 UTC,它们使用 time_t
数据(从 00:00h 1970 年 1 月 1 日到现在的秒数)作为内部时间.仅在向用户显示信息时才转换为本地时间(由于异常、夏季-冬季的变化等而导致复杂性),因此仅在转换为本地时间时才完成。如前所述,在 unix 系统中没有安排任何事情的安排或准备。
从 zdump(1)
您可以获得每个时区所需的所有信息,并使用它构建一个 crontab 以在进行切换时通知您。它查询本地时区数据库并提取有关从冬季到夏季或相反的切换(包括历史)的所有信息。
$ zdump -v Europe/Madrid
Europe/Madrid Fri Dec 13 20:45:52 1901 UTC = Fri Dec 13 20:45:52 1901 WET isdst=0 gmtoff=0
Europe/Madrid Sat Dec 14 20:45:52 1901 UTC = Sat Dec 14 20:45:52 1901 WET isdst=0 gmtoff=0
Europe/Madrid Sat May 5 22:59:59 1917 UTC = Sat May 5 22:59:59 1917 WET isdst=0 gmtoff=0
Europe/Madrid Sat May 5 23:00:00 1917 UTC = Sun May 6 00:00:00 1917 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 6 22:59:59 1917 UTC = Sat Oct 6 23:59:59 1917 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 6 23:00:00 1917 UTC = Sat Oct 6 23:00:00 1917 WET isdst=0 gmtoff=0
Europe/Madrid Mon Apr 15 22:59:59 1918 UTC = Mon Apr 15 22:59:59 1918 WET isdst=0 gmtoff=0
Europe/Madrid Mon Apr 15 23:00:00 1918 UTC = Tue Apr 16 00:00:00 1918 WEST isdst=1 gmtoff=3600
Europe/Madrid Sun Oct 6 22:59:59 1918 UTC = Sun Oct 6 23:59:59 1918 WEST isdst=1 gmtoff=3600
Europe/Madrid Sun Oct 6 23:00:00 1918 UTC = Sun Oct 6 23:00:00 1918 WET isdst=0 gmtoff=0
Europe/Madrid Sat Apr 5 22:59:59 1919 UTC = Sat Apr 5 22:59:59 1919 WET isdst=0 gmtoff=0
Europe/Madrid Sat Apr 5 23:00:00 1919 UTC = Sun Apr 6 00:00:00 1919 WEST isdst=1 gmtoff=3600
Europe/Madrid Mon Oct 6 22:59:59 1919 UTC = Mon Oct 6 23:59:59 1919 WEST isdst=1 gmtoff=3600
Europe/Madrid Mon Oct 6 23:00:00 1919 UTC = Mon Oct 6 23:00:00 1919 WET isdst=0 gmtoff=0
Europe/Madrid Wed Apr 16 22:59:59 1924 UTC = Wed Apr 16 22:59:59 1924 WET isdst=0 gmtoff=0
Europe/Madrid Wed Apr 16 23:00:00 1924 UTC = Thu Apr 17 00:00:00 1924 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 4 22:59:59 1924 UTC = Sat Oct 4 23:59:59 1924 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 4 23:00:00 1924 UTC = Sat Oct 4 23:00:00 1924 WET isdst=0 gmtoff=0
Europe/Madrid Sat Apr 17 22:59:59 1926 UTC = Sat Apr 17 22:59:59 1926 WET isdst=0 gmtoff=0
Europe/Madrid Sat Apr 17 23:00:00 1926 UTC = Sun Apr 18 00:00:00 1926 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 2 22:59:59 1926 UTC = Sat Oct 2 23:59:59 1926 WEST isdst=1 gmtoff=3600
Europe/Madrid Sat Oct 2 23:00:00 1926 UTC = Sat Oct 2 23:00:00 1926 WET isdst=0 gmtoff=0
Europe/Madrid Sat Apr 9 22:59:59 1927 UTC = Sat Apr 9 22:59:59 1927 WET isdst=0 gmtoff=0
...
顺便说一句,如果您想收到即将发生的本地时间更改的通知,您可以使用以前的信息来构建一个包含所有信息的 crontab 文件,或者简单地构建一个包含适用规则的 crontab 文件在你的地方。例如,如果我想在西班牙的交换机更改前一天收到通知(它在 march/october 的最后一个星期日 02/03h 更改),您可以在 crontab 文件中添加一些规则:
0 0 24-30 3,10 5 echo Time daylight savings change scheduled for tomorrow | mail $USER@your.domain.com
并且会在每个星期六 (5) 向您发送一封邮件,恰好是每年 3 月 24 日至 30 日和每年 10 月(3,10 部分)的那一周 00:00h (当地时间)。我相信您将能够根据您所在的地区或提前时间调整此示例(因此,在时间更改发生的前一天)。