我使用 strftime 获取 ISO 8601 格式 (%V) 的周数,并希望将其转换为 Outlook 中显示的周数(猜测是公历)。
Outlook 日历设置为:
- 一周的第一天(星期日)
- 一年的第一周从 1 月 1 日开始
对于某些年份,strftime 与 Outlook 中显示的周数匹配,但对于某些年份则不然。
简单的代码检查:
#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 周数映射到公历风格?
任何建议或代码示例都会有帮助!
谢谢!
最佳答案
您引用的网站似乎使用了非常独特的周编号系统。它对周数的定义似乎反射(reflect)了 ISO 定义,但一周的第一天是星期日而不是星期一。这意味着一年的第一天是一年中第一个星期四之前的星期日。
没有 strftime 标志来给出此定义的周数。但您可以使用 C++20 <chrono>
轻松计算它工具。不幸的是,他们还没有发货,但你可以使用这个 free, open-source C++20 chrono preview library适用于 C++11/14/17。
除了计算周数之外,您还需要计算年份,因为有时公历年份与与周相关的年份不匹配。例如根据https://www.calendar-365.com/2019-calendar.html ,2018 年 12 月 31 日恰逢 2019 年第一周。
因此,这是一个在给定日期的情况下计算年份和周数的函数:
#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
是周编号系统中的年份(通常但并不总是与公历年份相同)。如果日期在一年中很晚,即 12 月 28 日至 31 日,则可能会在下一年的第一周。为了捕捉这种可能性,首先将日期增加 4 天(星期日和星期四之间的差异),然后计算当前年份。
S M T W T F S
y-1 WL 21 22 23 24 25 26 27
y W1 28 29 30 31 1 2 3
完成此操作后,计算年初。如果年初恰好在该日期之后,那么您的日期就属于上一年。在这种情况下,周数年份可能比公历年份小1。当 1 月 1 日是星期五或星期六时,可能会发生这种情况。
S M T W T F S
y-1 WL 27 28 29 30 31 1 2
y W1 3 4 5 6 7 8 9
总之,日期 12/28 - 12/31 的周年编号可以等于其公历年份,也可以大于其公历年份。日期 01/01 和 01/02 的周年编号可以等于其公历年份,也可以小于其公历年份。 -- 全部取决于一月的第一个星期四是每月的哪一天 [1 - 7]。
一旦计算出年份周数 ( y
),周数就是日期与一年第一天之间的差值除以 7 天(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"
- 更改
namespace date
至namespace std::chrono
- 更改
2019_y
至2019y
关于c++ - strftime - 将周数 ISO8601 转换为公历标准 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63133926/