代码之家  ›  专栏  ›  技术社区  ›  Ali Kamel Ali

std::gmtime不返回UTC时间

  •  1
  • Ali Kamel Ali  · 技术社区  · 1 年前

    你好

    以下代码应分别打印当前UTC和当地时间:

    #pragma (disable : 4996)
    
    #include <ctime>
    using namespace std;
    
    int main()
    {
     tm* p_current_tm_0 = gmtime(&current_time);
     tm* p_current_tm_ = localtime(&current_time);
    
     char* current_tm_0 = asctime(p_current_tm_0);
     cout << "Current UTC date and time: " << current_tm_0;
    
     char* current_tm_ = asctime(p_current_tm_);
     cout << "Current local date and time: " << current_tm_;
    }
    

    然而,当我运行程序时,输出是本地时间重复两次。

    我不明白为什么会这样。

    1 回复  |  直到 1 年前
        1
  •  1
  •   Tim Roberts    1 年前

    这里的问题是 gmtime localtime 共享一个全局 struct tm 并返回一个指向它的指针。因此 当地时间 调用覆盖结构。

    试试这个,它会获取结构的副本:

    #include <iostream>
    #include <ctime>
    using namespace std;
    
    int main()
    {
        time_t current_time = time(NULL);
        tm p_current_tm_0 = * gmtime(&current_time);
        tm p_current_tm_ = * localtime(&current_time);
    
        char* current_tm_0 = asctime(&p_current_tm_0);
        cout << "Current UTC date and time: " << current_tm_0;
    
        char* current_tm_ = asctime(&p_current_tm_);
        cout << "Current local date and time: " << current_tm_;
    }
    

    (是的,变量名不再准确,因为它们不是指针。)

    或者,更改顺序:

        tm * p_current_tm_0 = gmtime(&current_time);
        char* current_tm_0 = asctime(p_current_tm_0);
        cout << "Current UTC date and time: " << current_tm_0;
    
        tm * p_current_tm_ = localtime(&current_time);
        char* current_tm_ = asctime(p_current_tm_);
        cout << "Current local date and time: " << current_tm_;
    
        2
  •  1
  •   Peter - Reinstate Monica    1 年前

    这有点棘手。这些功能是古老的。两者 gmtime()/localtime() 配对以及 asctime() 使用静态内存。 两者都将现有内存重新用于后续调用,覆盖先前调用的结果!你的(名字不好,顺便说一句) p_current_tm_0 p_current_tm_ 指针 参考相同的记忆! 字符串指针也是如此 current_tm_0 current_tm_ :您的字符指针总是引用相同的文本。以下是一个测试程序:

    #define _CRT_SECURE_NO_WARNINGS // visual C peculiarity
    #include <iostream>
    #include <ctime>
    using namespace std;
    
    int main()
    {
        time_t current_time;
        time(&current_time);
        tm* p_current_tm_0 = gmtime(&current_time);
        tm* p_current_tm_ = localtime(&current_time);
    
        char* current_tm_0 = asctime(p_current_tm_0);
        cout << "Current UTC date and time: " << current_tm_0;
    
        char* current_tm_ = asctime(p_current_tm_);
        cout << "Current local date and time: " << current_tm_;
    
        cout << "gmt time struct mem:   " << (void*)p_current_tm_0 << "\n";
        cout << "local time struct mem: " << (void*)p_current_tm_ <<  "\n";
        cout << "\n";
        cout << "UTC date and time string: " << (void*)current_tm_0 << "\n";
        cout << "local date and time:      " << (void*)current_tm_  << "\n";
        cout << "\n";
    }
    

    输出为:

    Current UTC date and time: Sun Jun 16 20:26:20 2024
    Current local date and time: Sun Jun 16 20:26:20 2024
    gmt time struct mem:   000001DCF4B8F920
    local time struct mem: 000001DCF4B8F920
    
    UTC date and time string: 000001DCF4B8FF20
    local date and time:      000001DCF4B8FF20
    

    正如你所看到的,和你一样,我也有同样的“错误”。但原因很清楚:这两个函数都使用相同的内存将epoch后的秒数转换为结构化时间值,并将其格式化为文本!第二次通话( localtime() )只需覆盖第一个得到UTC时间的,然后在第二个上面 asctime() 调用将覆盖第一个生成的文本。

    解决方案是将信息复制到某个地方,或者在被覆盖之前使用它,我在这里这样做:

    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <ctime>
    #include <cstring>
    
    using namespace std;
    
    int main()
    {
        time_t seconds_since_1970;
        time(&seconds_since_1970);
        tm* ptr_to_static_tm_memory = gmtime(&seconds_since_1970);
    
        char* ptr_to_static_time_text = asctime(ptr_to_static_tm_memory);
        cout << "Current UTC date and time string: " << ptr_to_static_time_text;
    
        // Note: No assignment necessary, function uses its built-in static memory!!
        localtime(&seconds_since_1970);
    
        // Note: No assignment necessary, function uses its built-in static memory!!
        asctime(ptr_to_static_tm_memory);
        cout << "Current local date and time:      " << ptr_to_static_time_text;
    }
    

    当我第二次调用函数时,我不会分配它们返回的指针! 知道 他们要在哪里写。。。

    背景是,在过去,多线程不是一件事。(像这样重复使用的静态内存不是线程安全的。)20世纪70年代的库编写器认为,通过强制用户传递缓冲区指针或强制用户删除返回的内存(如果函数动态分配,这将是必要的),用户很容易不给用户带来负担。

    顺便说一句,传递缓冲区指针会立即引发有多少内存可用的问题,这将需要一个额外的参数。事实上,内存是有限的,但其数量是未知的;边缘情况可能会导致越界写入。考虑到自功能开始以来45年左右的智慧,人们会选择不同的设计。在C++23中,如果我们相信cppreference的话,它们最终会被弃用。