384
384
* Returns the number of the week from a supplied year, month, and
385
* date in the Gregorian proleptic calendar.
387
* The week number returned will depend on the values of the
388
* various boolean flags passed to the function.
390
* The flags influence returned values in the following ways:
392
* sunday_is_first_day_of_week
394
* If TRUE, Sunday is first day of week
395
* If FALSE, Monday is first day of week
397
* week_range_is_ordinal
399
* If FALSE, the week is in range 0-53
401
* Week 0 is returned for the the last week of the previous year (for
402
* a date at start of january) In this case one can get 53 for the
403
* first week of next year. This flag ensures that the week is
404
* relevant for the given year.
406
* If TRUE, the week is in range 1-53.
408
* In this case one may get week 53 for a date in January (when
409
* the week is that last week of previous year) and week 1 for a
414
* If TRUE, the weeks are numbered according to ISO 8601:1988
416
* ISO 8601:1988 means that if the week containing January 1 has
417
* four or more days in the new year, then it is week 1;
418
* Otherwise it is the last week of the previous year, and the
419
* next week is week 1.
421
* If FALSE, the week that contains the first 'first-day-of-week' is week 1.
385
* date in the Gregorian proleptic calendar. We use strftime() and
386
* the %U, %W, and %V format specifiers depending on the value
387
* of the sunday_is_first_day_of_week parameter.
423
389
* @param Subject year
424
390
* @param Subject month
425
391
* @param Subject day
426
392
* @param Is sunday the first day of the week?
427
* @param Is the week range ordinal?
428
* @param Should we use ISO 8601:1988 rules?
429
* @param Pointer to a uint32_t to hold the resulting year, which
430
* may be incremented or decremented depending on flags
432
int64_t week_number_from_gregorian_date(uint32_t year
435
, bool sunday_is_first_day_of_week
436
, bool week_range_is_ordinal
437
, bool use_iso_8601_1988
438
, uint32_t *year_out)
441
int64_t day_number= julian_day_number_from_gregorian_date(year, month, day);
442
int64_t first_day_of_year= julian_day_number_from_gregorian_date(year, 1, 1);
443
uint32_t tmp_years= year;
445
int64_t week_day= day_of_week(first_day_of_year, sunday_is_first_day_of_week);
447
if (month == 1 && day <= (7 - week_day))
450
(! week_range_is_ordinal)
452
( (use_iso_8601_1988 && week_day != 0)
453
|| (!use_iso_8601_1988 && (week_day >= 4))
457
if (year_out != NULL)
458
*year_out= tmp_years;
461
week_range_is_ordinal= true;
463
tmp_days= days_in_year(tmp_years, GREGORIAN);
464
first_day_of_year-= tmp_days;
465
week_day= (week_day + (53 * 7) - tmp_days) % 7;
468
if ((!use_iso_8601_1988 && week_day != 0)
469
|| (use_iso_8601_1988 && week_day >= 4))
470
tmp_days= day_number - (first_day_of_year + (7 - week_day));
472
tmp_days= day_number - (first_day_of_year - week_day);
474
if (week_range_is_ordinal && tmp_days >= (52 * 7))
476
week_day= (week_day + days_in_year(tmp_years, GREGORIAN)) % 7;
477
if ((!use_iso_8601_1988 && week_day < 4)
478
|| (use_iso_8601_1988 && week_day == 0))
481
if (year_out != NULL)
482
*year_out= tmp_years;
486
if (year_out != NULL)
487
*year_out= tmp_years;
488
return (tmp_days / 7) + 1;
393
* @param Pointer to a uint32_t to hold the resulting year, which
394
* may be incremented or decremented depending on flags
396
uint32_t week_number_from_gregorian_date(uint32_t year
399
, bool sunday_is_first_day_of_week)
401
struct tm broken_time;
403
broken_time.tm_year= year;
404
broken_time.tm_mon= month - 1; /* struct tm has non-ordinal months */
405
broken_time.tm_mday= day;
407
/* fill out the rest of our tm fields. */
408
(void) mktime(&broken_time);
410
char result[3]; /* 3 is enough space for a max 2-digit week number */
411
size_t result_len= strftime(result
413
, (sunday_is_first_day_of_week ? "%U" : "%W")
417
return (uint32_t) atoi(result);
422
* Returns the ISO week number of a supplied year, month, and
423
* date in the Gregorian proleptic calendar. We use strftime() and
424
* the %V format specifier to do the calculation, which yields a
425
* correct ISO 8601:1988 week number.
427
* The final year_out parameter is a pointer to an integer which will
428
* be set to the year in which the week belongs, according to ISO8601:1988,
429
* which may be different from the Gregorian calendar year.
431
* @see http://en.wikipedia.org/wiki/ISO_8601
433
* @param Subject year
434
* @param Subject month
436
* @param Pointer to a uint32_t to hold the resulting year, which
437
* may be incremented or decremented depending on flags
439
uint32_t iso_week_number_from_gregorian_date(uint32_t year
442
, uint32_t *year_out)
444
struct tm broken_time;
446
if (year_out != NULL)
449
broken_time.tm_year= year;
450
broken_time.tm_mon= month - 1; /* struct tm has non-ordinal months */
451
broken_time.tm_mday= day;
453
/* fill out the rest of our tm fields. */
454
(void) mktime(&broken_time);
456
char result[3]; /* 3 is enough space for a max 2-digit week number */
457
size_t result_len= strftime(result
464
return 0; /* Not valid for ISO8601:1988 */
466
uint32_t week_number= (uint32_t) atoi(result);
469
* ISO8601:1988 states that if the first week in January
470
* does not contain 4 days, then the resulting week number
471
* shall be 52 or 53, depending on the number of days in the
472
* previous year. In this case, we adjust the outbound
473
* year parameter down a year.
475
if (year_out != NULL)
476
if (week_number == 53 || week_number == 52)