【问题标题】:How do I calculate the week number given a date?如何计算给定日期的周数?
【发布时间】:2010-09-21 10:49:59
【问题描述】:

如果我有一个日期,我如何计算该日期在该年的周数?

例如,在 2008 年,1 月 1 日到 1 月 6 日是第 1 周,1 月 7 日到 13 日是第 2 周,所以如果我的日期是 2008 年 1 月 10 日,我的周数就是 2。

一种算法可以很好地帮助我入门,示例代码也会有所帮助 - 我正在 Windows 上使用 C++ 进行开发。

相关:

Getting week number off a date in MS SQL Server 2005?

【问题讨论】:

标签: c++ windows algorithm time


【解决方案1】:

伪代码:

int julian = getDayOfYear(myDate)  // Jan 1 = 1, Jan 2 = 2, etc...
int dow = getDayOfWeek(myDate)     // Sun = 0, Mon = 1, etc...
int dowJan1 = getDayOfWeek("1/1/" + thisYear)   // find out first of year's day
// int badWeekNum = (julian / 7) + 1  // Get our week# (wrong!  Don't use this)
int weekNum = ((julian + 6) / 7)   // probably better.  CHECK THIS LINE. (See comments.)
if (dow < dowJan1)                 // adjust for being after Saturday of week #1
    ++weekNum;
return (weekNum)

为了澄清,这个算法假设你这样编号你的星期:

S  M  T  W  R  F  S
            1  2  3    <-- week #1
4  5  6  7  8  9 10    <-- week #2
[etc.]

getDayOfWeek() 和 getDayOfYear() 是大多数语言中的标准日期对象操作。如果您的没有它们,您可以从某个已知日期(1970 年 1 月 1 日是一个常见的日期)开始倒计时,然后查看它是星期几。

如果您要实现自己的日期计数例程,请记住,能被 100 整除的年份是不是闰年,除非它们也能被 400 整除。所以 1900 年不是闰年年,但 2000 年是。如果您要在很久以前工作,则必须弄乱公历和儒略历等,请参阅Wikipedia 以获取大量信息。

This link 更详细地讨论了 Windows/C++ 中的日期/时间函数。

【讨论】:

  • 我同意它没有达到我的要求,但我意识到我并没有要求我真正想要的!我对第几周的定义。是一个我认为是“标准”的,但因为它不是我很高兴改变我的定义。我认为您的答案可能更正确,但这是我使用的答案。
  • 除非我弄错了,否则这是不正确的。仅以 1 月 7 日为例:juilan = 7, dow = 3, dowJan1 = 4, weekNum = (7/7)+1 = 2。然后 dow 小于 dowJan1 所以 weekNum+1 = 3。但显然 1 月 7 日是第 2 周。
  • @NKijak -- 很好的收获!看起来我应该使用 ((julian + 6) / 7) 而不是 ((julian / 7) + 1) - 这是否解决了所有“减一”的问题?无论哪种方式,我认为调试服饰都可以,基本思想就在那里。 (如果有人想审查我的修复,我将编辑答案以包含更正的代码。)
  • 即使使用 ((julian / 7) + 1) 也不正确:例如,对于 2012 年 4 月 5 日,它返回 16,而不是 15。
  • @phortx:请记住,这个示例从在浏览器中输入的伪代码开始,并逐渐演变为几乎可以工作的 C,其中某些部分可能不太正确并需要使用 cmets调整。特别是,您指定的行是badWeekNum,而它下面的行被标记为“可能更好”。如果您有修复,我会很乐意编辑该示例以进一步改进它。谢谢!
【解决方案2】:

使用 gmtime 或 localtime 计算自星期日(即一周中的某天)以来的天数和自 1 月 1 日以来的天数(请注意,后者中 1 月 1 日为“0”)。

任意位决定第 1 周从一年中的哪一天开始:通常它只取决于 1 月 1 日是一周中的哪一天,当然你可以从 gmtime 的两条信息中计算出来。然后使用表格查找这 7 种可能性,这可能比编写规则更容易。

