std::mktime and timezone info

后端 未结 12 454
忘了有多久
忘了有多久 2020-11-30 10:56

I\'m trying to convert a time info I reveive as a UTC string to a timestamp using std::mktime in C++. My problem is that in / &

相关标签:
12条回答
  • 2020-11-30 11:23

    The tm structure used by mktime has a timezone field.
    What happens if you put 'UTC' into the timzone field?

    http://www.delorie.com/gnu/docs/glibc/libc_435.html

    0 讨论(0)
  • 2020-11-30 11:24

    If you are trying to do this in a multithreaded program and don't want to deal with locking and unlocking mutexes (if you use the environment variable method you'd have to), there is a function called timegm that does this. It isn't portable, so here is the source: http://trac.rtmpd.com/browser/trunk/sources/common/src/platform/windows/timegm.cpp

    int is_leap(unsigned y) {
        y += 1900;
        return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
    }
    
    time_t timegm (struct tm *tm)
    {
        static const unsigned ndays[2][12] = {
            {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
            {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
        };
        time_t res = 0;
        int i;
    
        for (i = 70; i < tm->tm_year; ++i)
            res += is_leap(i) ? 366 : 365;
    
        for (i = 0; i < tm->tm_mon; ++i)
            res += ndays[is_leap(tm->tm_year)][i];
        res += tm->tm_mday - 1;
        res *= 24;
        res += tm->tm_hour;
        res *= 60;
        res += tm->tm_min;
        res *= 60;
        res += tm->tm_sec;
        return res;
    }
    
    0 讨论(0)
  • 2020-11-30 11:26

    I have this same problem last day and by searching the doc "man mktime":

    The functions mktime() and timegm() convert the broken-out time (in the structure pointed to by *timeptr) into a time value with the same encoding as that of the values returned by the time(3) function (that is, seconds from the Epoch, UTC). The mktime() function interprets the input structure according to the current timezone setting (see tzset(3)). The timegm() function interprets the input structure as representing Universal Coordinated Time (UTC).

    Short:

    You should use timegm, instead of using mktime.

    Regards,

    Pai

    0 讨论(0)
  • 2020-11-30 11:27
    timestamp = mktime(&tm) - _timezone;
    

    or platform independent way:

     timestamp = mktime(&tm) - timezone;
    

    If you look in the source of mktime() on line 00117, the time is converted to local time:

    seconds += _timezone;
    
    0 讨论(0)
  • 2020-11-30 11:27

    A solution with little coding and portable, as it only uses mktime:

    The parsed time has to be in struct tm tm. if you use c++11, you might want to use std::get_time for parsing. It parses most time strings!

    Before calling mktime() be sure tm.tm_isdst is set to zero, then mktime does not adjust for daylight savings,

    // find the time_t of epoch, it is 0 on UTC, but timezone elsewhere
    // If you newer change timezone while program is running, you only need to do this once
    struct std::tm epoch;
    epoch.tm_isdst = 0;
    epoch.tm_sec = epoch.tm_min = epoch.tm_hour = epoch.tm_mon = 0;
    epoch.tm_mday = 1;
    epoch.tm_year = 70;
    time_t offset = mktime(&epoch);
    
    // Now we are ready to convert tm to time_t in UTC.
    // as mktime adds timezone, subtracting offset(=timezone) gives us the right result
    result = mktime(&tm)-offset
    
    0 讨论(0)
  • 2020-11-30 11:29

    I've just been trying to figure out how to do this. I'm not convinced this solution is perfect (it depends on how accurately the runtime library calculates Daylight Savings), but it's working pretty well for my problem.

    Initially I thought I could just calculate the difference between gmtime and localtime, and add that on to my converted timestamp, but that doesn't work because the difference will change according to the time of year that the code is run, and if your source time is in the other half of the year you'll be out by an hour.

    So, the trick is to get the runtime library to calculate the difference between UTC and local time for the time you're trying to convert.

    So what I'm doing is calculating my input time and then modifying that calculated time by plugging it back into localtime and gmtime and adding the difference of those two functions:

    std::tm     tm;
    
    // Fill out tm with your input time.
    
    std::time_t basetime = std::mktime( &tm );
    std::time_t diff;
    
    tm = *std::localtime( &basetime );
    tm.tm_isdst = -1;
    diff = std::mktime( &tm );
    
    tm = *std::gmtime( &basetime );
    tm.tm_isdst = -1;
    diff -= std::mktime( &tm );
    
    std::time_t finaltime = basetime + diff;
    

    It's a bit of a roundabout way to calculate this, but I couldn't find any other way without resorting to helper libraries or writing my own conversion function.

    0 讨论(0)
提交回复
热议问题