strftime returns iOS 星期几不正确
strftime returns incorrect day of the week on 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,它正确输出 "Monday"(今天是星期几)。当我在 iOS 上编译和 运行 相同的代码时,它 returns "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);
}
strptime()
仅更新提供的 struct tm
中格式字符串中指定的字段。其他字段保持不变(在您的情况下未初始化)。
有两个问题导致问题中的行为。
strptime
似乎在解析日期时意外地使本地时区生效(但仅用于设置星期几!)。似乎当它解析“2017-04-17”时,至少在星期几,它把它当作午夜 UTC 来处理——这意味着在负 UTC 中抵消了星期几 "time" 早一天。
基本上 strptime
总是给我 tm_wday
比正确值少一。解析“2017-04-17”(星期一)时,return 0
(星期日)表示 tm_wday
,“2017-04-18”表示 1
(星期一) "(星期二)。
非常奇怪的是它不会填写其他时区数据,例如tm_isdst
或tm_gmtoff
。它会让那些保持不变 - 只需为 tm_wday
.
选择一个错误的值
我能够通过在生成的 tm
结构 return 上调用 mktime
来解决这个问题 strptime
。我没有使用 mktime
中的 time_t
returned,但是在 tm
结构上调用 mktime
的行为正确设置了 [=13 的值=]、以及 正确设置 tm_isdst
、tm_gmtoff
等的值。
我没有对 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);
不是答案,但也许是解决方案:
如果您可以使用 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"
也作为 shorthand 用于 "%Y-%m-%d"
,作为 POSIX strptime
规范的扩展。
in >> parse("%F", ymd);
这是一个功能非常全面的日期时间库,可以处理粗略到一年的日历特征,以及精确到纳秒级的时间戳。它全部构建在 C++ <chrono>
库上,因此是完全类型安全的。随后它比 C/POSIX API 更容易使用,在编译时检测到许多逻辑错误。
我有以下代码:
#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,它正确输出 "Monday"(今天是星期几)。当我在 iOS 上编译和 运行 相同的代码时,它 returns "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);
}
strptime()
仅更新提供的 struct tm
中格式字符串中指定的字段。其他字段保持不变(在您的情况下未初始化)。
有两个问题导致问题中的行为。
strptime
似乎在解析日期时意外地使本地时区生效(但仅用于设置星期几!)。似乎当它解析“2017-04-17”时,至少在星期几,它把它当作午夜 UTC 来处理——这意味着在负 UTC 中抵消了星期几 "time" 早一天。基本上
strptime
总是给我tm_wday
比正确值少一。解析“2017-04-17”(星期一)时,return0
(星期日)表示tm_wday
,“2017-04-18”表示1
(星期一) "(星期二)。非常奇怪的是它不会填写其他时区数据,例如
选择一个错误的值tm_isdst
或tm_gmtoff
。它会让那些保持不变 - 只需为tm_wday
.我能够通过在生成的
tm
结构 return 上调用mktime
来解决这个问题strptime
。我没有使用mktime
中的time_t
returned,但是在tm
结构上调用mktime
的行为正确设置了 [=13 的值=]、以及 正确设置tm_isdst
、tm_gmtoff
等的值。我没有对
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);
不是答案,但也许是解决方案:
如果您可以使用 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"
也作为 shorthand 用于 "%Y-%m-%d"
,作为 POSIX strptime
规范的扩展。
in >> parse("%F", ymd);
这是一个功能非常全面的日期时间库,可以处理粗略到一年的日历特征,以及精确到纳秒级的时间戳。它全部构建在 C++ <chrono>
库上,因此是完全类型安全的。随后它比 C/POSIX API 更容易使用,在编译时检测到许多逻辑错误。