1 /*
2 Copyright (c) 1994 Cygnus Support.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms are permitted
6 provided that the above copyright notice and this paragraph are
7 duplicated in all such forms and that any documentation,
8 and/or other materials related to such
9 distribution and use acknowledge that the software was developed
10 at Cygnus Support, Inc. Cygnus Support, Inc. may not be used to
11 endorse or promote products derived from this software without
12 specific prior written permission.
13 THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17 /*
18 * localtime_r.c
19 * Original Author: Adapted from tzcode maintained by Arthur David Olson.
20 * Modifications:
21 * - Changed to mktm_r and added __tzcalc_limits - 04/10/02, Jeff Johnston
22 * - Fixed bug in mday computations - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
23 * - Fixed bug in __tzcalc_limits - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
24 * - Implement localtime_r() with gmtime_r() and the conditional code moved
25 * from _mktm_r() - 05/09/14, Freddie Chopin <freddie_chopin@op.pl>
26 *
27 * Converts the calendar time pointed to by tim_p into a broken-down time
28 * expressed as local time. Returns a pointer to a structure containing the
29 * broken-down time.
30 */
31
32 #include "local.h"
33
34 struct tm *
localtime_r(const time_t * __restrict tim_p,struct tm * __restrict res)35 localtime_r (const time_t *__restrict tim_p,
36 struct tm *__restrict res)
37 {
38 long offset;
39 int hours, mins, secs;
40 int year;
41 __tzinfo_type *const tz = __gettzinfo ();
42 const uint8_t *ip;
43
44 res = gmtime_r (tim_p, res);
45
46 year = res->tm_year + YEAR_BASE;
47 ip = __month_lengths[isleap(year)];
48
49 TZ_LOCK;
50 _tzset_unlocked ();
51 if (_daylight)
52 {
53 if (year == tz->__tzyear || __tzcalc_limits (year))
54 res->tm_isdst = (tz->__tznorth
55 ? (*tim_p >= tz->__tzrule[0].change
56 && *tim_p < tz->__tzrule[1].change)
57 : (*tim_p >= tz->__tzrule[0].change
58 || *tim_p < tz->__tzrule[1].change));
59 else
60 res->tm_isdst = -1;
61 }
62 else
63 res->tm_isdst = 0;
64
65 offset = (res->tm_isdst == 1
66 ? tz->__tzrule[1].offset
67 : tz->__tzrule[0].offset);
68
69 hours = (int) (offset / SECSPERHOUR);
70 offset = offset % SECSPERHOUR;
71
72 mins = (int) (offset / SECSPERMIN);
73 secs = (int) (offset % SECSPERMIN);
74
75 res->tm_sec -= secs;
76 res->tm_min -= mins;
77 res->tm_hour -= hours;
78
79 if (res->tm_sec >= SECSPERMIN)
80 {
81 res->tm_min += 1;
82 res->tm_sec -= SECSPERMIN;
83 }
84 else if (res->tm_sec < 0)
85 {
86 res->tm_min -= 1;
87 res->tm_sec += SECSPERMIN;
88 }
89 if (res->tm_min >= MINSPERHOUR)
90 {
91 res->tm_hour += 1;
92 res->tm_min -= MINSPERHOUR;
93 }
94 else if (res->tm_min < 0)
95 {
96 res->tm_hour -= 1;
97 res->tm_min += MINSPERHOUR;
98 }
99 if (res->tm_hour >= HOURSPERDAY)
100 {
101 ++res->tm_yday;
102 ++res->tm_wday;
103 if (res->tm_wday > 6)
104 res->tm_wday = 0;
105 ++res->tm_mday;
106 res->tm_hour -= HOURSPERDAY;
107 if (res->tm_mday > ip[res->tm_mon])
108 {
109 res->tm_mday -= ip[res->tm_mon];
110 res->tm_mon += 1;
111 if (res->tm_mon == 12)
112 {
113 res->tm_mon = 0;
114 res->tm_year += 1;
115 res->tm_yday = 0;
116 }
117 }
118 }
119 else if (res->tm_hour < 0)
120 {
121 res->tm_yday -= 1;
122 res->tm_wday -= 1;
123 if (res->tm_wday < 0)
124 res->tm_wday = 6;
125 res->tm_mday -= 1;
126 res->tm_hour += 24;
127 if (res->tm_mday == 0)
128 {
129 res->tm_mon -= 1;
130 if (res->tm_mon < 0)
131 {
132 res->tm_mon = 11;
133 res->tm_year -= 1;
134 res->tm_yday = 364 + isleap(res->tm_year + YEAR_BASE);
135 }
136 res->tm_mday = ip[res->tm_mon];
137 }
138 }
139 TZ_UNLOCK;
140
141 return (res);
142 }
143