从C / C ++中的周数计算公历日期 [英] Calculate Gregorian date from week number in C/C++

查看:382
本文介绍了从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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