从C / C ++中的周数计算公历日期 [英] Calculate Gregorian date from week number in C/C++
问题描述
我使用的公历,我想实施IS0 8601周,但我偶然发现计算任何一周数的日期问题。例如,ISO日期 2010-W01-1
应返回2010年1月4日和 2009-W01-1
应返回 2008年12月29日。
I'm using the Gregorian calendar the and I want to implement IS0 8601 weeks, but I've stumbled onto a issue calculating the date of any week number. For example the ISO dates 2010-W01-1
should return January 4, 2010 and 2009-W01-1
should return December 29, 2008.
// Get the date for a given year, week and weekday(1-7)
time_t *GetDateFromWeekNumber(int year, int week, int dayOfWeek)
{
// Algorithm here
}
编辑:
我发现任何在线工作的算法,尝试了很多,现在。
I havent found any algorithm that works online, tried a lot but I'm kind of stuck now.
推荐答案
目前接受的答案给出了2017年第1周(和2017年的每周)的错误答案。给定输入2017并且年
和 weekInYear $的函数
GetDayAndMonthFromWeekInYear
c $ c>分别应在 month
中输出1,在 dayInMonth
中输出2,表示2017-
The currently accepted answer gives the wrong answer for week 1 of 2017 (and every week of 2017). The function GetDayAndMonthFromWeekInYear
, given an input of 2017 and 1 for year
and weekInYear
respectively should output 1 in month
and 2 in dayInMonth
, indicating that 2017-W01 begins on Mon, 2017-01-02, but it instead outputs the Gregorian date 2017-01-01.
此免费,开放源代码,C ++ 11/14库使用以下语法输出从ISO周到Gregorian的正确日期转换:
This free, open source, C++11/14 library outputs the correct date conversion from ISO week to Gregorian with this syntax:
#include "date.h"
#include "iso_week.h"
#include <iostream>
int
main()
{
using namespace iso_week::literals;
std::cout << date::year_month_day{2017_y/1_w/mon} << '\n';
}
2017-01-02
是开源的,可以方便地检查所使用的算法的源(iso_week.h和date.h)。
As the library is open source, one can easily inspect the sources ("iso_week.h" and "date.h") for the algorithms used. The algorithms are also efficient, with no iteration used.
一般的方法是转换字段 2017_y / 1_w / mon
从1970-01-01开始连续计数,使用以下算法:
The general approach is to convert the field 2017_y/1_w/mon
into a serial count of days since 1970-01-01, using this algorithm:
CONSTCD14
inline
year_weeknum_weekday::operator sys_days() const NOEXCEPT
{
return sys_days{date::year{int{y_}-1}/date::dec/date::thu[date::last]}
+ (date::mon - date::thu) + weeks{unsigned{wn_}-1} + (wd_ - mon);
}
然后将连续天数转换为年/月/日
使用此算法的字段类型:
And then that serial count of days is converted into a year/month/day
field type using this algorithm:
CONSTCD14
inline
year_month_day
year_month_day::from_sys_days(const sys_days& dp) NOEXCEPT
{
static_assert(std::numeric_limits<unsigned>::digits >= 18,
"This algorithm has not been ported to a 16 bit unsigned integer");
static_assert(std::numeric_limits<int>::digits >= 20,
"This algorithm has not been ported to a 16 bit signed integer");
auto const z = dp.time_since_epoch().count() + 719468;
auto const era = (z >= 0 ? z : z - 146096) / 146097;
auto const doe = static_cast<unsigned>(z - era * 146097); // [0, 146096]
auto const yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399]
auto const y = static_cast<sys_days::rep>(yoe) + era * 400;
auto const doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365]
auto const mp = (5*doy + 2)/153; // [0, 11]
auto const d = doy - (153*mp+2)/5 + 1; // [1, 31]
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4146) // unary minus operator applied to unsigned type, result still unsigned
#endif
auto const m = mp + (mp < 10 ? 3 : -9u); // [1, 12]
#ifdef _MSVC_VER
#pragma warning(pop)
#endif
return year_month_day{date::year{y + (m <= 2)}, date::month(m), date::day(d)};
}
后一种算法是这里有令人难以置信的细节。
这篇关于从C / C ++中的周数计算公历日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!