~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/calendar.cc

  • Committer: Monty Taylor
  • Date: 2008-08-01 22:33:44 UTC
  • mto: (236.1.42 codestyle)
  • mto: This revision was merged to the branch mainline in revision 261.
  • Revision ID: monty@inaugust.com-20080801223344-vzhlflfmtijp1imv
First pass at gettexizing the error messages.

Show diffs side-by-side

added added

removed removed

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