strftime在iOS上返回错误的星期几

时间:2017-04-17 19:38:12

标签: c++ ctime

我有以下代码:

#include <iostream>
#include <ctime>
using namespace std; 

int main() {
    tm _tm;
    strptime("2017-04-17", "%Y-%m-%d", &_tm);

    char buf[16];
    strftime(buf, sizeof(buf), "%A", &_tm);

    cout << buf << endl;
}

Ideone上,它正确输出“星期一”(今天的星期几)。当我在iOS上编译并运行相同的代码时,它返回“Sunday”。是什么给了什么?!

编辑:对于那些无法理解这也是C问题的人,这里是C代码。问题仍然存在:

#include <stdio.h>
#include <time.h>

int main(void) {
    struct tm _tm;
    strptime("2017-04-17", "%Y-%m-%d", &_tm);

    char buf[16];
    strftime(buf, sizeof(buf), "%A", &_tm);

    printf(buf);
}

3 个答案:

答案 0 :(得分:1)

strptime()仅更新格式字符串中指定的提供的struct tm中的字段。其他字段保持不变(在您的情况下保持未初始化)。

答案 1 :(得分:1)

导致问题中的行为存在两个问题。

  1. strptime在解析日期时似乎意外地使本地时区生效(但仅用于设置星期几!)。看起来,当它解析&#34; 2017-04-17&#34;,至少在一周中的哪一天,它将其视为午夜UTC时间 - 意味着当天的负偏移量那个星期的时间&#34;时间&#34;是提前一天。

    基本上strptime总是给我tm_wday一个比正确值少的{1}}。在解析&#34; 2017-04-17&#34;时,它会为0返回tm_wday(星期日) (星期一)和1(星期一)&#34; 2017-04-18&#34; (星期二)。

    非常奇怪的是,它不会填写其他时区数据,例如tm_isdsttm_gmtoff。它会保留不变的 - 只为tm_wday选择一个不好的值。

    我能够通过在mktime返回的生成的tm结构上调用strptime来解决此问题。我没有使用time_t返回的mktime,但在mktime结构上调用tm的行为正确设置了tm_wday的值, 以及正确设置tm_isdsttm_gmtoff等的值。

  2. 我没有对tm结构进行零初始化。一旦我开始调用mktime,这才真正发挥作用。如果没有正确初始化,由于mktime的垃圾值,tm_gmtoff会破坏日期。正确初始化后,调用mktime会使用正确的tm_wday设置格式良好的日期。

  3. 所以一个工作的例子是这样的:

    tm _tm = {};
    strptime("2017-04-17", "%Y-%m-%d", &_tm); // Incorrect tm_wday after this call
    mktime(&_tm); // Correct tm_wday after this call
    
    char buf[16];
    strftime(buf, sizeof(buf), "%A", &_tm);
    

答案 2 :(得分:1)

不是答案,但也许是一个解决方案:

如果您可以使用C ++ 11或更高版本,Howard Hinnant's <chrono>-based, free, open-source, header-only date/time library可以在两个平台上获得相同的答案。

#include "date.h"
#include <iostream>
#include <sstream>

int
main()
{
    using namespace std;
    istringstream in{"2017-04-17"};
    date::year_month_day ymd;
    in >> parse("%Y-%m-%d", ymd);
    cout << format("%A\n", ymd);
}

便携式输出:

Monday

此库将解析和格式化解释为UTC中的隐式,没有带有时区的恶作剧或计算机的当前本地时区。如果您需要该功能,则它存在于separate library built on top of this one

"%F"也可作为"%Y-%m-%d"的简写,作为POSIX strptime规范的扩展。

in >> parse("%F", ymd);

这是一个功能非常全面的日期时间库,可以处理粗略的一年的日历功能,以及精确到纳秒的时间戳。它都建立在C ++ <chrono>库之上,因此完全是类型安全的。随后它比C / POSIX API更容易使用,在编译时检测到许多逻辑错误。