1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
* Common functions for dealing with calendrical calculations
29
#if TIME_WITH_SYS_TIME
30
# include <sys/time.h>
34
# include <sys/time.h>
41
#include "drizzled/calendar.h"
46
/** Static arrays for number of days in a month and their "day ends" */
47
static const uint32_t __leap_days_in_month[12]= {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
48
static const uint32_t __normal_days_in_month[12]= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
49
static const uint32_t __leap_days_to_end_month[13]= {0, 31, 60, 91, 121, 151, 182, 213, 244, 274, 305, 335, 366};
50
static const uint32_t __normal_days_to_end_month[13]= {0, 31, 59, 90, 120, 150, 181, 212, 243, 273, 304, 334, 365};
53
* Private utility macro for enabling a switch between
54
* Gregorian and Julian leap year date arrays.
56
#define __DAYS_IN_MONTH(y, c) (const uint32_t *) (IS_LEAP_YEAR((y),(c)) ? __leap_days_in_month : __normal_days_in_month)
57
#define __DAYS_TO_END_MONTH(y, c) (const uint32_t *) (IS_LEAP_YEAR((y),(c)) ? __leap_days_to_end_month : __normal_days_to_end_month)
61
* Calculates the Julian Day Number from the year, month
62
* and day supplied. The calendar used by the supplied
63
* year, month, and day is assumed to be Gregorian Proleptic.
65
* The months January to December are 1 to 12.
66
* Astronomical year numbering is used, thus 1 BC is 0, 2 BC is −1,
67
* and 4713 BC is −4712. In all divisions (except for JD) the floor
68
* function is applied to the quotient (for dates since
69
* March 1, −4800 all quotients are non-negative, so we can also
72
* a = (14 - month) / 12
75
* JDN = day + ((153m + 2) / 5) + 365y + (y / 4) - (y / 100) + (y / 400) - 32045
77
* @cite http://en.wikipedia.org/wiki/Julian_day#Calculation
81
* Year month and day values are assumed to be valid. This
82
* method does no bounds checking or validation.
85
* @param Month of date
88
int64_t julian_day_number_from_gregorian_date(uint32_t year, uint32_t month, uint32_t day)
91
int64_t a= (14 - month) / 12;
92
int64_t y= year + 4800 - a;
93
int64_t m= month + (12 * a) - 3;
95
day_number= day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - (y / 100) + (y / 400) - 32045;
100
* Translates an absolute day number to a
101
* Julian day number. Note that a Julian day number
102
* is not the same as a date in the Julian proleptic calendar.
104
* @param The absolute day number
106
int64_t absolute_day_number_to_julian_day_number(int64_t absolute_day)
108
return absolute_day + JULIAN_DAY_NUMBER_AT_ABSOLUTE_DAY_ONE;
112
* Translates a Julian day number to an
113
* absolute day number. Note that a Julian day number
114
* is not the same as a date in the Julian proleptic calendar.
116
* @param The Julian day number
118
int64_t julian_day_number_to_absolute_day_number(int64_t julian_day)
120
return julian_day - JULIAN_DAY_NUMBER_AT_ABSOLUTE_DAY_ONE;
124
* Given a supplied Julian Day Number, populates a year, month, and day
125
* with the date in the Gregorian Proleptic calendar which corresponds to
126
* the given Julian Day Number.
128
* @cite Algorithm from http://en.wikipedia.org/wiki/Julian_day
130
* @param Julian Day Number
131
* @param Pointer to year to populate
132
* @param Pointer to month to populate
133
* @param Pointer to the day to populate
135
void gregorian_date_from_julian_day_number(int64_t julian_day
137
, uint32_t *month_out
140
int64_t j = julian_day + 32044;
141
int64_t g = j / 146097;
142
int64_t dg = j % 146097;
143
int64_t c = (dg / 36524 + 1) * 3 / 4;
144
int64_t dc = dg - c * 36524;
145
int64_t b = dc / 1461;
146
int64_t db = dc % 1461;
147
int64_t a = (db / 365 + 1) * 3 / 4;
148
int64_t da = db - a * 365;
149
int64_t y = g * 400 + c * 100 + b * 4 + a;
150
int64_t m = (da * 5 + 308) / 153 - 2;
151
int64_t d = da - (m + 4) * 153 / 5 + 122;
152
int64_t Y = y - 4800 + (m + 2) / 12;
153
int64_t M = (m + 2) % 12 + 1;
154
int64_t D = (int64_t)((double)d + 1.5);
156
/* Push out parameters */
157
*year_out= (uint32_t) Y;
158
*month_out= (uint32_t) M;
159
*day_out= (uint32_t) D;
163
* Given a supplied Absolute Day Number, populates a year, month, and day
164
* with the date in the Gregorian Proleptic calendar which corresponds to
165
* the given Absolute Day Number.
167
* @param Absolute Day Number
168
* @param Pointer to year to populate
169
* @param Pointer to month to populate
170
* @param Pointer to the day to populate
172
void gregorian_date_from_absolute_day_number(int64_t absolute_day
174
, uint32_t *month_out
177
gregorian_date_from_julian_day_number(
178
absolute_day_number_to_julian_day_number(absolute_day)
185
* Functions to calculate the number of days in a
186
* particular year. The number of days in a year
187
* depends on the calendar used for the date.
189
* For the Julian proleptic calendar, a leap year
190
* is one which is evenly divisible by 4.
192
* For the Gregorian proleptic calendar, a leap year
193
* is one which is evenly divisible by 4, and if
194
* the year is evenly divisible by 100, it must also be evenly
199
* Returns the number of days in a particular year
200
* depending on the supplied calendar.
202
* @param year to evaluate
203
* @param calendar to use
205
inline uint32_t days_in_year(const uint32_t year, enum calendar calendar)
207
if (calendar == GREGORIAN)
208
return days_in_year_gregorian(year);
209
return days_in_year_julian(year);
213
* Returns the number of days in a particular Julian calendar year.
215
* @param year to evaluate
217
inline uint32_t days_in_year_julian(const uint32_t year)
219
/* Short-circuit. No odd years can be leap years... */
220
return (year & 3) == 0;
224
* Returns the number of days in a particular Gregorian year.
226
* @param year to evaluate
228
inline uint32_t days_in_year_gregorian(const uint32_t year)
230
/* Short-circuit. No odd years can be leap years... */
235
&& (year % 100 || ((year % 400 == 0) && year))
242
* Returns the number of the day in a week.
246
* Day Day Number Sunday first day?
247
* -------------- ----------- -----------------
263
* @param Julian Day Number
264
* @param Consider Sunday the first day of the week?
266
uint32_t day_of_week(int64_t day_number
267
, bool sunday_is_first_day_of_week)
269
uint32_t tmp= (uint32_t) (day_number % 7);
270
/* 0 returned from above modulo is a Monday */
271
if (sunday_is_first_day_of_week)
272
tmp= (tmp == 6 ? 0 : tmp + 1);
277
* Given a year, month, and day, returns whether the date is
278
* valid for the Gregorian proleptic calendar.
284
bool is_valid_gregorian_date(uint32_t year, uint32_t month, uint32_t day)
289
return (day <= __normal_days_in_month[month - 1]);
292
const uint32_t *p_months= __DAYS_IN_MONTH(year, (enum calendar) GREGORIAN);
293
return (day <= p_months[1]);
298
* Returns the number of days in a month, given
299
* a year and a month in the Gregorian calendar.
301
* @param Year in Gregorian Proleptic calendar
302
* @param Month in date
304
uint32_t days_in_gregorian_year_month(uint32_t year, uint32_t month)
306
const uint32_t *p_months= __DAYS_IN_MONTH(year, GREGORIAN);
307
return p_months[month - 1];
311
* Returns whether the supplied date components are within the
312
* range of the UNIX epoch.
314
* Times in the range of 1970-01-01T00:00:00 to 2038-01-19T03:14:07
323
bool in_unix_epoch_range(uint32_t year
330
if (month == 0 || day == 0)
332
if (year < UNIX_EPOCH_MAX_YEARS
333
&& year >= UNIX_EPOCH_MIN_YEARS)
335
if (year < UNIX_EPOCH_MIN_YEARS)
337
if (year == UNIX_EPOCH_MAX_YEARS)
347
/* We are on the final day of UNIX Epoch */
348
uint32_t seconds= (hour * 60 * 60)
351
if (seconds <= ((3 * 60 * 60) + (14 * 60) + 7))
360
* Returns the number of the week from a supplied year, month, and
361
* date in the Gregorian proleptic calendar. We use strftime() and
362
* the %U, %W, and %V format specifiers depending on the value
363
* of the sunday_is_first_day_of_week parameter.
365
* @param Subject year
366
* @param Subject month
368
* @param Is sunday the first day of the week?
369
* @param Pointer to a uint32_t to hold the resulting year, which
370
* may be incremented or decremented depending on flags
372
uint32_t week_number_from_gregorian_date(uint32_t year
375
, bool sunday_is_first_day_of_week)
377
struct tm broken_time;
379
broken_time.tm_year= year;
380
broken_time.tm_mon= month - 1; /* struct tm has non-ordinal months */
381
broken_time.tm_mday= day;
383
/* fill out the rest of our tm fields. */
384
(void) mktime(&broken_time);
386
char result[3]; /* 3 is enough space for a max 2-digit week number */
387
size_t result_len= strftime(result
389
, (sunday_is_first_day_of_week ? "%U" : "%W")
393
return (uint32_t) atoi(result);
398
* Returns the ISO week number of a supplied year, month, and
399
* date in the Gregorian proleptic calendar. We use strftime() and
400
* the %V format specifier to do the calculation, which yields a
401
* correct ISO 8601:1988 week number.
403
* The final year_out parameter is a pointer to an integer which will
404
* be set to the year in which the week belongs, according to ISO8601:1988,
405
* which may be different from the Gregorian calendar year.
407
* @see http://en.wikipedia.org/wiki/ISO_8601
409
* @param Subject year
410
* @param Subject month
412
* @param Pointer to a uint32_t to hold the resulting year, which
413
* may be incremented or decremented depending on flags
415
uint32_t iso_week_number_from_gregorian_date(uint32_t year
418
, uint32_t *year_out)
420
struct tm broken_time;
422
if (year_out != NULL)
425
broken_time.tm_year= year;
426
broken_time.tm_mon= month - 1; /* struct tm has non-ordinal months */
427
broken_time.tm_mday= day;
429
/* fill out the rest of our tm fields. */
430
(void) mktime(&broken_time);
432
char result[3]; /* 3 is enough space for a max 2-digit week number */
433
size_t result_len= strftime(result
440
return 0; /* Not valid for ISO8601:1988 */
442
uint32_t week_number= (uint32_t) atoi(result);
445
* ISO8601:1988 states that if the first week in January
446
* does not contain 4 days, then the resulting week number
447
* shall be 52 or 53, depending on the number of days in the
448
* previous year. In this case, we adjust the outbound
449
* year parameter down a year.
451
if (year_out != NULL)
452
if (week_number == 53 || week_number == 52)
460
* Takes a number in the form [YY]YYMM and converts it into
461
* a number of months.
463
* @param Period in the form [YY]YYMM
465
uint32_t year_month_to_months(uint32_t year_month)
470
uint32_t years= year_month / 100;
471
if (years < CALENDAR_YY_PART_YEAR)
473
else if (years < 100)
476
uint32_t months= year_month % 100;
477
return (years * 12) + (months - 1);
481
* Takes a number of months and converts it to
482
* a period in the form YYYYMM.
484
* @param Number of months
486
uint32_t months_to_year_month(uint32_t months)
491
uint32_t years= (months / 12);
494
years+= (years < CALENDAR_YY_PART_YEAR) ? 2000 : 1900;
496
return (years * 100) + (months % 12) + 1;
499
} /* namespace drizzled */