~drizzle-trunk/drizzle/development

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 */