813.1.2
by Jay Pipes
First function cleanup for temporal handling: YEAR() |
1 |
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
|
2 |
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
|
|
3 |
*
|
|
4 |
* Copyright (C) 2008 Sun Microsystems
|
|
5 |
*
|
|
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.
|
|
10 |
*
|
|
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.
|
|
15 |
*
|
|
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
|
|
19 |
*/
|
|
20 |
||
21 |
/**
|
|
22 |
* @file
|
|
23 |
*
|
|
24 |
* Common functions for dealing with calendrical calculations
|
|
25 |
*/
|
|
26 |
||
1241.9.1
by Monty Taylor
Removed global.h. Fixed all the headers. |
27 |
#include "config.h" |
28 |
||
29 |
#if TIME_WITH_SYS_TIME
|
|
30 |
# include <sys/time.h>
|
|
31 |
# include <time.h>
|
|
32 |
#else
|
|
33 |
# if HAVE_SYS_TIME_H
|
|
34 |
# include <sys/time.h>
|
|
35 |
# else
|
|
36 |
# include <time.h>
|
|
37 |
# endif
|
|
38 |
#endif
|
|
39 |
#include <cstdlib> |
|
40 |
||
813.1.2
by Jay Pipes
First function cleanup for temporal handling: YEAR() |
41 |
#include "drizzled/calendar.h" |
42 |
||
1280.1.10
by Monty Taylor
Put everything in drizzled into drizzled namespace. |
43 |
namespace drizzled |
44 |
{
|
|
45 |
||
813.1.2
by Jay Pipes
First function cleanup for temporal handling: YEAR() |
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}; |
|
51 |
||
52 |
/**
|
|
53 |
* Private utility macro for enabling a switch between
|
|
54 |
* Gregorian and Julian leap year date arrays.
|
|
55 |
*/
|
|
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)
|
|
58 |
||
59 |
||
60 |
/**
|
|
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.
|
|
64 |
*
|
|
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
|
|
70 |
* apply truncation).
|
|
71 |
*
|
|
72 |
* a = (14 - month) / 12
|
|
73 |
* y = year + 4800 - a
|
|
74 |
* m = month + 12a - 3
|
|
75 |
* JDN = day + ((153m + 2) / 5) + 365y + (y / 4) - (y / 100) + (y / 400) - 32045
|
|
76 |
*
|
|
77 |
* @cite http://en.wikipedia.org/wiki/Julian_day#Calculation
|
|
78 |
*
|
|
79 |
* @note
|
|
80 |
*
|
|
81 |
* Year month and day values are assumed to be valid. This
|
|
82 |
* method does no bounds checking or validation.
|
|
83 |
*
|
|
84 |
* @param Year of date
|
|
85 |
* @param Month of date
|
|
86 |
* @param Day of date
|
|
87 |
*/
|
|
88 |
int64_t julian_day_number_from_gregorian_date(uint32_t year, uint32_t month, uint32_t day) |
|
89 |
{
|
|
90 |
int64_t day_number; |
|
91 |
int64_t a= (14 - month) / 12; |
|
92 |
int64_t y= year + 4800 - a; |
|
93 |
int64_t m= month + (12 * a) - 3; |
|
94 |
||
95 |
day_number= day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - (y / 100) + (y / 400) - 32045; |
|
96 |
return day_number; |
|
97 |
}
|
|
98 |
||
99 |
/**
|
|
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.
|
|
103 |
*
|
|
104 |
* @param The absolute day number
|
|
105 |
*/
|
|
106 |
int64_t absolute_day_number_to_julian_day_number(int64_t absolute_day) |
|
107 |
{
|
|
108 |
return absolute_day + JULIAN_DAY_NUMBER_AT_ABSOLUTE_DAY_ONE; |
|
109 |
}
|
|
110 |
||
111 |
/**
|
|
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.
|
|
115 |
*
|
|
116 |
* @param The Julian day number
|
|
117 |
*/
|
|
118 |
int64_t julian_day_number_to_absolute_day_number(int64_t julian_day) |
|
119 |
{
|
|
120 |
return julian_day - JULIAN_DAY_NUMBER_AT_ABSOLUTE_DAY_ONE; |
|
121 |
}
|
|
122 |
||
123 |
/**
|
|
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.
|
|
127 |
*
|
|
128 |
* @cite Algorithm from http://en.wikipedia.org/wiki/Julian_day
|
|
129 |
*
|
|
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
|
|
134 |
*/
|
|
135 |
void gregorian_date_from_julian_day_number(int64_t julian_day |
|
136 |
, uint32_t *year_out |
|
137 |
, uint32_t *month_out |
|
138 |
, uint32_t *day_out) |
|
139 |
{
|
|
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; |
|
902
by Monty Taylor
Added the double cast to shut up the CentOS warnings. |
154 |
int64_t D = (int64_t)((double)d + 1.5); |
813.1.2
by Jay Pipes
First function cleanup for temporal handling: YEAR() |
155 |
|
156 |
/* Push out parameters */
|
|
157 |
*year_out= (uint32_t) Y; |
|
158 |
*month_out= (uint32_t) M; |
|
159 |
*day_out= (uint32_t) D; |
|
160 |
}
|
|
161 |
||
162 |
/**
|
|
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.
|
|
166 |
*
|
|
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
|
|
171 |
*/
|
|
172 |
void gregorian_date_from_absolute_day_number(int64_t absolute_day |
|
173 |
, uint32_t *year_out |
|
174 |
, uint32_t *month_out |
|
175 |
, uint32_t *day_out) |
|
176 |
{
|
|
177 |
gregorian_date_from_julian_day_number( |
|
178 |
absolute_day_number_to_julian_day_number(absolute_day) |
|
179 |
, year_out |
|
180 |
, month_out |
|
181 |
, day_out); |
|
182 |
}
|
|
183 |
||
184 |
/**
|
|
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.
|
|
188 |
*
|
|
189 |
* For the Julian proleptic calendar, a leap year
|
|
190 |
* is one which is evenly divisible by 4.
|
|
191 |
*
|
|
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
|
|
195 |
* divisible by 400.
|
|
196 |
*/
|
|
197 |
||
198 |
/**
|
|
199 |
* Returns the number of days in a particular year
|
|
200 |
* depending on the supplied calendar.
|
|
201 |
*
|
|
202 |
* @param year to evaluate
|
|
203 |
* @param calendar to use
|
|
204 |
*/
|
|
205 |
inline uint32_t days_in_year(const uint32_t year, enum calendar calendar) |
|
206 |
{
|
|
207 |
if (calendar == GREGORIAN) |
|
208 |
return days_in_year_gregorian(year); |
|
209 |
return days_in_year_julian(year); |
|
210 |
}
|
|
211 |
||
212 |
/**
|
|
213 |
* Returns the number of days in a particular Julian calendar year.
|
|
214 |
*
|
|
215 |
* @param year to evaluate
|
|
216 |
*/
|
|
217 |
inline uint32_t days_in_year_julian(const uint32_t year) |
|
218 |
{
|
|
219 |
/* Short-circuit. No odd years can be leap years... */
|
|
220 |
return (year & 3) == 0; |
|
221 |
}
|
|
222 |
||
223 |
/**
|
|
224 |
* Returns the number of days in a particular Gregorian year.
|
|
225 |
*
|
|
226 |
* @param year to evaluate
|
|
227 |
*/
|
|
228 |
inline uint32_t days_in_year_gregorian(const uint32_t year) |
|
229 |
{
|
|
230 |
/* Short-circuit. No odd years can be leap years... */
|
|
231 |
if ((year & 1) == 1) |
|
232 |
return 365; |
|
233 |
return ( |
|
234 |
(year & 3) == 0 |
|
235 |
&& (year % 100 || ((year % 400 == 0) && year)) |
|
236 |
? 366 |
|
237 |
: 365 |
|
238 |
);
|
|
239 |
}
|
|
240 |
||
241 |
/**
|
|
242 |
* Returns the number of the day in a week.
|
|
243 |
*
|
|
244 |
* Return values:
|
|
245 |
*
|
|
246 |
* Day Day Number Sunday first day?
|
|
247 |
* -------------- ----------- -----------------
|
|
248 |
* Sunday 0 true
|
|
249 |
* Monday 1 true
|
|
250 |
* Tuesday 2 true
|
|
251 |
* Wednesday 3 true
|
|
252 |
* Thursday 4 true
|
|
253 |
* Friday 5 true
|
|
254 |
* Saturday 6 true
|
|
255 |
* Sunday 6 false
|
|
256 |
* Monday 0 false
|
|
257 |
* Tuesday 1 false
|
|
258 |
* Wednesday 2 false
|
|
259 |
* Thursday 3 false
|
|
260 |
* Friday 4 false
|
|
261 |
* Saturday 5 false
|
|
262 |
*
|
|
263 |
* @param Julian Day Number
|
|
264 |
* @param Consider Sunday the first day of the week?
|
|
265 |
*/
|
|
266 |
uint32_t day_of_week(int64_t day_number |
|
267 |
, bool sunday_is_first_day_of_week) |
|
268 |
{
|
|
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); |
|
273 |
return tmp; |
|
274 |
}
|
|
275 |
||
276 |
/**
|
|
277 |
* Given a year, month, and day, returns whether the date is
|
|
278 |
* valid for the Gregorian proleptic calendar.
|
|
279 |
*
|
|
280 |
* @param The year
|
|
281 |
* @param The month
|
|
282 |
* @param The day
|
|
283 |
*/
|
|
284 |
bool is_valid_gregorian_date(uint32_t year, uint32_t month, uint32_t day) |
|
285 |
{
|
|
286 |
if (year < 1) |
|
287 |
return false; |
|
288 |
if (month != 2) |
|
289 |
return (day <= __normal_days_in_month[month - 1]); |
|
290 |
else
|
|
291 |
{
|
|
292 |
const uint32_t *p_months= __DAYS_IN_MONTH(year, (enum calendar) GREGORIAN); |
|
293 |
return (day <= p_months[1]); |
|
294 |
}
|
|
295 |
}
|
|
296 |
||
297 |
/**
|
|
298 |
* Returns the number of days in a month, given
|
|
299 |
* a year and a month in the Gregorian calendar.
|
|
300 |
*
|
|
301 |
* @param Year in Gregorian Proleptic calendar
|
|
302 |
* @param Month in date
|
|
303 |
*/
|
|
304 |
uint32_t days_in_gregorian_year_month(uint32_t year, uint32_t month) |
|
305 |
{
|
|
306 |
const uint32_t *p_months= __DAYS_IN_MONTH(year, GREGORIAN); |
|
307 |
return p_months[month - 1]; |
|
308 |
}
|
|
309 |
||
310 |
/**
|
|
311 |
* Returns whether the supplied date components are within the
|
|
312 |
* range of the UNIX epoch.
|
|
313 |
*
|
|
314 |
* Times in the range of 1970-01-01T00:00:00 to 2038-01-19T03:14:07
|
|
315 |
*
|
|
316 |
* @param Year
|
|
317 |
* @param Month
|
|
318 |
* @param Day
|
|
319 |
* @param Hour
|
|
320 |
* @param Minute
|
|
321 |
* @param Second
|
|
322 |
*/
|
|
323 |
bool in_unix_epoch_range(uint32_t year |
|
324 |
, uint32_t month |
|
325 |
, uint32_t day |
|
326 |
, uint32_t hour |
|
327 |
, uint32_t minute |
|
328 |
, uint32_t second) |
|
329 |
{
|
|
330 |
if (month == 0 || day == 0) |
|
331 |
return false; |
|
332 |
if (year < UNIX_EPOCH_MAX_YEARS |
|
333 |
&& year >= UNIX_EPOCH_MIN_YEARS) |
|
334 |
return true; |
|
335 |
if (year < UNIX_EPOCH_MIN_YEARS) |
|
336 |
return false; |
|
337 |
if (year == UNIX_EPOCH_MAX_YEARS) |
|
338 |
{
|
|
339 |
if (month > 1) |
|
340 |
return false; |
|
341 |
if (day > 19) |
|
342 |
return false; |
|
343 |
else if (day < 19) |
|
344 |
return true; |
|
345 |
else
|
|
346 |
{
|
|
347 |
/* We are on the final day of UNIX Epoch */
|
|
348 |
uint32_t seconds= (hour * 60 * 60) |
|
349 |
+ (minute * 60) |
|
350 |
+ (second); |
|
351 |
if (seconds <= ((3 * 60 * 60) + (14 * 60) + 7)) |
|
352 |
return true; |
|
353 |
return false; |
|
354 |
}
|
|
355 |
}
|
|
356 |
return false; |
|
357 |
}
|
|
358 |
||
359 |
/**
|
|
360 |
* Returns the number of the week from a supplied year, month, and
|
|
813.1.22
by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the |
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.
|
|
813.1.2
by Jay Pipes
First function cleanup for temporal handling: YEAR() |
364 |
*
|
365 |
* @param Subject year
|
|
366 |
* @param Subject month
|
|
367 |
* @param Subject day
|
|
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
|
|
371 |
*/
|
|
372 |
uint32_t week_number_from_gregorian_date(uint32_t year |
|
373 |
, uint32_t month |
|
374 |
, uint32_t day |
|
813.1.22
by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the |
375 |
, bool sunday_is_first_day_of_week) |
376 |
{
|
|
377 |
struct tm broken_time; |
|
378 |
||
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; |
|
382 |
||
383 |
/* fill out the rest of our tm fields. */
|
|
384 |
(void) mktime(&broken_time); |
|
385 |
||
386 |
char result[3]; /* 3 is enough space for a max 2-digit week number */ |
|
387 |
size_t result_len= strftime(result |
|
388 |
, sizeof(result) |
|
389 |
, (sunday_is_first_day_of_week ? "%U" : "%W") |
|
390 |
, &broken_time); |
|
391 |
||
392 |
if (result_len != 0) |
|
393 |
return (uint32_t) atoi(result); |
|
394 |
return 0; |
|
395 |
}
|
|
396 |
||
397 |
/**
|
|
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.
|
|
402 |
*
|
|
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.
|
|
406 |
*
|
|
407 |
* @see http://en.wikipedia.org/wiki/ISO_8601
|
|
408 |
*
|
|
409 |
* @param Subject year
|
|
410 |
* @param Subject month
|
|
411 |
* @param Subject day
|
|
412 |
* @param Pointer to a uint32_t to hold the resulting year, which
|
|
413 |
* may be incremented or decremented depending on flags
|
|
414 |
*/
|
|
415 |
uint32_t iso_week_number_from_gregorian_date(uint32_t year |
|
416 |
, uint32_t month |
|
417 |
, uint32_t day |
|
418 |
, uint32_t *year_out) |
|
419 |
{
|
|
420 |
struct tm broken_time; |
|
421 |
||
422 |
if (year_out != NULL) |
|
423 |
*year_out= year; |
|
424 |
||
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; |
|
428 |
||
429 |
/* fill out the rest of our tm fields. */
|
|
430 |
(void) mktime(&broken_time); |
|
431 |
||
432 |
char result[3]; /* 3 is enough space for a max 2-digit week number */ |
|
433 |
size_t result_len= strftime(result |
|
434 |
, sizeof(result) |
|
435 |
, "%V" |
|
436 |
, &broken_time); |
|
437 |
||
438 |
||
439 |
if (result_len == 0) |
|
440 |
return 0; /* Not valid for ISO8601:1988 */ |
|
441 |
||
442 |
uint32_t week_number= (uint32_t) atoi(result); |
|
443 |
||
444 |
/*
|
|
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.
|
|
450 |
*/
|
|
451 |
if (year_out != NULL) |
|
452 |
if (week_number == 53 || week_number == 52) |
|
453 |
if (month == 1) |
|
454 |
*year_out--; |
|
455 |
||
456 |
return week_number; |
|
813.1.2
by Jay Pipes
First function cleanup for temporal handling: YEAR() |
457 |
}
|
907.1.3
by Jay Pipes
Merging in old r903 temporal changes |
458 |
|
459 |
/**
|
|
460 |
* Takes a number in the form [YY]YYMM and converts it into
|
|
461 |
* a number of months.
|
|
462 |
*
|
|
463 |
* @param Period in the form [YY]YYMM
|
|
464 |
*/
|
|
465 |
uint32_t year_month_to_months(uint32_t year_month) |
|
466 |
{
|
|
467 |
if (year_month == 0) |
|
468 |
return 0L; |
|
469 |
||
470 |
uint32_t years= year_month / 100; |
|
471 |
if (years < CALENDAR_YY_PART_YEAR) |
|
472 |
years+= 2000; |
|
473 |
else if (years < 100) |
|
474 |
years+= 1900; |
|
475 |
||
476 |
uint32_t months= year_month % 100; |
|
477 |
return (years * 12) + (months - 1); |
|
478 |
}
|
|
479 |
||
480 |
/**
|
|
481 |
* Takes a number of months and converts it to
|
|
482 |
* a period in the form YYYYMM.
|
|
483 |
*
|
|
484 |
* @param Number of months
|
|
485 |
*/
|
|
486 |
uint32_t months_to_year_month(uint32_t months) |
|
487 |
{
|
|
488 |
if (months == 0L) |
|
489 |
return 0L; |
|
490 |
||
491 |
uint32_t years= (months / 12); |
|
492 |
||
493 |
if (years < 100) |
|
494 |
years+= (years < CALENDAR_YY_PART_YEAR) ? 2000 : 1900; |
|
495 |
||
496 |
return (years * 100) + (months % 12) + 1; |
|
497 |
}
|
|
1280.1.10
by Monty Taylor
Put everything in drizzled into drizzled namespace. |
498 |
|
499 |
} /* namespace drizzled */ |