2009-02-09 18 views
24

मैं सी ++ में std::mktime का उपयोग करके एक टाइमस्टैम्प के लिए एक यूटीसी स्ट्रिंग के रूप में एक समय की जानकारी को बदलने की कोशिश कर रहा हूं। मेरी समस्या यह है कि <ctime>/<time.h> में यूटीसी में कनवर्ट करने के लिए कोई फ़ंक्शन नहीं है; mktime केवल टाइमस्टैम्प को स्थानीय समय के रूप में वापस कर देगा।std :: mktime और timezone जानकारी

इसलिए मुझे टाइमज़ोन ऑफसेट को समझने और इसे ध्यान में रखना होगा, लेकिन मुझे एक मंच-स्वतंत्र तरीका नहीं मिल रहा है जिसमें पूरे कोड को boost::date_time पर पोर्टिंग शामिल नहीं है। क्या कोई आसान समाधान है जिसे मैंने अनदेखा किया है?

+1

"mktime केवल स्थानीय समय के रूप में टाइमस्टैम्प वापस आ जाएगी" - स्पष्ट रूप से, टाइमस्टैम्प एक UNIX टाइमस्टैम्प है (जिनके लिए टाइमज़ोन पूरी तरह से अप्रासंगिक हैं)। क्या होता है कि 'mktime' स्थानीय समय के रूप में _input_ को व्याख्या करता है। –

उत्तर

4

mktime मानता है कि दिनांक मान स्थानीय समय क्षेत्र में है। इस प्रकार आप टाइमज़ोन पर्यावरण परिवर्तक को पहले से (setenv) बदल सकते हैं और यूटीसी टाइमज़ोन प्राप्त कर सकते हैं।

Windows tzset

भी विभिन्न घर का बना utc-mktimes, mktime-utcs, etc.

+0

धन्यवाद! मैंने Google परिणाम में ऐसा कुछ देखा, लेकिन क्या यह विंडोज़ पर काम करता है? – VolkA

+0

लिंक काम किया, मुझे तुरंत एक mkgmtime() मिला। –

1

टीएम mktime द्वारा इस्तेमाल किया संरचना को देखकर एक समयक्षेत्र क्षेत्र है की कोशिश कर सकते हैं।
यदि आप 'यूटीसी' को टाइमज़ोन फ़ील्ड में डालते हैं तो क्या होता है?

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

+1

हां, यह लिनक्स के लिए आसान लग रहा है, लेकिन माइक्रोसॉफ्ट सहमत नहीं है - वे इसके बजाय _mkgmtime फ़ंक्शन प्रदान करते हैं ... – VolkA

+3

