1 /*****************************************************************************
2 * gmtime_r.c: POSIX gmtime_r() replacement
3 *****************************************************************************
4 * Copyright © 2011-2012 Rémi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
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 Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
29 struct tm
*gmtime_r (const time_t *timep
, struct tm
*tm
)
31 static const unsigned short normal
[12] =
32 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
33 static const unsigned short leap
[12] =
34 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
36 const unsigned short *months
;
38 /* Rebase from 1970 Unix epoch to fictitious year 0 (i.e. would-be
39 * year 1 BC had the Gregorian calendar already existed then) */
40 d
.quot
= 60LL * 60 * 24 * (4 * 146097 + 135140) + *timep
;
42 d
= lldiv (d
.quot
, 60); /* 60 seconds per minute */
50 d
= lldiv (d
.quot
, 60); /* 60 minutes per hour */
53 d
= lldiv (d
.quot
, 24); /* 24 hours per day */
56 tm
->tm_wday
= (d
.quot
+ 6) % 7; /* 7 days per week */
58 d
= lldiv (d
.quot
, 146097); /* 146097 days per 4 centuries */
59 tm
->tm_year
= 400 * d
.quot
;
62 { /* Century with 24 leap years */
66 d
= lldiv (d
.rem
, 36524); /* 36524 days per normal century */
67 tm
->tm_year
+= d
.quot
* 100;
68 if (d
.rem
>= 59) /* not in January or February of year 00 */
69 d
.rem
++; /* insert missing February 29th 00*/
71 tm
->tm_year
-= 1900; /* Rebase to 1900 for struct tm */
73 d
= lldiv (d
.rem
, 1461); /* 1461 days per 4 years */
74 tm
->tm_year
+= 4 * d
.quot
;
81 d
= lldiv (d
.rem
, 365); /* 365 days per normal year */
82 tm
->tm_year
+= d
.quot
;
89 for (tm
->tm_mon
= 0; d
.rem
>= months
[tm
->tm_mon
]; tm
->tm_mon
++)
90 d
.rem
-= months
[tm
->tm_mon
]; /* 28 to 31 days in a month */
91 tm
->tm_mday
= d
.rem
+ 1;
93 tm
->tm_isdst
= 0; /* UTC time */