2017-04-17 38 views
2

我有以下代码一周的日不正确:的strftime返回在iOS

#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); 
} 
+2

从man7.org,“使用环境变量TZ和LC_TIME”。运行程序时,您可能需要在每个系统上检查两个值。 – donjuedo

+0

@WeatherVane我相信这也是一个有效的C问题。请不要删除标签。 – aardvarkk

+0

@Olaf您是否真的需要我将这个格式重新格式化为C才表明它也是一个有效的C问题? – aardvarkk

回答

1

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

  1. strptime似乎解析日期时,意外地采取本地时区生效(但只能用于设置一周中的一天!)。它似乎是在解析“2017-04-17”时,至少在一周中的某一天,它将其视为像UTC午夜之类的东西 - 意味着在UTC时间消极的情况下,该“时间”一周中的某天是提前一天。

    基本上strptime总是给我tm_wday一个比正确的价值。当解析“2017-04-17”(星期一)和1(星期一)为“2017-04-18”(星期二)时,它将返回0(星期日)为tm_wday

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

    我能够通过调用mktime修复生成的tm结构返回从strptime。我没有使用time_tmktime返回,但对tm调用mktime的行为结构正常,除了设置tm_wday价值正确设置值tm_isdsttm_gmtoff,等等。

  2. 我没有零初始化tm结构。这只有在我开始致电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); 
1

strptime()只更新了在格式字符串指定的提供struct tm的字段。其他字段保持独立(并且在您的情况下未被初始化)。

+0

在这种情况下,'tm_wday'实际上设置为0.我尝试手动将其设置为1,但'strptime'将其重置为0(星期日,而不是星期一)。所以我不认为这是问题,但对我来说,将结构初始化为零是最好的做法。不过,这并不能解决问题。 – aardvarkk

+1

我认为@yellowantphil可能是对的?也许是时区问题。我提供的日期被解释为*时间*(可能是UTC)。由于我的UTC偏移量是负值,因此它会将星期几计算为前一天?这是我的跑步理论...... – aardvarkk

+0

我相信它可能与'tm_isdst'(与时区有关)有关。 –

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更易于使用,它在编译时检测到许多逻辑错误。