I have CODE as below to calculate offset, Here I executed below code on EST timezone machine whose offset is -18000 seconds i.e. UTC-5.00
Please note I can't use localtime()
due to some limitations which is very long story to mention here.
So I used below logic to do minus of GMT epoch from localtime epoch as below and it returned perfectly the offset.
Now what I want here is suppose case of DST(Day light Saving), where offset will be -14400 seconds i.e. UTC-4.00. Due to 1 adjustment of DST(Day light Saving) for EST time zone.
So will my code mentioned below work? in case system is having DST(Day light Saving). I can not test live right now, as DST(Day light Saving) is not active on my machine.
Its planned as below:
/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
So wanted to know, when DST is active, i.e. say between 14 March 2021 to 7 Nov 2021, will my below code return offset of -14400.
Does time()
function consider epoch time after DST adjustment.
#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
CodePudding user response:
By making this small modification to your program:
gtm = gmtime (&rawtime);
gtm->tm_isdst = -1;
g_epoch = mktime(gtm);
it should work when DST is in effect. Setting tm_isdst
to -1 forces mktime
to decide for itself whether DST is in effect.
You can also skip the manipulations involving ltm
and l_epoch
and the call to localtime
. (I thought the whole point of the exercise was to avoid calling localtime
?) You can compute your offset just fine with
offset = rawtime - g_epoch;
But in the end this is still a pretty dreadful hack, and as @ikegami has pointed out, it won't work properly in the vicinity of DST transitions. For example, the time_t
value 1636261200 properly corresponds to 1am EDT on November 7, 2021, but this code will wrongly determine that it has already fallen back to EST. This problem will be worse (will apply for a larger number of hours) the farther your local time zone is from GMT. There's probably a way around this, but it won't be particularly pretty.
CodePudding user response:
I don't think it will work at all, but I'm not sure. Best case, it will give incorrect results near switches to/from DST.
If you can't trust the system time zone database, you can always use your own copy of the tz database. Steve Summit points out the database even comes with a reference implementation of all the time zone-related functions such as localtime
, so there would be no need to parse the database yourself.
Note: The database is frequently updated, so you will need some kind of process to update your application frequently if you need to work with arbitrary time zones.
Does time() function consider epoch time after DST adjustment.
time
returns the number of seconds since the start of 1970 UTC.
As such, the result doesn't change where you are in the world.
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).
Doesn't mktime
take it's information about local time from the same place localtime
does? So why would mktime
work on a system where localtime
doesn't?
But let's say mktime
does work.
Even if we assume that mktime
works correctly on a system where localtime
doesn't, I don't think it will work. I think gtm.tm_isdst
will always be zero (since gmtime
uses UTC which doesn't have DST), and I think that will cause the following mktime
to return something different than desired. But this can be addressed by setting gtm .tm_isdst
to -1
.
So let's say mktime
does return what we expect.
Even if mktime
returns what we expect, the approach is flawed. It will give the wrong offsets near switches 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
And there's the problem. 2021-03-13T03:30:00
(local) is after the change to DST, but we're only 2022-03-12T22:30:00
(local), which is still before the change to DST. This is going to give us the wrong offset.