['mktime() 'manpage] के अनुसार (http://www.kernel.org/ डॉक्टर/मैन-पेज/ऑनलाइन/पेज/मैन 3/mktime.3.html), 'स्ट्रक्चर टीएम' में टाइमज़ोन फ़ील्ड नहीं है। आपके द्वारा संदर्भित ग्लिबैक दस्तावेज़ के अनुसार, "tm_gmtoff की तरह, यह फ़ील्ड बीएसडी और जीएनयू एक्सटेंशन है, और सख्त आईएसओ सी पर्यावरण में दिखाई नहीं दे रहा है।" –

18
timestamp = mktime(&tm) - _timezone; 

या मंच स्वतंत्र तरीके:

timestamp = mktime(&tm) - timezone; 

आप mktime() के स्रोत में देखें, तो:

http://www.raspberryginger.com/jbailey/minix/html/mktime_8c-source.html

लाइन 00,117 समय में परिवर्तित स्थानीय समय पर:

seconds += _timezone; 
+0

यह कुछ कार्यान्वयन है। कॉलिंग कोड में आपको '_timezone' कहां मिलेगा? –

+2

मैंने बस "टाइमज़ोन" ("_timezone" नहीं) का उपयोग किया। "टाइमज़ोन" को में परिभाषित किया गया है। – Serg

+0

आपके उत्तर की पहली पंक्ति –

6

mktime() टाइमज़ोन का पता लगाने के लिए tzname का उपयोग करता है। tzset() TZ enviroment चर से tzname चर प्रारंभ करता है। यदि टीजेड वैरिएबल वातावरण में दिखाई देता है लेकिन इसका मूल्य खाली है या इसका मूल्य सही ढंग से व्याख्या नहीं किया जा सकता है, तो यूटीसी का उपयोग किया जाता है।

एक पोर्टेबल (threadsafe नहीं) timegm manpage

#include <time.h> 
    #include <stdlib.h> 

    time_t 
    my_timegm(struct tm *tm) 
    { 
     time_t ret; 
     char *tz; 

     tz = getenv("TZ"); 
     setenv("TZ", "", 1); 
     tzset(); 
     ret = mktime(tm); 
     if (tz) 
      setenv("TZ", tz, 1); 
     else 
      unsetenv("TZ"); 
     tzset(); 
     return ret; 
    } 

एरिक एस रेमंड के अनुसार संस्करण अपने लेख Time, Clock, and Calendar Programming In C

time_t my_timegm(register struct tm * t) 
/* struct tm to seconds since Unix epoch */ 
{ 
    register long year; 
    register time_t result; 
#define MONTHSPERYEAR 12  /* months per calendar year */ 
    static const int cumdays[MONTHSPERYEAR] = 
     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; 

    /*@ +matchanyintegral @*/ 
    year = 1900 + t->tm_year + t->tm_mon/MONTHSPERYEAR; 
    result = (year - 1970) * 365 + cumdays[t->tm_mon % MONTHSPERYEAR]; 
    result += (year - 1968)/4; 
    result -= (year - 1900)/100; 
    result += (year - 1600)/400; 
    if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) && 
     (t->tm_mon % MONTHSPERYEAR) < 2) 
     result--; 
    result += t->tm_mday - 1; 
    result *= 24; 
    result += t->tm_hour; 
    result *= 60; 
    result += t->tm_min; 
    result *= 60; 
    result += t->tm_sec; 
    if (t->tm_isdst == 1) 
     result -= 3600; 
    /*@ -matchanyintegral @*/ 
    return (result); 
} 
+1

