~posulliv/drizzle/memcached_applier

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
27
#include "drizzled/global.h"
28
#include "drizzled/calendar.h"
29
30
/** Static arrays for number of days in a month and their "day ends" */
31
static const uint32_t __leap_days_in_month[12]=       {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
32
static const uint32_t __normal_days_in_month[12]=     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
33
static const uint32_t __leap_days_to_end_month[13]=   {0, 31, 60, 91, 121, 151, 182, 213, 244, 274, 305, 335, 366};
34
static const uint32_t __normal_days_to_end_month[13]= {0, 31, 59, 90, 120, 150, 181, 212, 243, 273, 304, 334, 365};
35
36
/** 
37
 * Private utility macro for enabling a switch between
38
 * Gregorian and Julian leap year date arrays.
39
 */
40
#define __DAYS_IN_MONTH(y, c) (const uint32_t *) (IS_LEAP_YEAR((y),(c)) ? __leap_days_in_month : __normal_days_in_month)
41
#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)
42
43
44
/**
45
 * Calculates the Julian Day Number from the year, month 
46
 * and day supplied.  The calendar used by the supplied
47
 * year, month, and day is assumed to be Gregorian Proleptic.
48
 *
49
 * The months January to December are 1 to 12. 
50
 * Astronomical year numbering is used, thus 1 BC is 0, 2 BC is −1, 
51
 * and 4713 BC is −4712. In all divisions (except for JD) the floor 
52
 * function is applied to the quotient (for dates since 
53
 * March 1, −4800 all quotients are non-negative, so we can also 
54
 * apply truncation).
55
 *
56
 * a = (14 - month) / 12
57
 * y = year + 4800 - a
58
 * m = month + 12a - 3
59
 * JDN = day + ((153m + 2) / 5) + 365y + (y / 4) - (y / 100) + (y / 400) - 32045
60
 *
61
 * @cite http://en.wikipedia.org/wiki/Julian_day#Calculation
62
 *
63
 * @note
64
 *
65
 * Year month and day values are assumed to be valid.  This 
66
 * method does no bounds checking or validation.
67
 *
68
 * @param Year of date
69
 * @param Month of date
70
 * @param Day of date
71
 */
72
int64_t julian_day_number_from_gregorian_date(uint32_t year, uint32_t month, uint32_t day)
73
{
74
  int64_t day_number;
75
  int64_t a= (14 - month) / 12;
76
  int64_t y= year + 4800 - a;
77
  int64_t m= month + (12 * a) - 3;
78
79
  day_number= day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - (y / 100) + (y / 400) - 32045;
80
  return day_number;
81
}
82
83
/**
84
 * Translates an absolute day number to a 
85
 * Julian day number.  Note that a Julian day number
86
 * is not the same as a date in the Julian proleptic calendar.
87
 *
88
 * @param The absolute day number
89
 */
90
int64_t absolute_day_number_to_julian_day_number(int64_t absolute_day)
91
{
92
  return absolute_day + JULIAN_DAY_NUMBER_AT_ABSOLUTE_DAY_ONE;
93
}
94
95
/**
96
 * Translates a Julian day number to an 
97
 * absolute day number.  Note that a Julian day number
98
 * is not the same as a date in the Julian proleptic calendar.
99
 *
100
 * @param The Julian day number
101
 */
102
int64_t julian_day_number_to_absolute_day_number(int64_t julian_day)
103
{
104
  return julian_day - JULIAN_DAY_NUMBER_AT_ABSOLUTE_DAY_ONE;
105
}
106
107
/**
108
 * Given a supplied Julian Day Number, populates a year, month, and day
109
 * with the date in the Gregorian Proleptic calendar which corresponds to
110
 * the given Julian Day Number.
111
 *
112
 * @cite Algorithm from http://en.wikipedia.org/wiki/Julian_day
113
 *
114
 * @param Julian Day Number
115
 * @param Pointer to year to populate
116
 * @param Pointer to month to populate
117
 * @param Pointer to the day to populate
118
 */
119
void gregorian_date_from_julian_day_number(int64_t julian_day
120
                                         , uint32_t *year_out
121
                                         , uint32_t *month_out
122
                                         , uint32_t *day_out)
123
{
124
  int64_t j = julian_day + 32044;
125
  int64_t g = j / 146097;
126
  int64_t dg = j % 146097;
127
  int64_t c = (dg / 36524 + 1) * 3 / 4;
128
  int64_t dc = dg - c * 36524;
129
  int64_t b = dc / 1461;
130
  int64_t db = dc % 1461;
131
  int64_t a = (db / 365 + 1) * 3 / 4;
132
  int64_t da = db - a * 365;
133
  int64_t y = g * 400 + c * 100 + b * 4 + a;
134
  int64_t m = (da * 5 + 308) / 153 - 2;
135
  int64_t d = da - (m + 4) * 153 / 5 + 122;
136
  int64_t Y = y - 4800 + (m + 2) / 12;
137
  int64_t M = (m + 2) % 12 + 1;
902 by Monty Taylor
Added the double cast to shut up the CentOS warnings.
138
  int64_t D = (int64_t)((double)d + 1.5);
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
139
140
  /* Push out parameters */
141
  *year_out= (uint32_t) Y;
142
  *month_out= (uint32_t) M;
143
  *day_out= (uint32_t) D;
144
}
145
146
/**
147
 * Given a supplied Absolute Day Number, populates a year, month, and day
148
 * with the date in the Gregorian Proleptic calendar which corresponds to
149
 * the given Absolute Day Number.
150
 *
151
 * @param Absolute Day Number
152
 * @param Pointer to year to populate
153
 * @param Pointer to month to populate
154
 * @param Pointer to the day to populate
155
 */
156
void gregorian_date_from_absolute_day_number(int64_t absolute_day
157
                                           , uint32_t *year_out
158
                                           , uint32_t *month_out
159
                                           , uint32_t *day_out)
160
{
161
  gregorian_date_from_julian_day_number(
162
      absolute_day_number_to_julian_day_number(absolute_day)
163
    , year_out
164
    , month_out
165
    , day_out);
166
}
167
168
/**
169
 * Functions to calculate the number of days in a 
170
 * particular year.  The number of days in a year 
171
 * depends on the calendar used for the date.
172
 *
173
 * For the Julian proleptic calendar, a leap year 
174
 * is one which is evenly divisible by 4.
175
 *
176
 * For the Gregorian proleptic calendar, a leap year
177
 * is one which is evenly divisible by 4, and if
178
 * the year is evenly divisible by 100, it must also be evenly
179
 * divisible by 400.
180
 */
181
182
/**
183
 * Returns the number of days in a particular year
184
 * depending on the supplied calendar.
185
 *
186
 * @param year to evaluate
187
 * @param calendar to use
188
 */
189
inline uint32_t days_in_year(const uint32_t year, enum calendar calendar)
190
{
191
  if (calendar == GREGORIAN)
192
    return days_in_year_gregorian(year);
193
  return days_in_year_julian(year);
194
}
195
196
/**
197
 * Returns the number of days in a particular Julian calendar year.
198
 *
199
 * @param year to evaluate
200
 */
201
inline uint32_t days_in_year_julian(const uint32_t year)
202
{
203
  /* Short-circuit. No odd years can be leap years... */
204
  return (year & 3) == 0;
205
}
206
207
/**
208
 * Returns the number of days in a particular Gregorian year.
209
 *
210
 * @param year to evaluate
211
 */
212
inline uint32_t days_in_year_gregorian(const uint32_t year)
213
{
214
  /* Short-circuit. No odd years can be leap years... */
215
  if ((year & 1) == 1)
216
    return 365;
217
  return (            
218
            (year & 3) == 0 
219
            && (year % 100 || ((year % 400 == 0) && year)) 
220
            ? 366 
221
            : 365
222
         );
223
}
224
225
/**
226
 * Returns the number of the day in a week.
227
 *
228
 * Return values:
229
 *
230
 * Day            Day Number  Sunday first day?
231
 * -------------- ----------- -----------------
232
 * Sunday         0           true
233
 * Monday         1           true
234
 * Tuesday        2           true
235
 * Wednesday      3           true
236
 * Thursday       4           true
237
 * Friday         5           true
238
 * Saturday       6           true
239
 * Sunday         6           false
240
 * Monday         0           false
241
 * Tuesday        1           false
242
 * Wednesday      2           false
243
 * Thursday       3           false
244
 * Friday         4           false
245
 * Saturday       5           false
246
 *
247
 * @param Julian Day Number
248
 * @param Consider Sunday the first day of the week?
249
 */
250
uint32_t day_of_week(int64_t day_number
251
                   , bool sunday_is_first_day_of_week)
252
{
253
  uint32_t tmp= (uint32_t) (day_number % 7);
254
  /* 0 returned from above modulo is a Monday */
255
  if (sunday_is_first_day_of_week)
256
    tmp= (tmp == 6 ? 0 : tmp + 1);
257
  return tmp;
258
}
259
260
/**
261
 * Given a year, month, and day, returns whether the date is 
262
 * valid for the Gregorian proleptic calendar.
263
 *
264
 * @param The year
265
 * @param The month
266
 * @param The day
267
 */
268
bool is_valid_gregorian_date(uint32_t year, uint32_t month, uint32_t day)
269
{
270
  if (year < 1)
271
    return false;
272
  if (month != 2)
273
    return (day <= __normal_days_in_month[month - 1]);
274
  else
275
  {
276
    const uint32_t *p_months= __DAYS_IN_MONTH(year, (enum calendar) GREGORIAN);
277
    return (day <= p_months[1]);
278
  }
279
}
280
281
/**
282
 * Returns the number of days in a month, given
283
 * a year and a month in the Gregorian calendar.
284
 *
285
 * @param Year in Gregorian Proleptic calendar
286
 * @param Month in date
287
 */
288
uint32_t days_in_gregorian_year_month(uint32_t year, uint32_t month)
289
{
290
  const uint32_t *p_months= __DAYS_IN_MONTH(year, GREGORIAN);
291
  return p_months[month - 1];
292
}
293
294
/**
295
 * Returns whether the supplied date components are within the 
296
 * range of the UNIX epoch.
297
 *
298
 * Times in the range of 1970-01-01T00:00:00 to 2038-01-19T03:14:07
299
 *
300
 * @param Year
301
 * @param Month
302
 * @param Day
303
 * @param Hour
304
 * @param Minute
305
 * @param Second
306
 */
307
bool in_unix_epoch_range(uint32_t year
308
                       , uint32_t month
309
                       , uint32_t day
310
                       , uint32_t hour
311
                       , uint32_t minute
312
                       , uint32_t second)
313
{
314
  if (month == 0 || day == 0)
315
    return false;
316
  if (year < UNIX_EPOCH_MAX_YEARS
317
      && year >= UNIX_EPOCH_MIN_YEARS)
318
    return true;
319
  if (year < UNIX_EPOCH_MIN_YEARS)
320
    return false;
321
  if (year == UNIX_EPOCH_MAX_YEARS)
322
  {
323
    if (month > 1)
324
      return false;
325
    if (day > 19)
326
      return false;
327
    else if (day < 19)
328
      return true;
329
    else
330
    {
331
      /* We are on the final day of UNIX Epoch */
332
      uint32_t seconds= (hour * 60 * 60)
333
                      + (minute * 60)
334
                      + (second);
335
      if (seconds <= ((3 * 60 * 60) + (14 * 60) + 7))
336
        return true;
337
      return false;
338
    }
339
  }
340
  return false;
341
}
342
343
/**
344
 * 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
345
 * date in the Gregorian proleptic calendar.  We use strftime() and
346
 * the %U, %W, and %V format specifiers depending on the value
347
 * of the sunday_is_first_day_of_week parameter.
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
348
 *
349
 * @param Subject year
350
 * @param Subject month
351
 * @param Subject day
352
 * @param Is sunday the first day of the week?
353
 * @param Pointer to a uint32_t to hold the resulting year, which 
354
 *        may be incremented or decremented depending on flags
355
 */
356
uint32_t week_number_from_gregorian_date(uint32_t year
357
                                       , uint32_t month
358
                                       , uint32_t day
813.1.22 by Jay Pipes
default_week_format variable has gone the way of the Dodo, as have the
359
                                       , bool sunday_is_first_day_of_week)
360
{
361
  struct tm broken_time;
362
363
  broken_time.tm_year= year;
364
  broken_time.tm_mon= month - 1; /* struct tm has non-ordinal months */
365
  broken_time.tm_mday= day;
366
367
  /* fill out the rest of our tm fields. */
368
  (void) mktime(&broken_time);
369
370
  char result[3]; /* 3 is enough space for a max 2-digit week number */
371
  size_t result_len= strftime(result
372
                            , sizeof(result)
373
                            , (sunday_is_first_day_of_week ? "%U" : "%W")
374
                            , &broken_time);
375
376
  if (result_len != 0)
377
    return (uint32_t) atoi(result);
378
  return 0;
379
}
380
381
/**
382
 * Returns the ISO week number of a supplied year, month, and
383
 * date in the Gregorian proleptic calendar.  We use strftime() and
384
 * the %V format specifier to do the calculation, which yields a
385
 * correct ISO 8601:1988 week number.
386
 *
387
 * The final year_out parameter is a pointer to an integer which will
388
 * be set to the year in which the week belongs, according to ISO8601:1988, 
389
 * which may be different from the Gregorian calendar year.
390
 *
391
 * @see http://en.wikipedia.org/wiki/ISO_8601
392
 *
393
 * @param Subject year
394
 * @param Subject month
395
 * @param Subject day
396
 * @param Pointer to a uint32_t to hold the resulting year, which 
397
 *        may be incremented or decremented depending on flags
398
 */
399
uint32_t iso_week_number_from_gregorian_date(uint32_t year
400
                                           , uint32_t month
401
                                           , uint32_t day
402
                                           , uint32_t *year_out)
403
{
404
  struct tm broken_time;
405
406
  if (year_out != NULL)
407
    *year_out= year;
408
409
  broken_time.tm_year= year;
410
  broken_time.tm_mon= month - 1; /* struct tm has non-ordinal months */
411
  broken_time.tm_mday= day;
412
413
  /* fill out the rest of our tm fields. */
414
  (void) mktime(&broken_time);
415
416
  char result[3]; /* 3 is enough space for a max 2-digit week number */
417
  size_t result_len= strftime(result
418
                            , sizeof(result)
419
                            , "%V"
420
                            , &broken_time);
421
422
423
  if (result_len == 0)
424
    return 0; /* Not valid for ISO8601:1988 */
425
426
  uint32_t week_number= (uint32_t) atoi(result);
427
428
  /* 
429
   * ISO8601:1988 states that if the first week in January
430
   * does not contain 4 days, then the resulting week number
431
   * shall be 52 or 53, depending on the number of days in the
432
   * previous year.  In this case, we adjust the outbound
433
   * year parameter down a year.
434
   */
435
  if (year_out != NULL)
436
    if (week_number == 53 || week_number == 52)
437
      if (month == 1)
438
        *year_out--;
439
440
  return week_number;
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
441
}
907.1.3 by Jay Pipes
Merging in old r903 temporal changes
442
443
/**
444
 * Takes a number in the form [YY]YYMM and converts it into
445
 * a number of months.
446
 *
447
 * @param Period in the form [YY]YYMM
448
 */
449
uint32_t year_month_to_months(uint32_t year_month)
450
{
451
  if (year_month == 0)
452
    return 0L;
453
454
  uint32_t years= year_month / 100;
455
  if (years < CALENDAR_YY_PART_YEAR)
456
    years+= 2000;
457
  else if (years < 100)
458
    years+= 1900;
459
460
  uint32_t months= year_month % 100;
461
  return (years * 12) + (months - 1);
462
}
463
464
/**
465
 * Takes a number of months and converts it to
466
 * a period in the form YYYYMM.
467
 *
468
 * @param Number of months
469
 */
470
uint32_t months_to_year_month(uint32_t months)
471
{
472
  if (months == 0L)
473
    return 0L;
474
475
  uint32_t years= (months / 12);
476
477
  if (years < 100)
478
    years+= (years < CALENDAR_YY_PART_YEAR) ? 2000 : 1900;
479
480
  return (years * 100) + (months % 12) + 1;
481
}