std::mktime and timezone info
mktime assumes that the date value is in the local time zone. Thus you can change the timezone environment variable beforehand (setenv) and get the UTC timezone.
Windows tzset
Can also try looking at various home-made utc-mktimes, mktime-utcs, etc.
how to use mktime to respect timezone
You problem is almost certainly that the tm_isdst
flag of your tm
struct defaulted to 0 which caused it to assume no DST even in summer (which your date is). Then when you converted back to localtime it DID add the DST offset, causing the difference you note.
The simplest and often correct solution is to set the tm_isdst
member to -1 to let mktime
figure out if the date in question should have a DST offset applied.
Note that whether DST is in effect is orthogonal to which timezone you're using. Both need to be set in the correct way for the results to come out correctly.
Also do consider using localtime_r
instead of localtime
if there's any chance of your application being threaded.
Easy way to convert a struct tm (expressed in UTC) to time_t type
Use timegm() instead of mktime()
Why does mktime() need to know about daylight saving time?
Whether DST is in effect changes what the epoch time will be because mktime
uses the current time zone to determine the time.
For example, if I populate tm
with 1/1/70 00:00:00 as follows:
tm.tm_sec = 0;
tm.tm_min = 0;
tm.tm_hour = 0;
tm.tm_mday = 1;
tm.tm_mon = 0;
tm.tm_year = 70;
tm.tm_isdst = 0;
I get a value of 18000 for tv
because my timezone is GMT-5 (18000 = 3600 * 5). If I change the value of tm_isdst
to 1, then tv
will be set to 14400 (3600 * 4).
Setting tm_isdst
to -1 will look at the local timezone database to see if DST is in effect for the given date/time.
mktime and tm_isdst
I believe the original reason for that is some timezones do not have daylight savings time. Since mktime is not async-safe nor is it re-entrant allows the implementation to store the current value of daylight savings in the POSIX extern char tzname[2], indexed by daylight [0 or 1]. This means tzname[0]="[std TZ name]" and tzname="[daylight TZ name, e.g. EDT]"
See your tzset() man page for more information on this. Standards conforming mktime() is required to behave as though it called tzset() anyway. This kind of obviates the use of tm_isdst, IMO.
Bottom line: your particular implementation and timezone(s) would dictate whether you would use -1, 0, or 1 for tm_isdst. There is no one default correct way for all implementations.
Incorrect time calculation with mktime to get UTC+8
You could use localtime
after changing the TZ
environment variable to your desired timezone:
#include <iostream>
#include <stdlib.h>
#include <time.h>
int main(){
_putenv_s( "TZ", "GMT-08:00" );
time_t mytime = time( NULL );
struct tm* mytm = localtime( &mytime );
std::cout << "Current local time and date: " << asctime(mytm);
return 0;
}
The object mytime
will receive as a result of the function time()
the amount of seconds since 00:00 hours, Jan 1, 1970 UTC
, which is the current Unix timestamp. localtime()
will use the value pointed by mytime
to fill a tm
structure with the values that represent the corresponding time, expressed for the local timezone.
By default, the timezone used by localtime()
is generally the one used in your computer. However, you can change it with the function _putenv_s()
, in which I manipulated the TZ
variable and added a new definition to it GMT-08:00
which is the timezone for Hong Kong.
In POSIX systems, a user can specify the time zone by means of the TZ
environment variable.
Note that however a more standard way of manipulating TZ
variable is by using the function int setenv (const char *name, const char *value, int replace)
but it wasn't defined in this sample, so I used an alternative.
You can read more about TZ environment variable here
mktime shows inconsistent output
I think the problem is here:
The mktime() function shall convert the broken-down time, expressed as local time, in the structure pointed to by timeptr, into a time since the Epoch value...
Note the words local time
. The C standard has them too in the description of mktime()
:
The mktime function converts the broken-down time, expressed as local time, in the
structure pointed to by timeptr into a calendar time value with the same encoding as
that of the values returned by the time function.
gmtime()
, on the other hand, produces time in GMT/UTC and not in your time zone:
The gmtime() function shall convert the time in seconds since the Epoch pointed to by timer into a broken-down time, expressed as Coordinated Universal Time (UTC).
EDIT: If you just want 19:00 of the previous GMT/UTC day, you can do this:
#include <stdio.h>
#include <time.h>
int main(void)
{
time_t currentTime;
struct tm *brokenDownTime;
time(¤tTime);
// get the time in GMT as we are in PDT
brokenDownTime = gmtime(¤tTime);
printf("Current Time (GMT): %2d:%02d\n"
" seconds since Epoch: %ld\n",
brokenDownTime->tm_hour,
brokenDownTime->tm_min,
(long)currentTime);
// "Unwind" time to 0:00:00 (assuming time_t is an integer):
currentTime /= 24 * (time_t)3600;
currentTime *= 24 * (time_t)3600;
brokenDownTime = gmtime(¤tTime);
printf("Time at the beginning of the current GMT day: %2d:%02d\n"
" seconds since Epoch: %ld\n",
brokenDownTime->tm_hour,
brokenDownTime->tm_min,
(long)currentTime);
// Add 19 hours:
currentTime += 19 * (time_t)3600;
brokenDownTime = gmtime(¤tTime);
printf("Time at 19:00:00 of the current GMT day: %2d:%02d\n"
" seconds since Epoch: %ld\n",
brokenDownTime->tm_hour,
brokenDownTime->tm_min,
(long)currentTime);
// Subtract 1 day:
currentTime -= 24 * (time_t)3600;
brokenDownTime = gmtime(¤tTime);
printf("Time at 19:00:00 of the previous GMT day: %2d:%02d\n"
" seconds since Epoch: %ld\n",
brokenDownTime->tm_hour,
brokenDownTime->tm_min,
(long)currentTime);
return 0;
}
Output:
Current Time (GMT): 13:23
seconds since Epoch: 1341235429
Time at the beginning of the current GMT day: 0:00
seconds since Epoch: 1341187200
Time at 19:00:00 of the current GMT day: 19:00
seconds since Epoch: 1341255600
Time at 19:00:00 of the previous GMT day: 19:00
seconds since Epoch: 1341169200
Related Topics
What Destructors Are Run When the Constructor Throws an Exception
Segmentation Fault at Glgenvertexarrays( 1, &Vao );
What Does It Mean for a C++ Function to Be Inline
What's a Good Hash Function for English Words
How to Change the Background Color of a Button Winapi C++
Compiling External C++ Library for Use with iOS Project
How Does Openmp Handle Nested Loops
How to Generate Thread-Safe Uniform Random Numbers
What Is Return Type of Assignment Operator
Converting Float Values from Big Endian to Little Endian
Why Does Visual Studio 2013 Error on C4996
Skipping Incompatible Libraries at Compile
How to Test a String for Letters Only
Assignment Operator Inheritance
Custom Manipulator for C++ iOStream
Accessing Protected Members of Superclass in C++ with Templates