Strftime在iOS上返回一周中不正确的一天

strftime returns incorrect day of the week on iOS

本文关键字:不正确 一天 一周 返回 iOS Strftime      更新时间:2023-10-16

我有以下代码:

#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上编译并运行相同的代码时,它会返回"星期日"。什么给?!

编辑:对于所有不了解这也是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);
}

strptime()仅更新以格式字符串指定的struct tm中的字段。其他字段是单独留下的(在您的情况下,不可分化(。

有两个问题导致问题中的行为。

  1. strptime似乎意外地将本地时区解析时(但仅用于设置一周的一天!(。似乎当它解析" 2017-04-17"时,至少在一周中的一天时,它将其视为诸如午夜UTC之类的东西 - 在那个"时间"的一周中,UTC在负面的情况下是一天前。

    基本上strptime总是给我一个比正确值少的tm_wday。在解析" 2017-04-17"(星期一(和1(星期一(的" 2017-04-18"(星期二(时,它将返回0(周日(。

    非常奇怪的是,它不会填写其他时区数据,例如tm_isdsttm_gmtoff。它将留下那些不变的东西 - 只需为tm_wday选择一个不好的价值。

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

  2. 我没有将tm struct的零元素化。一旦我开始致电mktime,这才真正发挥作用。在没有适当初始化的情况下,mktime由于tm_gmtoff的垃圾值处理日期。在适当初始化后,呼叫mktime给出了正确的日期,并使用正确的tm_wday套装。

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

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);

不是答案,而是解决方案:

如果您可以在C 11或更高版本中工作,则霍华德·辛南特(Howard Hinnant(的<chrono>基于CC_28,免费,开放源代码,仅标题/时间库可以在两个平台上为您提供相同的答案。

#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("%An", ymd);
}

便便输出:

Monday

此库将解析和格式解释为UTC中的隐式,而没有时间区或计算机当前的本地时区的恶作剧。如果您需要该功能,它存在于在该功能上构建的单独库中。

"%F"还可以作为"%Y-%m-%d"的速记,作为POSIX strptime规格的扩展名。

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

这是一个非常完整的DateTime库,可以处理一年一样粗糙的日历功能,并且具有与纳秒一样精确的时间戳。所有这些都是在C <chrono>库上构建的,因此完全可以使用。随后,它比C/posix API容易得多,在编译时检测许多逻辑错误。