无法在 C 中获得正确的本地时间
Cant get right localtime in C
我试图在 C 中获取当前本地时间,比方说意大利,我尝试了下面的代码,但它 return 比实际时间早三个小时。
例如,如果在 17:34 处执行,它将 return 14:34,我做错了什么?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
setenv("TZ", "UTC+1", 1); // Italy is UTC+1
tzset();
time_t sec = 1634224877; // Just for test
struct tm * end = localtime(&sec);
// Check for daylight save
if(end->tm_isdst == 1)
{
end->tm_hour += 1;
}
printf("Daylight save time?: %d\n", end->tm_isdst);
printf("Time is says: %.2d/%.2d/%d - %.2d:%.2d:%.2d\n", end->tm_mday, end->tm_mon + 1, end->tm_year + 1900,
end->tm_hour, end->tm_min, end->tm_sec);
}
谢谢
tl;dr 如果您想要某个位置的时间,您必须将 TZ
设置为某个位置。
1634224877 是 2021-10-14 15:21:17 UTC。 setenv
takes POSIX time zones which don't work like you think。 UTC+1 表示 UTC 的一个小时头。即14:21:17。如果你想要“UTC+1”,你实际上要求 UTC-1
,比 UTC 晚一小时。
但不要要求 UTC-1
。
setenv("TZ", "UTC+1", 1); // Italy is UTC+1
该评论不正确。意大利不是 UTC+1。意大利有时是UTC+1,有时是UTC+2。为了了解夏令时(和其他古怪的时区问题),TZ 需要知道您的位置。
将 TZ 设置为离您最近的城市,如 Europe/Rome
。现在localtime
可以判断是不是夏令时了,不需要更正了。
int main()
{
setenv("TZ", "Europe/Rome", 1);
tzset();
time_t sec = 1634224877; // Just for test
struct tm * end = localtime(&sec);
printf("Daylight savings time?: %d\n", end->tm_isdst);
printf("Time is says: %.2d/%.2d/%d - %.2d:%.2d:%.2d\n", end->tm_mday, end->tm_mon + 1, end->tm_year + 1900,
end->tm_hour, end->tm_min, end->tm_sec);
}
Daylight savings time?: 1
Time is says: 14/10/2021 - 17:21:17
管理时区的系统叫做tzdata。它是一个包含位置、时区信息、夏令时开关和许多其他古怪时区信息的数据库。它让您的计算机知道罗马通常是 UTC+1,但有时应该是 UTC+2。
A list of all tzdata locations can be had on Wikipedia,但这些不一定与您机器上安装的 tzdata 匹配。
TZ
环境变量值 FOO+1
(我将其从 UTC+1
更改为避免混淆)被解释为指定为“FOO”的标准时区,没有备用(夏令时) )区。 +1
(+
是可选的)表示需要将当地时间添加 1 小时以将其转换为协调世界时 (UTC)。要指定备用(夏令时)时区,请将其添加到标准时间偏移量之后,例如FOO+1BAR0
。备用区域后的偏移量可以省略,在这种情况下它默认为比标准偏移量小一,因此 FOO+1BAR0
可以缩短为 FOO1BAR
。这意味着当标准时间生效时,当地时间将比 UTC 晚 1 小时,而当备用(夏令时)时间生效时,本地时间将是 UTC。可选地,偏移量可以包括分钟或分钟和秒,例如FOO+01:00BAR+00:00:00
.
意大利在标准时间有效时(例如冬季)使用中欧时间(CET,对应UTC+1),而在交替(夏令时)时使用中欧夏令时(CEST,对应UTC+1)节省)时间有效(例如在夏季)。这可以通过 TZ
环境变量值 CET-1CEST-2
或 CET-1CEST
来表示。请注意,TZ
环境变量中使用的偏移量与通常的约定相反。
当 TZ
具有前面提到的值之一和备用时间(例如 CET-1CEST
)时,由系统库来使用一些任意的(并且对于大多数情况通常是不正确的)世界)规则来确定标准时间和备用时间之间转换的日期和时间。每年恰好两次转换的日期和时间的简单规则可以在 TZ
变量中的备用区域名称和偏移量之后进行编码,以逗号分隔。转换日期可以指定为 Mm.n.d,意思是 d第 n 周(从 1 开始计算)的第 天(0 = 星期日,1 = 星期一,...,6 = 星期六)第 43=]m 个月(1 = 一月,...,12 = 十二月)。 n = 5 被解释为一个月中的最后 d 天 m。过渡日期也可以指定为 Jn,其中 n 是一年中的第几天,不包括 2 月 29 日(因此 3 月 1 日始终是一天60). (可选)过渡时间可以指定为 /time,其中 time 指定过渡日期的当前本地时间,在该时间过渡到其他时间,默认为 02:00:00。 time值可以像时区偏移量一样缩写,所以/2和/02:00:00一样,但不允许有前导加号或减号(由当前标准)。
意大利目前按照欧盟时区转换规则运行(该规则的废除目前已推迟),其中转换发生在 01:00 UTC,当地时间在 3 月的最后一个星期日提前 1 小时(M3.5.0
) 并在 10 月的最后一个星期日 (M10.5.0
) 撤退 1 小时。对于意大利,当地的过渡时间是三月02:00:00(前进到03:00:00)和十月03:00:00(退到02:00:00),所以规则是M3.5.0/2
和 M10.5.3
。 (M3.5.0/2
可以缩短为 M3.5.0
,因为它使用默认的过渡时间。)
以下经过修改的代码可以显示意大利的时间,至少在当前的欧盟时区规则被废除之前:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1); // Italy rules!
tzset();
time_t sec;
#if 0
sec = 1634224877; // Just for test
#else
sec = time(NULL); // For current time
#endif
struct tm * end = localtime(&sec);
printf("Daylight save time?: %d\n", end->tm_isdst);
printf("Time is says: %.2d/%.2d/%d - %.2d:%.2d:%.2d\n",
end->tm_mday, end->tm_mon + 1, end->tm_year + 1900,
end->tm_hour, end->tm_min, end->tm_sec);
}
我试图在 C 中获取当前本地时间,比方说意大利,我尝试了下面的代码,但它 return 比实际时间早三个小时。 例如,如果在 17:34 处执行,它将 return 14:34,我做错了什么?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
setenv("TZ", "UTC+1", 1); // Italy is UTC+1
tzset();
time_t sec = 1634224877; // Just for test
struct tm * end = localtime(&sec);
// Check for daylight save
if(end->tm_isdst == 1)
{
end->tm_hour += 1;
}
printf("Daylight save time?: %d\n", end->tm_isdst);
printf("Time is says: %.2d/%.2d/%d - %.2d:%.2d:%.2d\n", end->tm_mday, end->tm_mon + 1, end->tm_year + 1900,
end->tm_hour, end->tm_min, end->tm_sec);
}
谢谢
tl;dr 如果您想要某个位置的时间,您必须将 TZ
设置为某个位置。
1634224877 是 2021-10-14 15:21:17 UTC。 setenv
takes POSIX time zones which don't work like you think。 UTC+1 表示 UTC 的一个小时头。即14:21:17。如果你想要“UTC+1”,你实际上要求 UTC-1
,比 UTC 晚一小时。
但不要要求 UTC-1
。
setenv("TZ", "UTC+1", 1); // Italy is UTC+1
该评论不正确。意大利不是 UTC+1。意大利有时是UTC+1,有时是UTC+2。为了了解夏令时(和其他古怪的时区问题),TZ 需要知道您的位置。
将 TZ 设置为离您最近的城市,如 Europe/Rome
。现在localtime
可以判断是不是夏令时了,不需要更正了。
int main()
{
setenv("TZ", "Europe/Rome", 1);
tzset();
time_t sec = 1634224877; // Just for test
struct tm * end = localtime(&sec);
printf("Daylight savings time?: %d\n", end->tm_isdst);
printf("Time is says: %.2d/%.2d/%d - %.2d:%.2d:%.2d\n", end->tm_mday, end->tm_mon + 1, end->tm_year + 1900,
end->tm_hour, end->tm_min, end->tm_sec);
}
Daylight savings time?: 1
Time is says: 14/10/2021 - 17:21:17
管理时区的系统叫做tzdata。它是一个包含位置、时区信息、夏令时开关和许多其他古怪时区信息的数据库。它让您的计算机知道罗马通常是 UTC+1,但有时应该是 UTC+2。
A list of all tzdata locations can be had on Wikipedia,但这些不一定与您机器上安装的 tzdata 匹配。
TZ
环境变量值 FOO+1
(我将其从 UTC+1
更改为避免混淆)被解释为指定为“FOO”的标准时区,没有备用(夏令时) )区。 +1
(+
是可选的)表示需要将当地时间添加 1 小时以将其转换为协调世界时 (UTC)。要指定备用(夏令时)时区,请将其添加到标准时间偏移量之后,例如FOO+1BAR0
。备用区域后的偏移量可以省略,在这种情况下它默认为比标准偏移量小一,因此 FOO+1BAR0
可以缩短为 FOO1BAR
。这意味着当标准时间生效时,当地时间将比 UTC 晚 1 小时,而当备用(夏令时)时间生效时,本地时间将是 UTC。可选地,偏移量可以包括分钟或分钟和秒,例如FOO+01:00BAR+00:00:00
.
意大利在标准时间有效时(例如冬季)使用中欧时间(CET,对应UTC+1),而在交替(夏令时)时使用中欧夏令时(CEST,对应UTC+1)节省)时间有效(例如在夏季)。这可以通过 TZ
环境变量值 CET-1CEST-2
或 CET-1CEST
来表示。请注意,TZ
环境变量中使用的偏移量与通常的约定相反。
当 TZ
具有前面提到的值之一和备用时间(例如 CET-1CEST
)时,由系统库来使用一些任意的(并且对于大多数情况通常是不正确的)世界)规则来确定标准时间和备用时间之间转换的日期和时间。每年恰好两次转换的日期和时间的简单规则可以在 TZ
变量中的备用区域名称和偏移量之后进行编码,以逗号分隔。转换日期可以指定为 Mm.n.d,意思是 d第 n 周(从 1 开始计算)的第 天(0 = 星期日,1 = 星期一,...,6 = 星期六)第 43=]m 个月(1 = 一月,...,12 = 十二月)。 n = 5 被解释为一个月中的最后 d 天 m。过渡日期也可以指定为 Jn,其中 n 是一年中的第几天,不包括 2 月 29 日(因此 3 月 1 日始终是一天60). (可选)过渡时间可以指定为 /time,其中 time 指定过渡日期的当前本地时间,在该时间过渡到其他时间,默认为 02:00:00。 time值可以像时区偏移量一样缩写,所以/2和/02:00:00一样,但不允许有前导加号或减号(由当前标准)。
意大利目前按照欧盟时区转换规则运行(该规则的废除目前已推迟),其中转换发生在 01:00 UTC,当地时间在 3 月的最后一个星期日提前 1 小时(M3.5.0
) 并在 10 月的最后一个星期日 (M10.5.0
) 撤退 1 小时。对于意大利,当地的过渡时间是三月02:00:00(前进到03:00:00)和十月03:00:00(退到02:00:00),所以规则是M3.5.0/2
和 M10.5.3
。 (M3.5.0/2
可以缩短为 M3.5.0
,因为它使用默认的过渡时间。)
以下经过修改的代码可以显示意大利的时间,至少在当前的欧盟时区规则被废除之前:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1); // Italy rules!
tzset();
time_t sec;
#if 0
sec = 1634224877; // Just for test
#else
sec = time(NULL); // For current time
#endif
struct tm * end = localtime(&sec);
printf("Daylight save time?: %d\n", end->tm_isdst);
printf("Time is says: %.2d/%.2d/%d - %.2d:%.2d:%.2d\n",
end->tm_mday, end->tm_mon + 1, end->tm_year + 1900,
end->tm_hour, end->tm_min, end->tm_sec);
}