我使用strftime获得ISO 8601格式(%v)的周数,并希望将其转换为outlook中显示的周数(猜它是格里高利)。
Outlook日历设置为:
对于某些年份,strftime与outlook中显示的weeknumber匹配,但对于某些年份则不匹配。
一个简单的代码检查:
#include
#include
int main ()
{
time_t rawtime;
struct tm *tmDate;
char buffer [80];
time (&rawtime);
tmDate = localtime(&rawtime);
tmDate->tm_hour = 12;
tmDate->tm_mday = 1; //Day of the Month
tmDate->tm_mon = 8; //Month (0=Jan...8=Sep)
tmDate->tm_year = 2018-1900; //Year
mktime(tmDate);
strftime (buffer,80,"%Y-W%V",tmDate);
puts (buffer);
return 0;
}
对于上面的代码及其输入,输出将是2018-W35,它与我的outlook日历(https://www.calendar-365.com/2018-calendar.html)匹配。
然而,如果将年份更改为2019年,则输出将是2019-W35,但在我看来,它将是2019-W36(https://www.calendar-365.com/2019-calendar.html)。
是否有可能将ISO8601周数映射到公历风格?
任何建议或代码示例将会很有帮助!
谢谢!
您参考的网站似乎使用了一个非常独特的周编号系统。 它对周数的定义似乎与ISO的定义相同,只是一周的第一天是星期日而不是星期一。 这意味着一年的第一天是一年的第一个星期四之前的星期天。
没有strftime标志来给出具有此定义的周数。 但是您可以使用C++20
工具轻松地计算它。 不幸的是,它们还没有发布,但是您可以使用这个免费的,开源的C++20chrono预览库,它可以与C++11/14/17一起工作。
除了计算周数外,您还需要计算年份,因为有时公历年与周关联的年份不匹配。 例如,根据https://www.calendar-365.com/2019-calendar.html,2018年12月31日是2019年的第1周。
在给定日期的情况下,这里有一个计算年和周的函数:
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <utility>
// {year, week number}
std::pair<int, int>
outlook_weeknum(date::sys_days sd)
{
using namespace date;
auto y = year_month_day{sd + (Thursday - Sunday)}.year();
auto year_start = sys_days{Thursday[1]/January/y} - (Thursday - Sunday);
if (sd < year_start)
{
--y;
year_start = sys_days{Thursday[1]/January/y} - (Thursday - Sunday);
}
return {int{y}, (sd - year_start)/weeks{1} + 1};
}
逻辑有点棘手。 难的部分是找到一年的第一天的日期,也就是一年的第一个星期四之前的星期天。 这在名义上是:
auto year_start = sys_days{Thursday[1]/January/y} - (Thursday - Sunday);
其中y
是周编号系统中的年份(通常,但不总是与公历年相同)。 当日期在一年中很晚的时候,例如2018-12-31,它可能会落在下一年的第一周。 要捕捉到这种可能性,首先将日期提前4天(周日和周四之间的差值),然后计算当前年份。
这样做之后,计算一年的开始。 如果一年的开始恰好在日期之后,那么你就处于这样一种情况:你的日期在公历年的早期,但在第一个星期四之前是在下一周,而不是本周。 在这种情况下,周数年比公历年少一个。
一旦计算出周数year,那么周数就是简单地将日期和一年的第一个日期之间的差除以7天(1周),再加上1,从而将第一个星期偏置为1,而不是0。
这可以这样锻炼:
int
main()
{
using namespace date;
auto [i, w] = outlook_weeknum(2019_y/9/1);
std::cout << i << "-W" << w << '\n';
}
输出:
2019-W36
要将此代码移植到C++20:
#include“date/date.h”
命名空间日期
更改为命名空间std::chrono
2019_y
更改为2019y