6
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
8
// Redistribution and use in source and binary forms, with or without
9
// modification, are permitted provided that the following conditions
12
// 1. Redistributions of source code must retain the above copyright
13
// notice, this list of conditions and the following disclaimer.
14
// 2. Redistributions in binary form must reproduce the above copyright
15
// notice, this list of conditions and the following disclaimer in the
16
// documentation and/or other materials provided with the distribution.
17
// 3. Neither the name of the project nor the names of its contributors
18
// may be used to endorse or promote products derived from this software
19
// without specific prior written permission.
21
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
25
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36
#include <drizzled/type/time.h>
37
#include <drizzled/util/gmtime.h>
45
#define SECS_DAY (24L * 60L * 60L)
46
#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
47
#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
48
#define FIRSTSUNDAY(timp) (((timp)->tm_yday - (timp)->tm_wday + 420) % 7)
49
#define FIRSTDAYOF(timp) (((timp)->tm_wday - (timp)->tm_yday + 420) % 7)
51
#define TIME_MAX INT64_MIN
53
int _daylight = 0; // Non-zero if daylight savings time is used
54
long _dstbias = 0; // Offset for Daylight Saving Time
55
type::Time::epoch_t _timezone = 0; // Difference in seconds between GMT and local time
56
const char *_tzname[2] = {"GMT", "GMT"}; // Standard/daylight savings time zone names
60
"Sunday", "Monday", "Tuesday", "Wednesday",
61
"Thursday", "Friday", "Saturday"
64
const char *_days_abbrev[] =
66
"Sun", "Mon", "Tue", "Wed",
70
const char *_months[] =
72
"January", "February", "March",
73
"April", "May", "June",
74
"July", "August", "September",
75
"October", "November", "December"
78
const char *_months_abbrev[] =
86
const int _ytab[2][12] =
88
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
89
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
92
struct tm *gmtime(const type::Time::epoch_t &timer, struct tm *tmbuf)
94
uint64_t dayclock, dayno;
100
dayclock = (uint64_t) timer % SECS_DAY;
101
dayno = (uint64_t) timer / SECS_DAY;
103
tmbuf->tm_sec = dayclock % 60;
104
tmbuf->tm_min = (dayclock % 3600) / 60;
105
tmbuf->tm_hour = dayclock / 3600;
106
tmbuf->tm_wday = (dayno + 4) % 7; // Day 0 was a thursday
107
while (dayno >= (uint64_t) YEARSIZE(year))
109
dayno -= YEARSIZE(year);
112
tmbuf->tm_year = year - YEAR0;
113
tmbuf->tm_yday = dayno;
115
while (dayno >= (uint64_t) _ytab[LEAPYEAR(year)][tmbuf->tm_mon])
117
dayno -= _ytab[LEAPYEAR(year)][tmbuf->tm_mon];
120
tmbuf->tm_mday = dayno + 1;
126
void gmtime(const type::Time::epoch_t &timer, type::Time &tmbuf)
128
uint64_t dayclock, dayno;
129
int32_t year= EPOCH_YR;
136
dayclock= (uint64_t) timer % SECS_DAY;
137
dayno= (uint64_t) timer / SECS_DAY;
139
tmbuf.second= dayclock % 60;
140
tmbuf.minute= (dayclock % 3600) / 60;
141
tmbuf.hour= dayclock / 3600;
142
while (dayno >= (uint64_t) YEARSIZE(year))
144
dayno -= YEARSIZE(year);
148
while (dayno >= (uint64_t) _ytab[LEAPYEAR(year)][tmbuf.month])
150
dayno -= _ytab[LEAPYEAR(year)][tmbuf.month];
155
tmbuf.time_type= type::DRIZZLE_TIMESTAMP_DATETIME;
158
void localtime(const type::Time::epoch_t &timer, type::Time &tmbuf)
160
type::Time::epoch_t t;
162
t = timer - _timezone;
163
return util::gmtime(t, tmbuf);
166
struct tm *localtime(const type::Time::epoch_t &timer, struct tm *tmbuf)
168
type::Time::epoch_t t;
170
t = timer - _timezone;
171
return util::gmtime(t, tmbuf);
174
// We don't use this code.
176
time_t mktime(struct tm *tmbuf)
181
/*unsigned*/ long seconds;
185
tmbuf->tm_min += tmbuf->tm_sec / 60;
187
if (tmbuf->tm_sec < 0)
192
tmbuf->tm_hour += tmbuf->tm_min / 60;
193
tmbuf->tm_min = tmbuf->tm_min % 60;
194
if (tmbuf->tm_min < 0)
199
day = tmbuf->tm_hour / 24;
200
tmbuf->tm_hour= tmbuf->tm_hour % 24;
201
if (tmbuf->tm_hour < 0)
203
tmbuf->tm_hour += 24;
206
tmbuf->tm_year += tmbuf->tm_mon / 12;
208
if (tmbuf->tm_mon < 0)
213
day += (tmbuf->tm_mday - 1);
216
if(--tmbuf->tm_mon < 0)
221
day += _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon];
223
while (day >= _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon])
225
day -= _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon];
226
if (++(tmbuf->tm_mon) == 12)
232
tmbuf->tm_mday = day + 1;
234
if (tmbuf->tm_year < year - YEAR0) return (time_t) -1;
236
day = 0; // Means days since day 0 now
239
// Assume that when day becomes negative, there will certainly
240
// be overflow on seconds.
241
// The check for overflow needs not to be done for leapyears
243
// The code only works when year (1970) is not a leapyear.
244
tm_year = tmbuf->tm_year + YEAR0;
246
if (TIME_MAX / 365 < tm_year - year)
248
day = (tm_year - year) * 365;
249
if (TIME_MAX - day < (tm_year - year) / 4 + 1) overflow++;
250
day += (tm_year - year) / 4 + ((tm_year % 4) && tm_year % 4 < year % 4);
251
day -= (tm_year - year) / 100 + ((tm_year % 100) && tm_year % 100 < year % 100);
252
day += (tm_year - year) / 400 + ((tm_year % 400) && tm_year % 400 < year % 400);
255
while (month < tmbuf->tm_mon)
257
yday += _ytab[LEAPYEAR(tm_year)][month];
260
yday += (tmbuf->tm_mday - 1);
261
if (day + yday < 0) overflow++;
264
tmbuf->tm_yday = yday;
265
tmbuf->tm_wday = (day + 4) % 7; // Day 0 was thursday (4)
267
seconds = ((tmbuf->tm_hour * 60L) + tmbuf->tm_min) * 60L + tmbuf->tm_sec;
269
if ((TIME_MAX - seconds) / SECS_DAY < day) overflow++;
270
seconds += day * SECS_DAY;
272
// Now adjust according to timezone and daylight saving time
273
if (((_timezone > 0) && (TIME_MAX - _timezone < seconds))
274
|| ((_timezone < 0) && (seconds < -_timezone)))
276
seconds += _timezone;
283
if (dst > seconds) overflow++; // dst is always non-negative
286
if (overflow) return (time_t) -1;
288
if ((time_t) seconds != seconds) return (time_t) -1;
289
return (time_t) seconds;
293
} /* namespace util */
294
} /* namespace drizzled */