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