ab8fc1ac45294c437516a31436fe6fd4e711806d
[kopensolaris-gnu/glibc.git] / time / localtime.c
1 /* Convert `time_t' to `struct tm' in local time zone.
2    Copyright (C) 1991, 92, 93, 95, 96, 97 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <errno.h>
21 #include <time.h>
22 #include <libc-lock.h>
23
24 /* The C Standard says that localtime and gmtime return the same pointer.  */
25 struct tm _tmbuf;
26
27 /* Prototype for the internal function to get information based on TZ.  */
28 extern void __tzset_internal __P ((int always));
29 extern int __tz_compute __P ((time_t timer, struct tm *tp));
30 extern int __tzfile_compute __P ((time_t timer,
31                                   long int *leap_correct, int *leap_hit));
32
33 extern int __use_tzfile;
34
35 /* This lock is defined in tzset.c and locks all the data defined there
36    and in tzfile.c; the internal functions do no locking themselves.
37    This lock is only taken here and in `tzset'.  */
38 __libc_lock_define (extern, __tzset_lock)
39
40
41 /* Return the `struct tm' representation of *TIMER in the local timezone.  */
42 static struct tm *
43 localtime_internal (const time_t *timer, struct tm *tp)
44 {
45   long int leap_correction;
46   int leap_extra_secs;
47
48   if (timer == NULL)
49     {
50       __set_errno (EINVAL);
51       return NULL;
52     }
53
54   if (__use_tzfile)
55     {
56       if (! __tzfile_compute (*timer, &leap_correction, &leap_extra_secs))
57         tp = NULL;
58     }
59   else
60     {
61       tp = __gmtime_r (timer, tp);
62       if (tp && ! __tz_compute (*timer, tp))
63         tp = NULL;
64       leap_correction = 0L;
65       leap_extra_secs = 0;
66     }
67
68   if (tp)
69     {
70       __offtime (timer, __timezone - leap_correction, tp);
71       tp->tm_sec += leap_extra_secs;
72       tp->tm_isdst = __daylight;
73       tp->tm_gmtoff = __timezone;
74       tp->tm_zone = __tzname[__daylight];
75     }
76
77   return tp;
78 }
79
80
81 /* POSIX.1 8.3.7.2 says that localtime_r is not required to set
82    tzname.  This is a good idea since this allows at least a bit more
83    parallelism.  */
84
85 struct tm *
86 localtime (timer)
87      const time_t *timer;
88 {
89   struct tm *result;
90
91   __libc_lock_lock (__tzset_lock);
92
93   /* Update internal database according to current TZ setting.  */
94   __tzset_internal (1);
95
96   result = localtime_internal (timer, &_tmbuf);
97
98   __libc_lock_unlock (__tzset_lock);
99
100   return result;
101 }
102
103
104 struct tm *
105 __localtime_r (timer, tp)
106      const time_t *timer;
107      struct tm *tp;
108 {
109   struct tm *result;
110
111   __libc_lock_lock (__tzset_lock);
112
113   /* Make sure the database is initialized.  */
114   __tzset_internal (0);
115
116   result = localtime_internal (timer, tp);
117
118   __libc_lock_unlock (__tzset_lock);
119
120   return result;
121 }
122 weak_alias (__localtime_r, localtime_r)