यह भी देखें [यह एक अन्य प्रश्न का उत्तर] (http://stackoverflow.com/a/6474100/60075) जो 'setenv ("TZ", "UTC", 1) का उपयोग करने के लिए कहता है;' इसके बजाय, यह होगा विंडोज पर काम –

+4

ध्यान दें कि यह समाधान ओएच भगवान है, इसलिए नहीं THREADSAFE। यदि आप इसे दो अलग-अलग धागे से कॉल करना चाहते हैं, तो आपको इसे म्यूटेक्स लॉक में लपेटना होगा। – Quuxplusone

+0

पर्यावरण चर के धागे सुरक्षित पर निर्भर कुछ भी करना संभव नहीं है :-( – Lothar

2

मैं इस एक ही समस्या है अंतिम दिन में और द्वारा प्रकाशित एक threadsafe संस्करण है डॉक्टर "मैन mktime" खोज रहे हैं:

फ़ंक्शंस mktime() और timegm() टूटा हुआ समय परिवर्तित करता है (एस में समय (3) फ़ंक्शन (यानी, एपोक, यूटीसी से सेकंड) द्वारा दिए गए मानों के के रूप में उसी एन्कोडिंग के साथ एक समय मूल्य में * timeptr द्वारा इंगित ट्रक्चर)। Mktime() फ़ंक्शन के अनुसार वर्तमान समय क्षेत्र सेटिंग (tzset (3) देखें) के अनुसार इनपुट संरचना का अर्थ देता है। टाइमगैम() फ़ंक्शन यूनिवर्सल कोऑर्डिनेटेड टाइम (यूटीसी) का प्रतिनिधित्व करने के रूप में इनपुट संरचना को व्याख्या करता है।

लघु:

इसके बजाय आप mktime का उपयोग कर के, timegm उपयोग करना चाहिए।

सादर,

पै

4

आप एक बहु कार्यक्रम में यह करने के लिए कोशिश कर रहे हैं और लॉक और अनलॉक करना mutexes (यदि आप वातावरण चर विधि का उपयोग आप होगा से निपटने के लिए नहीं करना चाहते हैं करने के लिए), टाइमगैम नामक एक फ़ंक्शन है जो यह करता है। यहां यह पोर्टेबल नहीं है, तो स्रोत है: 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

यह एक सीमा के अपवाद को ट्रिगर कर सकता है यदि 'tm_mon' लीप वर्ष पर 12 पर सेट किया गया है, तो अगले वर्ष जनवरी के लिए 'mktime' में एक आम अर्थशास्त्री (और यदि ऐसा नहीं होता है, तो परिणाम बहुत गलत है)। यह कई लूप और फ़ंक्शन कॉल (दिसंबर 2015 को 57) बनाता है, और यहां तक ​​कि अधिक महंगा मॉड्यूलो ऑपरेशंस (लगभग 100)। यह मानता है कि 'time_t' सेकंड में है, जो पत्थर में नक्काशीदार नहीं है। – fgrieu

2

उपयोग _mkgmtime, यह सब कुछ का ख्याल रखता है।

+1

और यह कहां उपलब्ध और दस्तावेज हो सकता है? –

3

यहां एक समायोज्य यूटीसी वर्ष की शुरुआत के बाद struct tm से सेकंड के समय में अस्थायी परिवर्तन के बिना कोड का एक सरल, परीक्षण किया गया, उम्मीदवार पोर्टेबल टुकड़ा है। मार्च से

  • महीनों नंबर, सभी महीनों 5 महीने 153 के कुल का एक चक्र के साथ कि मूल दोहराने से पहले एक को छोड़कर:

    // Conversion from UTC date to second, signed 64-bit adjustable epoch version. 
    // Written by François Grieu, 2015-07-21; public domain. 
    
    #include <time.h>     // needed for struct tm 
    #include <stdint.h>     // needed for int_least64_t 
    #define MY_EPOCH 1970   // epoch year, changeable 
    typedef int_least64_t my_time_t; // type for seconds since MY_EPOCH 
    
    // my_mktime converts from struct tm UTC to non-leap seconds since 
    // 00:00:00 on the first UTC day of year MY_EPOCH (adjustable). 
    // It works since 1582 (start of Gregorian calendar), assuming an 
    // apocryphal extension of Coordinated Universal Time, until some 
    // event (like celestial impact) deeply messes with Earth. 
    // It strive to be strictly C99-conformant. 
    // 
    // input: Pointer to a struct tm with field tm_year, tm_mon, tm_mday, 
    //   tm_hour, tm_min, tm_sec set per mktime convention; thus 
    //   - tm_year is year minus 1900; 
    //   - tm_mon is [0..11] for January to December, but [-2..14] 
    //   works for November of previous year to February of next year; 
    //   - tm_mday, tm_hour, tm_min, tm_sec similarly can be offset to 
    //   the full range [-32767 to 32767]. 
    // output: Number of non-leap seconds since beginning of the first UTC 
    //   day of year MY_EPOCH, as a signed at-least-64-bit integer. 
    //   The input is not changed (in particular, fields tm_wday, 
    //   tm_yday, and tm_isdst are unchanged and ignored). 
    my_time_t my_mktime(const struct tm * ptm) { 
        int m, y = ptm->tm_year+2000; 
        if ((m = ptm->tm_mon)<2) { m += 12; --y; } 
    // compute number of days within constant, assuming appropriate origin 
    #define MY_MKTIME(Y,M,D) ((my_time_t)Y*365+Y/4-Y/100*3/4+(M+2)*153/5+D) 
        return (((MY_MKTIME(y   , m, ptm->tm_mday) 
           -MY_MKTIME((MY_EPOCH+99), 12, 1   ) 
          )*24+ptm->tm_hour)*60+ptm->tm_min)*60+ptm->tm_sec; 
    #undef MY_MKTIME // this macro is private 
        } 
    

    कुंजी महान सरलीकरण की इजाजत दी टिप्पणियों this और that जवाब में कोड की तुलना 31 और 30 दिनों के वैकल्पिक दिन, ताकि किसी भी महीने के लिए, और लीप वर्षों के लिए विचार किए बिना, पिछले फरवरी के बाद से दिनों की संख्या (स्थिर के भीतर) उचित स्थिरता, 153 द्वारा गुणा करके, 5 द्वारा पूर्णांक विभाजन;

  • वर्षों में कई वर्षों में लीप वर्ष के लिए नियम के लिए लेखांकन के दिनों में सुधार (जो एकाधिक -4 नियमों के अपवाद के अनुसार गैर-छलांग है, सिवाय इसके कि 400 के एकाधिक) की गणना की जा सकती है (निरंतर के भीतर) एक उचित निरंतर, 100 द्वारा पूर्णांक विभाजन, 3 से गुणा, और 4 द्वारा पूर्णांक विभाजन के अतिरिक्त;
  • हम मुख्य गणना में उपयोग किए जाने वाले उसी सूत्र का उपयोग करके किसी भी युग के लिए सुधार की गणना कर सकते हैं, और यह मैक्रो के साथ ऐसा कर सकते हैं ताकि संकलन समय पर यह सुधार की गणना की जा सके।

यहाँ 64-बिट समर्थन, 1970 मूल करने के लिए बंद कर दिया की जरूरत नहीं एक और संस्करण है।

// Conversion from UTC date to second, unsigned 32-bit Unix epoch version. 
// Written by François Grieu, 2015-07-21; public domain. 

#include <time.h>     // needed for struct tm 
#include <limits.h>     // needed for UINT_MAX 
#if UINT_MAX>=0xFFFFFFFF   // unsigned is at least 32-bit 
typedef unsigned  my_time_t; // type for seconds since 1970 
#else 
typedef unsigned long my_time_t; // type for seconds since 1970 
#endif 

// my_mktime converts from struct tm UTC to non-leap seconds since 
// 00:00:00 on the first UTC day of year 1970 (fixed). 
// It works from 1970 to 2105 inclusive. It strives to be compatible 
// with C compilers supporting // comments and claiming C89 conformance. 
// 
// input: Pointer to a struct tm with field tm_year, tm_mon, tm_mday, 
//   tm_hour, tm_min, tm_sec set per mktime convention; thus 
//   - tm_year is year minus 1900 
//   - tm_mon is [0..11] for January to December, but [-2..14] 
//   works for November of previous year to February of next year 
//   - tm_mday, tm_hour, tm_min, tm_sec similarly can be offset to 
//   the full range [-32767 to 32768], as long as the combination 
//   with tm_year gives a result within years [1970..2105], and 
//   tm_year>0. 
// output: Number of non-leap seconds since beginning of the first UTC 
//   day of year 1970, as an unsigned at-least-32-bit integer. 
//   The input is not changed (in particular, fields tm_wday, 
//   tm_yday, and tm_isdst are unchanged and ignored). 
my_time_t my_mktime(const struct tm * ptm) { 
    int m, y = ptm->tm_year; 
    if ((m = ptm->tm_mon)<2) { m += 12; --y; } 
    return ((((my_time_t)(y-69)*365u+y/4-y/100*3/4+(m+2)*153/5-446+ 
     ptm->tm_mday)*24u+ptm->tm_hour)*60u+ptm->tm_min)*60u+ptm->tm_sec; 
    } 
0

मैं यूटीसी में समय स्टांप उत्पन्न करने के लिए निम्न कोड का प्रयोग किया:

#include <iostream> 
#include <sstream> 
#include <chrono> 
using namespace std; 

string getTimeStamp() { 
    time_t now = time(NULL); 
    tm* gmt_time = gmtime(&now); 
    ostringstream oss; 
    oss << put_time(gmt_time, "%Y-%m-%d %H:%M:%S"); 
    return oss.str(); 
} 
संबंधित मुद्दे