例如,我认为 Outlook 使用的标准是第 1 周是包含星期四的第一周。因此,如果 1 月 1 日是星期日,那么第 1 周的第一天就是 1 月 1 日,即第 0 天。剩下的可能性是星期一,-1;星期二,-2;星期三,-3;星期四,-4;星期五,2;星期六,1。

注意负数:“第 1 周的星期日”实际上并不存在于 7 个案例中的 4 个,但如果我们假装它是前一年的一天,我们就会得到正确的答案。

一旦你有了它,它和你的日期之间的天数会告诉你周数:除以 7 并加 1。

也就是说,我想在某个地方有一个 Windows API 可以为您提供与 Outlook 使用的相同的周数。我只是不知道它是什么,当然,如果您的第 1 周规则与 Outlook 的不同,那么它可能没有多大用处。

未经测试的代码:

int firstdays[7] = { 0, -1, -2, -3, -4, 2, 1 }; // or some other Week 1 rule
struct tm breakdown;
time_t target = time_you_care_about();
_gmtime_s(&breakdown,&target);
int dayofweek = breakdown.tm_wday;
int dayofyear = breakdown.tm_yday;

int jan1wday = (dayofweek - dayofyear) % 7;
if (jan1wday < 0) jan1wday += 7;

int week1first = firstdays[jan1wday];
if (dayofyear < week1first) return 0;
return ((dayofyear - week1first)/7) + 1;

反正就是这样。

