不使用本地时间的夏令时(DST)偏移计算
offset calculation for day light saving(DST) without using localtime
我有如下代码来计算偏移量,
在这里,我在 EST 时区机器上执行了以下代码,其偏移量为 -18000 秒,即 UTC-5.00
请注意,由于某些限制,我无法使用 localtime()
,这里说来话长。
所以我使用下面的逻辑从本地时间纪元减去 GMT 纪元,如下所示,它 return 完美地调整了偏移量。
现在我想要的是假设 DST(夏令时)的情况,其中偏移量将为 -14400 秒,即 UTC-4.00。由于 EST 时区的 DST(夏令时)+1 调整。
下面提到的我的代码可以工作吗?如果系统有 DST(夏令时)。
我现在无法实时测试,因为 DST(夏令时)在我的机器上未激活。
计划如下:
/etc/localtime Sun Mar 14 06:59:59 2021 UT = Sun Mar 14 01:59:59 2021 EST isdst=0 gmtoff=-18000
/etc/localtime Sun Mar 14 07:00:00 2021 UT = Sun Mar 14 03:00:00 2021 EDT isdst=1 gmtoff=-14400
/etc/localtime Sun Nov 7 05:59:59 2021 UT = Sun Nov 7 01:59:59 2021 EDT isdst=1 gmtoff=-14400
/etc/localtime Sun Nov 7 06:00:00 2021 UT = Sun Nov 7 01:00:00 2021 EST isdst=0 gmtoff=-18000
所以想知道,当 DST 处于活动状态时,即在 2021 年 3 月 14 日至 2021 年 11 月 7 日之间,我的以下代码 return 是否会偏移 -14400。
time()
函数是否考虑夏令时调整后的纪元时间。
#include <stdio.h>
#include <time.h>
int main ()
{
time_t rawtime, g_epoch, l_epoch;
struct tm * gtm, *ltm;
signed long int offset;
//Get current epoch time
time ( &rawtime );
// convert rawtime epoch to struct tm in GMT
gtm = gmtime ( &rawtime );
// again convert back GMT struct tm to epoch
g_epoch = mktime(gtm);
//convert rawtime epoch to "struct tm* ltm" in local time zone
ltm= localtime(&rawtime);
// again convert back local time zone "struct tm* ltm" to epoch l_epoch
l_epoch= mktime(ltm);
//calculate offset
offset= l_epoch - g_epoch;
printf("Rawtime: %u\n",rawtime);
printf("GMTepoch: %u\n",g_epoch);
printf("Local Epoch: %u\n",l_epoch);
printf("Offset: %ld",offset);
return 0;
}
O/p as below:
Rawtime: 1640176204
GMTepoch: 1640194204
Local Epoch: 1640176204
Offset: -18000
我认为它根本行不通,但我不确定。最好的情况是,它会在开关 to/from DST 附近给出不正确的结果。
如果您不信任系统时区数据库,您始终可以使用自己的 tz database 副本。 Steve Summit 指出数据库甚至附带了所有与时区相关的功能的参考实现,例如 localtime
,因此无需自己解析数据库。
注意:数据库经常更新,因此如果您需要使用任意时区,您将需要某种进程来频繁更新您的应用程序。
Does time() function consider epoch time after DST adjustment.
time
returns 自 1970 UTC 开始以来的秒数。
因此,结果不会改变您在世界上的位置。
Local time Time Zone Examples time()
------------------------- ------------------ ----------
2021-06-01T12:00:00Z Etc/UTC, E./Dublin 1622548800
2021-06-01T08:00:00-04:00 "EDT", A./New_York 1622548800
2021-06-01T07:00:00-05:00 "EST", A./Bogota 1622548800
2021-06-01T12:00:00Z Etc/UTC, E./Dublin 1622548800
2021-06-01T12:00:00-04:00 "EDT", A./New_York 1622563200
2021-06-01T12:00:00-05:00 "EST", A./Bogota 1622566800
So will my code mentioned below work? in case system is having DST(Day light Saving).
mktime
不是从同一个地方 localtime
获取有关本地时间的信息吗?那么为什么 mktime
可以在 localtime
不能的系统上工作呢?
但假设 mktime
确实有效。
即使我们假设 mktime
在 localtime
不能正常工作的系统上正常工作,我也不认为它会工作。我认为 gtm.tm_isdst
将始终为零(因为 gmtime
使用没有 DST 的 UTC),我认为这将导致以下 mktime
到 return 不同于想要的。但这可以通过将 gtm .tm_isdst
设置为 -1
.
来解决
那么假设 mktime
做了 return 我们期望的事情。
即使 mktime
return 符合我们的预期,该方法也存在缺陷。它会在开关 to/from DST 附近给出错误的偏移量。
// Current time zone: America/New_York
// Current local time: 2022-03-12T22:30:00-05:00
// Change to DST: In 3.5 hours.
// Get the current epoch time.
// This returns the same thing worldwide.
time(&rawtime); // rawtime = 1647142200
// Convert current epoch time to UTC.
gtm = gmtime(&rawtime); // gtm = 2021-03-13T03:30:00
gtm .tm_isdst = -1;
// Note that mktime expects a local time.
// But we're passing the current UTC time.
// So g_epoch is the epoch time for
// 2021-03-13T03:30:00 America/New_York
g_epoch = mktime(gtm); // rawtime = 1647156600
问题来了。 2021-03-13T03:30:00
(local)是夏令时之后的,而我们只是2022-03-12T22:30:00
(local),还是夏令时之前。这会给我们错误的偏移量。
通过对您的程序进行以下小修改:
gtm = gmtime (&rawtime);
gtm->tm_isdst = -1;
g_epoch = mktime(gtm);
它应该在 DST 生效时工作。将 tm_isdst
设置为 -1 会强制 mktime
自行决定 DST 是否生效。
您还可以跳过涉及 ltm
和 l_epoch
的操作以及对 localtime
的调用。 (我认为练习的重点是避免调用 localtime
?)您可以使用
计算偏移量
offset = rawtime - g_epoch;
但最后这仍然是一个非常可怕的 hack,正如@ikegami 指出的那样,它在 DST 转换附近无法正常工作。例如,time_t
值 1636261200 正确对应 2021 年 11 月 7 日凌晨 1 点 EDT,但此代码将错误地确定它已经回落到 EST。这个问题会更糟(将申请更多的小时数)你当地的时区离格林威治标准时间越远。可能有办法解决这个问题,但不会特别漂亮。
我有如下代码来计算偏移量, 在这里,我在 EST 时区机器上执行了以下代码,其偏移量为 -18000 秒,即 UTC-5.00
请注意,由于某些限制,我无法使用 localtime()
,这里说来话长。
所以我使用下面的逻辑从本地时间纪元减去 GMT 纪元,如下所示,它 return 完美地调整了偏移量。
现在我想要的是假设 DST(夏令时)的情况,其中偏移量将为 -14400 秒,即 UTC-4.00。由于 EST 时区的 DST(夏令时)+1 调整。
下面提到的我的代码可以工作吗?如果系统有 DST(夏令时)。 我现在无法实时测试,因为 DST(夏令时)在我的机器上未激活。
计划如下:
/etc/localtime Sun Mar 14 06:59:59 2021 UT = Sun Mar 14 01:59:59 2021 EST isdst=0 gmtoff=-18000
/etc/localtime Sun Mar 14 07:00:00 2021 UT = Sun Mar 14 03:00:00 2021 EDT isdst=1 gmtoff=-14400
/etc/localtime Sun Nov 7 05:59:59 2021 UT = Sun Nov 7 01:59:59 2021 EDT isdst=1 gmtoff=-14400
/etc/localtime Sun Nov 7 06:00:00 2021 UT = Sun Nov 7 01:00:00 2021 EST isdst=0 gmtoff=-18000
所以想知道,当 DST 处于活动状态时,即在 2021 年 3 月 14 日至 2021 年 11 月 7 日之间,我的以下代码 return 是否会偏移 -14400。
time()
函数是否考虑夏令时调整后的纪元时间。
#include <stdio.h>
#include <time.h>
int main ()
{
time_t rawtime, g_epoch, l_epoch;
struct tm * gtm, *ltm;
signed long int offset;
//Get current epoch time
time ( &rawtime );
// convert rawtime epoch to struct tm in GMT
gtm = gmtime ( &rawtime );
// again convert back GMT struct tm to epoch
g_epoch = mktime(gtm);
//convert rawtime epoch to "struct tm* ltm" in local time zone
ltm= localtime(&rawtime);
// again convert back local time zone "struct tm* ltm" to epoch l_epoch
l_epoch= mktime(ltm);
//calculate offset
offset= l_epoch - g_epoch;
printf("Rawtime: %u\n",rawtime);
printf("GMTepoch: %u\n",g_epoch);
printf("Local Epoch: %u\n",l_epoch);
printf("Offset: %ld",offset);
return 0;
}
O/p as below:
Rawtime: 1640176204
GMTepoch: 1640194204
Local Epoch: 1640176204
Offset: -18000
我认为它根本行不通,但我不确定。最好的情况是,它会在开关 to/from DST 附近给出不正确的结果。
如果您不信任系统时区数据库,您始终可以使用自己的 tz database 副本。 Steve Summit 指出数据库甚至附带了所有与时区相关的功能的参考实现,例如 localtime
,因此无需自己解析数据库。
注意:数据库经常更新,因此如果您需要使用任意时区,您将需要某种进程来频繁更新您的应用程序。
Does time() function consider epoch time after DST adjustment.
time
returns 自 1970 UTC 开始以来的秒数。
因此,结果不会改变您在世界上的位置。
Local time Time Zone Examples time()
------------------------- ------------------ ----------
2021-06-01T12:00:00Z Etc/UTC, E./Dublin 1622548800
2021-06-01T08:00:00-04:00 "EDT", A./New_York 1622548800
2021-06-01T07:00:00-05:00 "EST", A./Bogota 1622548800
2021-06-01T12:00:00Z Etc/UTC, E./Dublin 1622548800
2021-06-01T12:00:00-04:00 "EDT", A./New_York 1622563200
2021-06-01T12:00:00-05:00 "EST", A./Bogota 1622566800
So will my code mentioned below work? in case system is having DST(Day light Saving).
mktime
不是从同一个地方 localtime
获取有关本地时间的信息吗?那么为什么 mktime
可以在 localtime
不能的系统上工作呢?
但假设 mktime
确实有效。
即使我们假设 mktime
在 localtime
不能正常工作的系统上正常工作,我也不认为它会工作。我认为 gtm.tm_isdst
将始终为零(因为 gmtime
使用没有 DST 的 UTC),我认为这将导致以下 mktime
到 return 不同于想要的。但这可以通过将 gtm .tm_isdst
设置为 -1
.
那么假设 mktime
做了 return 我们期望的事情。
即使 mktime
return 符合我们的预期,该方法也存在缺陷。它会在开关 to/from DST 附近给出错误的偏移量。
// Current time zone: America/New_York
// Current local time: 2022-03-12T22:30:00-05:00
// Change to DST: In 3.5 hours.
// Get the current epoch time.
// This returns the same thing worldwide.
time(&rawtime); // rawtime = 1647142200
// Convert current epoch time to UTC.
gtm = gmtime(&rawtime); // gtm = 2021-03-13T03:30:00
gtm .tm_isdst = -1;
// Note that mktime expects a local time.
// But we're passing the current UTC time.
// So g_epoch is the epoch time for
// 2021-03-13T03:30:00 America/New_York
g_epoch = mktime(gtm); // rawtime = 1647156600
问题来了。 2021-03-13T03:30:00
(local)是夏令时之后的,而我们只是2022-03-12T22:30:00
(local),还是夏令时之前。这会给我们错误的偏移量。
通过对您的程序进行以下小修改:
gtm = gmtime (&rawtime);
gtm->tm_isdst = -1;
g_epoch = mktime(gtm);
它应该在 DST 生效时工作。将 tm_isdst
设置为 -1 会强制 mktime
自行决定 DST 是否生效。
您还可以跳过涉及 ltm
和 l_epoch
的操作以及对 localtime
的调用。 (我认为练习的重点是避免调用 localtime
?)您可以使用
offset = rawtime - g_epoch;
但最后这仍然是一个非常可怕的 hack,正如@ikegami 指出的那样,它在 DST 转换附近无法正常工作。例如,time_t
值 1636261200 正确对应 2021 年 11 月 7 日凌晨 1 点 EDT,但此代码将错误地确定它已经回落到 EST。这个问题会更糟(将申请更多的小时数)你当地的时区离格林威治标准时间越远。可能有办法解决这个问题,但不会特别漂亮。