提问者:小点点

strftime-将周号ISO8601转换为Gregorian standard C++


我使用strftime获得ISO 8601格式(%v)的周数,并希望将其转换为outlook中显示的周数(猜它是格里高利)。

Outlook日历设置为:

  • 一周的第一天(星期日)
  • 一年的第一周从1月1日开始

对于某些年份,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周数映射到公历风格?

任何建议或代码示例将会很有帮助!

谢谢!


共1个答案

匿名用户

您参考的网站似乎使用了一个非常独特的周编号系统。 它对周数的定义似乎与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:

  1. 删除#include“date/date.h”
  2. 命名空间日期更改为命名空间std::chrono
  3. 2019_y更改为2019y

相关问题


MySQL Query : SELECT * FROM v9_ask_question WHERE 1=1 AND question regexp '(strftime-|周|号|iso8601|转|换为|gregorian|standard|c++)' ORDER BY qid DESC LIMIT 20
MySQL Error : Got error 'repetition-operator operand invalid' from regexp
MySQL Errno : 1139
Message : Got error 'repetition-operator operand invalid' from regexp
Need Help?