【讨论】:

    【解决方案3】:

    请注意,虽然您对一年中第 nth 周的定义是成立的,但它也不是“标准”。

    ISO 8601 定义了日期、时间和时区的表示标准。它定义了从星期一开始的星期。它还说一年的第一周是从给定年份起至少包含 4 天的那一周。因此,20xx 年 12 月 29 日、30 日和 31 日可能在 20xy 的第 1 周(其中 xy = xx + 1),而 20xy 的 1 月 1 日、2 日和 3 日都可能在 20xx 的最后一周。此外,可能还有第 53 周。

    [添加:请注意,C 标准和 `strftime() 函数提供从星期日开始的周以及从星期一开始的周。尚不清楚 C 标准是否为基于星期日的周提供第 0 周的年份数。另请参阅 Emerick Rogul 的回答。]

    接下来是有趣的测试阶段——你什么时候能拿到第 53 周? 一个答案是 2010 年 1 月 1 日星期五,即 2009-W53(如, 事实上,是 2010 年 1 月 3 日星期日)。同样,1 月 1 日星期六 2005 年是 2004-W53,但 2006 年 1 月 1 日星期日是 2005-W52。

    这是从以下代码中的注释中摘录的,它实际上是在 Informix SPL(存储过程语言)中,但它是可读的 - 尽管可能不可写 - 没有更多的解释。 '||' operator 是 SQL 字符串连接操作,星期日是第 0 天,星期一是第 1 天,...星期六是一周的第 6 天。 cmets 中有大量注释,包括标准中的相关文本。一行 cmets start '--';可能多行 cmets 以 '{' 开头并在下一个 '}' 结束。

    -- @(#)$Id: iso8601_weekday.spl,v 1.1 2001/04/03 19:34:43 jleffler Exp $
    --
    -- Calculate ISO 8601 Week Number for given date
    -- Defines procedure: iso8601_weekday().
    -- Uses procedure: iso8601_weeknum().
    
    {
    According to a summary of the ISO 8601:1988 standard "Data Elements and
    Interchange Formats -- Information Interchange -- Representation of
    dates and times":
    
        The week notation can also be extended by a number indicating the
        day of the week.  For example the day 1996-12-31 which is the
        Tuesday (day 2) of the first week of 1997 can also be written as
    
            1997-W01-2 or 1997W012
    
        for applications like industrial planning where many things like
        shift rotations are organized per week and knowing the week number
        and the day of the week is more handy than knowing the day of the
        month.
    
    This procedure uses iso8601_weeknum() to format the YYYY-Www part of the
    date, and appends '-d' to the result, allowing for Informix's coding of
    Sunday as day 0 rather than day 7 as required by ISO 8601.
    }
    
    CREATE PROCEDURE iso8601_weekday(dateval DATE DEFAULT TODAY) RETURNING CHAR(10);
        DEFINE rv CHAR(10);
        DEFINE dw CHAR(4);
        LET dw = WEEKDAY(dateval);
        IF dw = 0 THEN
                LET dw = 7;
        END IF;
        RETURN iso8601_weeknum(dateval) || '-' || dw;
    END PROCEDURE;
    -- @(#)$Id: iso8601_weeknum.spl,v 1.1 2001/02/27 20:36:25 jleffler Exp $
    --
    -- Calculate ISO 8601 Week Number for given date
    -- Defines procedures: day_one_week_one() and iso8601_weeknum().
    
    {
    According to a summary of the ISO 8601:1988 standard "Data Elements and
    Interchange Formats -- Information Interchange -- Representation of
    dates and times":
    
        In commercial and industrial applications (delivery times,
        production plans, etc.), especially in Europe, it is often required
        to refer to a week of a year.  Week 01 of a year is per definition
        the first week which has the Thursday in this year, which is
        equivalent to the week which contains the fourth day of January.  In
        other words, the first week of a new year is the week which has the
        majority of its days in the new year.  Week 01 might also contain
        days from the previous year and the week before week 01 of a year is
        the last week (52 or 53) of the previous year even if it contains
        days from the new year.  A week starts with Monday (day 1) and ends
        with Sunday (day 7).  For example, the first week of the year 1997
        lasts from 1996-12-30 to 1997-01-05 and can be written in standard
        notation as
    
            1997-W01 or 1997W01
    
        The week notation can also be extended by a number indicating the
        day of the week.  For example the day 1996-12-31 which is the
        Tuesday (day 2) of the first week of 1997 can also be written as
    
            1997-W01-2 or 1997W012
    
        for applications like industrial planning where many things like
        shift rotations are organized per week and knowing the week number
        and the day of the week is more handy than knowing the day of the
        month.
    
    Referring to the standard itself, section 3.17 defines a calendar week:
    
        week, calendar: A seven day period within a calendar year, starting
        on a Monday and identified by its ordinal number within the year;
        the first calendar week of the year is the one that includes the
        first Thursday of that year.  In the Gregorian calendar, this is
        equivalent to the week which includes 4 January.
    
    Section 5.2.3 "Date identified by Calendar week and day numbers" states:
    
        Calendar week is represented by two numeric digits.  The first
        calendar week of a year shall be identified as 01 [...]
    
        Day of the week is represented by one decimal digit.  Monday
        shall be identified as day 1 of any calendar week [...]
    
    Section 5.2.3.1 "Complete representation" states:
    
        When the application clearly identifies the need for a complete
        representation of a date identified by calendar week and day
        numbers, it shall be one of the alphanumeric representations as
        follows, where CCYY represents a calendar year, W is the week
        designator, ww represents the ordinal number of a calendar week
        within the year, and D represents the ordinal number within the
        calendar week.
    
        Basic format: CCYYWwwD
            Example: 1985W155
        Extended format: CCYY-Www-D
            Example: 1985-W15-5
    
    Both the summary and the formal definition are intuitively clear, but it
    is not obvious how to translate it into an algorithm.  However, we can
    deal with the problem by exhaustively enumerating the seven options for
    the day of the week on which 1st January falls (with actual year values
    for concreteness):
    
        1st January 2001 is Monday    => Week 1 starts on 2001-01-01
        1st January 2002 is Tuesday   => Week 1 starts on 2001-12-31
        1st January 2003 is Wednesday => Week 1 starts on 2002-12-30
        1st January 2004 is Thursday  => Week 1 starts on 2003-12-29
        1st January 2010 is Friday    => Week 1 starts on 2010-01-04
        1st January 2005 is Saturday  => Week 1 starts on 2005-01-03
        1st January 2006 is Sunday    => Week 1 starts on 2006-01-02
    
    (Cross-check: 1st January 1997 was a Wednesday; the summary notes state
    that week 1 of 1997 started on 1996-12-30, which is consistent with the
    table derived for dates in the first decade of the third millennium
    above).
    
    When working with the Informix DATE types, bear in mind that Informix
    uses WEEKDAY values 0 = Sunday, 1 = Monday, 6 = Saturday.  When the
    weekday of the first of January has the value in the LH column, you need
    to add the value in the RH column to the 1st of January to obtain the
    date of the first day of the first week of the year.
    
        Weekday         Offset to
        1st January     1st day of week 1
    
        0               +1
        1                0
        2               -1
        3               -2
        4               -3
        5               +3
        6               +2
    
    This can be written as MOD(11-w,7)-3 where w is the (Informix encoding
    of the) weekday of 1st January and the value 11 is used to ensure that
    no negative values are presented to the MOD operator.  Hence, the
    expression for the date corresponding to the 1st day (Monday) of the 1st
    week of a given year, yyyy, is:
    
        d1w1 = MDY(1, 1, yyyy) + MOD(11 - WEEKDAY(MDY(1,1,yyyy)), 7) - 3
    
    This expression is encapsulated in stored procedure day_one_week_one:
    }
    
    CREATE PROCEDURE day_one_week_one(yyyy INTEGER) RETURNING DATE;
        DEFINE jan1 DATE;
        LET jan1 = MDY(1, 1, yyyy);
        RETURN jan1 + MOD(11 - WEEKDAY(jan1), 7) - 3;
    END PROCEDURE;
    
    {
    Given this date d1w1, we can calculate the week number of any other date
    in the same year as:
    
        TRUNC((dateval - d1w1) / 7) + 1
    
    The residual issues are ensuring that the wraparounds are correct.  If
    the given date is earlier than the start of the first week of the year
    that contains it, then the date belongs to the last week of the previous
    year.  If the given date is on or after the start of the first week of
    the next year, then the date belongs to the first week of the next year.
    
    Given these observations, we can write iso8601_weeknum as shown below.
    (Beware: iso8601_week_number() is too long for servers with the
    18-character limit; so is day_one_of_week_one()).
    
    Then comes the interesting testing phase -- when do you get week 53?
    One answer is on Friday 1st January 2010, which is in 2009-W53 (as,
    indeed, is Sunday 3rd January 2010).  Similarly, Saturday 1st January
    2005 is in 2004-W53, but Sunday 1st January 2006 is in 2005-W52.
    }
    
    CREATE PROCEDURE iso8601_weeknum(dateval DATE DEFAULT TODAY) RETURNING CHAR(8);
        DEFINE rv CHAR(8);
        DEFINE yyyy CHAR(4);
        DEFINE ww CHAR(2);
        DEFINE d1w1 DATE;
        DEFINE tv DATE;
        DEFINE wn INTEGER;
        DEFINE yn INTEGER;
        -- Calculate year and week number.
        LET yn = YEAR(dateval);
        LET d1w1 = day_one_week_one(yn);
        IF dateval < d1w1 THEN
            -- Date is in early January and is in last week of prior year
            LET yn = yn - 1;
            LET d1w1 = day_one_week_one(yn);
        ELSE
            LET tv = day_one_week_one(yn + 1);
            IF dateval >= tv THEN
                -- Date is in late December and is in the first week of next year
                LET yn = yn + 1;
                LET d1w1 = tv;
            END IF;
        END IF;
        LET wn = TRUNC((dateval - d1w1) / 7) + 1;
        -- Calculation complete: yn is year number and wn is week number.
        -- Format result.
        LET yyyy = yn;
        IF wn < 10 THEN
            LET ww = '0' || wn;
        ELSE
            LET ww = wn;
        END IF
        LET rv = yyyy || '-W' || ww;
        RETURN rv;
    END PROCEDURE;
    

    为了完整起见,逆函数也很容易用上面的day_one_week_one()函数写出来:

    -- @(#)$Id: ywd_date.spl,v 1.1 2012/12/29 05:13:27 jleffler Exp $
    -- @(#)Create ywd_date() and ywdstr_date() stored procedures
    
    -- Convert a date in format year, week, day (ISO 8601) to DATE.
    -- Two variants:
    -- ywd_date(yyyy SMALLINT, ww SMALLINT, dd SMALLINT) RETURNING DATE;
    -- ywdstr_date(ywd CHAR(10)) RETURNING DATE;
    
    -- NB: If week 53 is supplied, there is no check that the year had week
    --     53 (GIGO).
    -- NB: If year yyyy is a leap year and yyyy-01-01 falls on Wed (3) or
    --     Thu (4), there are 53 weeks in the year.
    -- NB: If year yyyy is not a leap year and yyyy-01-01 falls on Thu (4),
    --     there are 53 weeks in the year.
    
    CREATE PROCEDURE ywd_date(yyyy SMALLINT, ww SMALLINT, dd SMALLINT) RETURNING DATE AS date;
        DEFINE d DATE;
        -- Check ranges
        IF yyyy < 1 OR yyyy > 9999 OR ww < 1 OR ww > 53 OR dd < 1 OR dd > 7 THEN
            RETURN NULL;
        END IF;
        LET d = day_one_week_one(yyyy);
        LET d = d + (ww - 1) * 7 + (dd - 1);
        RETURN d;
    END PROCEDURE;
    
    -- Input: 2012-W52-5
    CREATE PROCEDURE ywdstr_date(ywd CHAR(10)) RETURNING DATE AS date;
        DEFINE yyyy SMALLINT;
        DEFINE ww   SMALLINT;
        DEFINE dd   SMALLINT;
        LET yyyy = SUBSTR(ywd,  1, 4);
        LET ww   = SUBSTR(ywd,  7, 2);
        LET dd   = SUBSTR(ywd, 10, 1);
        RETURN ywd_date(yyyy, ww, dd);
    END PROCEDURE;
    
    CREATE TEMP TABLE test_dates(d DATE);
    INSERT INTO test_dates VALUES('2011-12-28');
    INSERT INTO test_dates VALUES('2011-12-29');
    INSERT INTO test_dates VALUES('2011-12-30');
    INSERT INTO test_dates VALUES('2011-12-31');
    INSERT INTO test_dates VALUES('2012-01-01');
    INSERT INTO test_dates VALUES('2012-01-02');
    INSERT INTO test_dates VALUES('2012-01-03');
    INSERT INTO test_dates VALUES('2012-01-04');
    INSERT INTO test_dates VALUES('2012-01-05');
    INSERT INTO test_dates VALUES('2012-01-06');
    INSERT INTO test_dates VALUES('2012-01-07');
    
    SELECT d, iso8601_weeknum(d), iso8601_weekday(d), ywdstr_date(iso8601_weekday(d))
      FROM test_dates
     ORDER BY d;
    

    如 cmets 中所述,代码将接受第 53 周的日期,即使年份应该只接受 52 周。

    【讨论】:

    • 哦,标准的当前版本是 ISO/IEC 8601:2004。
    • 感谢非常详细的解释,我没有意识到计算周数的不同含义和方法!
    • 约扎!我不知道有多少人知道这 4 天的事情...谢谢!
    【解决方案4】:

    我强烈建议使用 C 标准库的时间函数来计算周数。具体来说,strftime 函数具有说明符,用于以分解 (struct tm) 格式打印给定日期的周数(以及许多其他值)。这是一个说明这一点的小示例程序:

    #include <stdio.h>
    #include <string.h>
    #include <time.h>
    
    int
    main(void)
    {
      struct tm tm;
      char timebuf[64];
    
      // Zero out struct tm
      memset(&tm, 0, sizeof tm);
    
      // November 4, 2008 11:00 pm
      tm.tm_sec = 0;
      tm.tm_min = 0;
      tm.tm_hour = 23;
      tm.tm_mday = 4;
      tm.tm_mon = 10;
      tm.tm_year = 108;
      tm.tm_isdst = -1;
    
      // Call mktime to recompute tm.tm_wday and tm.tm_yday
      mktime(&tm);
    
      if (strftime(timebuf, sizeof timebuf, "%W", &tm) != 0) {
        printf("Week number is: %s\n", timebuf);
      }
    
      return 0;
    }
    

    这个程序的输出(在 Linux 上用 GCC 和在 Windows 上用 Microsoft Visual Studio 2005 SP1 编译)是:

    Week number is: 44
    

    您可以了解更多关于 strftime here

    【讨论】:

    • 还要注意 %U、%G、%u、%V 等。
    • ISO C 90 不支持 %U、%G、%u、%V 和 Visual Studio 2005(我相信是 2008)在这方面遵循 C 90,因此在 Windows 上这些不可用。它们记录在opengroup.org/onlinepubs/009695399/functions/strftime.html
    • 查看 strftime 的来源,这是使用的计算: (t->tm_yday + 7 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7.直接使用这种计算避免了必须转换成字符串/从字符串转换。
    【解决方案5】:

    struct tm用于表示“故障时间”,至少有以下字段:

    int tm_sec 秒 [0,60]。 int tm_min 分钟 [0,59]。 int tm_hour 小时 [0,23]。 int tm_mday 日期 [1,31]。 int tm_mon 一年中的月份 [0,11]。 int tm_year 自 1900 年以来的年份。 int tm_wday 星期[0,6](星期日=0)。 int tm_yday 一年中的某一天 [0,365]。 int tm_isdst 夏令时标志。

    您可以使用 localtime() 函数从 time_t 创建一个 struct tm。

    您可以使用 mktime() 函数从 struct tm 创建 time_t。

    关于 struct tm 最好的部分是您可以执行诸如将 24 添加到一年中的月份成员之类的操作,并且当您调用 mktime() 时,您将获得一个 time_t,即 2 年后(这适用于它的任何成员,因此您可以例如将小时增加 1000,然后在未来 41 天获得 time_t)...

    【讨论】:

    • 但是 struct tm 没有一年中的星期,所以这对于这种情况来说用途有限。
    【解决方案6】:

    Boost 提供 gregorian::date::week_number() 见http://www.boost.org/doc/libs/1_38_0/doc/html/boost/gregorian/date.htmlhttp://www.boost.org/doc/libs/1_38_0/boost/date_time/gregorian/greg_date.hpp.

    但是我看不到一种方法来获取与周数匹配的年数(可能与该日期的日历年不同)。

    【讨论】:

      【解决方案7】:

      对不起,我是新来的,无法对答案本身发表评论,但带有复选标记的答案中的伪代码并不完全正确。

      伪代码:

      int julian = getDayOfYear(myDate)  // Jan 1 = 1, Jan 2 = 2, etc...
      int dow = getDayOfWeek(myDate)     // Sun = 0, Mon = 1, etc...
      int dowJan1 = getDayOfWeek("1/1/" + thisYear)   // find out first of year's day
      int weekNum = (julian / 7) + 1     // Get our week#
      if (dow < dowJan1)                 // adjust for being after Saturday of week #1
          ++weekNum;
      return (weekNum)
      

      您不应该寻找“年初的一天”,而应该寻找去年的最后一天。

      getDayOfWeek("12/31/" + thisYear-1)
      

      将是正确的,而不是

      getDayOfWeek("1/1/" + thisYear) 
      

      如果您不这样做,去年的最后一个工作日(如星期一)总是会提前一周。

      【讨论】:

        【解决方案8】:

        我的定义是非 ISO 8601(对我的目的来说足够好并且速度很快):

        // week number of the year
        // (Monday as the first day of the week) as a decimal number [00,53].
        // All days in a new year preceding the first Monday are considered to be in week 0.
        int GetWeek(const struct tm& ts)
        {
            return (ts.tm_yday + 7 - (ts.tm_wday ? (ts.tm_wday - 1) : 6)) / 7;
        }
        

        【讨论】:

          【解决方案9】:

          我的假设是,如 Olie 的回答所示,一年中的第一周最多可能包含 7 天。 该代码不处理一周从星期日开始的另一天的文化,这是世界的很大一部分。

          tm t = ... //the date on which to find week of year
          
          int wy = -1;
          
          struct tm t1;
          t1.tm_year = t.tm_year;
          t1.tm_mday = t1.tm_mon = 1; //set to 1st of January
          time_t tt = mktime(&t1); //compute tm
          
          //remove days for 1st week
          int yd = t.tm_yday - (7 - t1.tm_wday);
          if(yd <= 0 ) //first week is now negative
            wy = 0;
          else
            wy = (int)std::ceil( (double) ( yd/7) ); //second week will be 1 
          

          【讨论】:

            【解决方案10】:
            public int GetWeekOfYear(DateTime todayDate)
            {
                int days = todayDate.DayOfYear;
                float result = days / 7;
                result=result+1;
                Response.Write(result.ToString());
                return Convert.ToInt32(result);
            }
            

            只需将当前日期作为参数传递给此函数。 然后你会得到当前的周数。 希望它能解决你的问题。非常欢迎任何建议。

            【讨论】:

              【解决方案11】:
              time_t t = time(NULL);
              tm* timePtr = localtime(&t);
              double day_of_year=timePtr->tm_yday +1 ; // 1-365
              int week_of_year =(int) ceill(day_of_year/7.0);
              

              【讨论】:

                【解决方案12】:
                /**
                 * @brief WeekNo
                 * @param yr
                 * @param mon
                 * @param day
                 * @param iso
                 * @return
                 *
                 *  Given a date, return the week number
                 *  Note. The first week of the year begins on the Monday
                 *  following the previous Thursday
                 *  Follows ISO 8601
                 *
                 *  Mutually equivalent definitions for week 01 are:
                 *
                 *  the week with the year's first Thursday in it (the ISO 8601 definition)
                 *  the week with the Thursday in the period 1 – 7 January
                 *  the week starting with the Monday in the period 29 December – 4 January
                 *  the week starting with the Monday which is nearest in time to 1 January
                 *  the week ending with the Sunday in the period 4 – 10 January
                 *  the week with 4 January in it
                 *  the first week with the majority (four or more) of its days in the starting year
                 *    If 1 January is on a Monday, Tuesday, Wednesday or Thursday, it is in week 01.
                 *    If 1 January is on a Friday, Saturday or Sunday, it is part of week 52 or 53 of the previous year.
                 *    the week with the year's first working day in it (if Saturdays, Sundays, and 1 January are not working days).
                 ***    strftime has a conversion of struct tm to weeknumber.  strptime fills in tm struct**
                 *   Code uses strptime, strftime functions.
                 */
                
                int WeekNo( int yr,int mon, int day, int iso)
                {
                    struct tm tm;
                    char format[32];
                    //memset(tm,0,sizeof(tm));
                    sprintf(format,"%d-%02d-%02d",yr,mon,day);
                    strptime(format, "%Y-%m-%d", &tm);
                    // structure tm is now filled in for strftime
                
                   strftime(format, sizeof(format), iso? "%V":"%U", &tm);
                
                    //puts(format);
                    return atoi(format);
                }
                

                调用为 Weekno(2015,12,23,1); //对于 ISO 周数。 Weekno(2015,12,23,0) //对于非 ISO 周数

                【讨论】:

                • 与直接执行代码相比,这很优雅,但执行起来很昂贵。但是,它与 strptime 和 strftime 的 C 语言函数一样准确。
                • 对我不起作用 - 只为所有日期返回 52。
                【解决方案13】:

                这是我的解决方案,但不是 C++

                NoOfDays = (CurrentDate - YearStartDate)+1
                IF NoOfDays MOD 7 = 0 Then
                    WeekNo = INT(NoOfDays/7)
                ELSE
                    WeekNo = INT(NoOfDays/7)+1
                END 
                

                【讨论】:

                  【解决方案14】:

                  使用howardhinnant.github.io/iso_week.html 中的iso_week.h 这很容易实现:

                  #include <iostream>
                  #include "iso_week.h"
                  
                  int main() {
                      using namespace iso_week;
                      using namespace std::chrono;
                      // Get the current time_point and floor to convert to the sys_days:
                      auto today = floor<days>(system_clock::now());
                      // Convert from sys_days to iso_week::year_weeknum_weekday format
                      auto yww = year_weeknum_weekday{today};
                      // Print current week number of the year
                      std::cout << "The current week of " << yww.year() << " is: " 
                                << yww.weeknum() << std::endl;
                  
                      // Set any day
                      auto any_day = 2014_y/9/28;
                      // Get week of `any_day`
                      std::cout << "The week of " << any_day.year() << " on `any day` was: " 
                                << any_day.weeknum() << std::endl;   
                  }
                  

                  输出是:

                  The current week of 2019 is: W18
                  The week in 2014 on `any day` was: W09
                  

                  【讨论】:

                    【解决方案15】:
                    /**********************************************************************************
                    Function Name: rtcCalcYearWeek
                    Description  : Function to calculate the working week of the year (changing on a Monday)
                    Arguments    : IN  iYear - The year 2000...
                                   IN  iMonth - The month 1..12
                                   IN  iDay - The day 1..31
                                   IN  iWeekDay - The week day 0 = Monday ... 6 = Sunday
                    Return Value : The year week 1..52
                    ***********************************************************************************/
                    int rtcCalcYearWeek(int iYear, int iMonth, int iDay, int iWeekDay)
                    {
                        int iLeap = 0;
                        static const int ppiYearDays[2][13] =
                        {
                             /* Normal year */
                             {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
                             /* Leap year */
                             {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
                        };
                        /* Check for leap year */
                        if (((iYear % 4) == 0) && (((iYear % 100) != 0) || ((iYear % 400) == 0)))
                        {
                            iLeap = 1;
                        }
                        /* Calculate the year week */
                        return (((ppiYearDays[iLeap][iMonth] + iDay) - (iWeekDay + 7) % 7 + 7) / 7) + 1;
                    }
                    /***********************************************************************************
                    End of function  rtcCalcYearWeek
                    ***********************************************************************************/
                    
                    /**********************************************************************************
                    * Function Name: rtcCalcWeekDay
                    * Description  : Function to calculate the week day for a given date from 2000
                    *                to 2099.
                    * Arguments    : IN  iDay - The day 1..31
                    *                IN  iMonth - The month 1..12
                    *                IN  iYear - The year 2000..2099
                    * Return Value : The weekday 0 = Monday ... 6 = Sunday
                    ***********************************************************************************/
                    int rtcCalcWeekDay(int iDay, int iMonth, int iYear)
                    {
                        if (iMonth < 3)
                        {
                            iMonth += 12;
                            iYear -= 1;
                        }
                        return (iDay + (2 * iMonth) + (6 * (iMonth + 1) / 10) + iYear 
                                + (iYear / 4)- (iYear / 100) + (iYear / 400)) % 7;
                    }
                    /***********************************************************************************
                    End of function  rtcCalcWeekDay
                    ***********************************************************************************/
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-07-11
                      • 1970-01-01
                      • 2016-05-07
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-08-06
                      相关资源
                      最近更新 更多