1 /* PEAK Library
2 *
3 * Copyright (c) 2003, 2004
4 * Stephane Thiell <mbuna@bugged.org>. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30 #define RCSID "$Id: time.c,v 1.3 2004/01/04 23:49:20 mbuna Exp $"
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <peak/time.h>
37 #include "internal.h"
38 #include "task_private.h"
39
40 #include <assert.h>
41 #include <limits.h>
42 #include <stdlib.h>
43 #include <sys/time.h> /* gettimeofday */
44 #include <unistd.h>
45 #ifdef HAVE_TZFILE_H
46 #include <tzfile.h>
47 #endif
48
49 /* Accurate only for the past couple of centuries;
50 * that will probably do. (from FreeBSD)
51 */
52 #define ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
53
54 #ifndef EPOCH_YEAR
55 #define EPOCH_YEAR 1970
56 #elif EPOCH_YEAR != 1970
57 /* Uh ho, funky. */
58 #warning EPOCH_YEAR != 1970
59 #endif
60
61 static inline double
__peak_time_tv2ab(struct timeval * tv)62 __peak_time_tv2ab(struct timeval *tv)
63 {
64 return (double)tv->tv_sec + 1.0E-6 * (double)tv->tv_usec;
65 }
66
67 static double
_peak_time_float()68 _peak_time_float()
69 {
70 struct timeval tv;
71
72 gettimeofday(&tv, NULL);
73 return __peak_time_tv2ab(&tv);
74 }
75
76 time_t
peak_time()77 peak_time()
78 {
79 time_t now;
80 double nowf;
81
82 /* Get from task's cache if possible. */
83 if (_peak_task_time(&now))
84 return now;
85
86 /* No, so get it now. */
87 nowf = _peak_time_float();
88
89 /* Cache it. */
90 _peak_task_set_on_time(nowf);
91 return (time_t)nowf;
92 }
93
94 double
peak_time_float()95 peak_time_float()
96 {
97 double now;
98
99 /* Get from task's cache if possible. */
100 if (_peak_task_time_float(&now))
101 return now;
102
103 /* No, so get it now. */
104 now = _peak_time_float();
105
106 /* Cache it. */
107 _peak_task_set_on_time(now);
108 return now;
109 }
110
111 static const uint16_t days_before_month[16] =
112 {
113 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0
114 };
115
116 static inline uint16_t
__days_before_month(int month,int32_t year,int leap)117 __days_before_month(int month, int32_t year, int leap)
118 {
119 return days_before_month[month] + (2 < month && leap);
120 }
121
122 peak_time_date
peak_time_get_date(double t,peak_tz tz)123 peak_time_get_date(double t, peak_tz tz)
124 {
125 peak_time_date d;
126 double tc = t; /* time with tz correction */
127 int32_t absdays, ydays, b, y;
128 int leap, tci;
129
130 if (tz)
131 tc += (double)peak_tz_get_gmt_offset(tz, (time_t)t);
132
133 absdays = (int32_t)(tc / 86400.0);
134 b = absdays / 146097; /* 400 * 365.2425 */
135 y = b * 400 + EPOCH_YEAR;
136
137 absdays -= b * 146097;
138 while (absdays < 0)
139 {
140 y--;
141 absdays += 365 + ISLEAP(y);
142 }
143
144 for (ydays = 365 + ISLEAP(y); ydays <= absdays;
145 ydays = 365 + ISLEAP(y))
146 {
147 y++;
148 absdays -= ydays;
149 }
150
151 d.year = y;
152 d.month = absdays / 33 + 1;
153 leap = ISLEAP(y);
154
155 while (__days_before_month(d.month + 1, y, leap) <= absdays)
156 d.month++;
157
158 d.day = absdays - __days_before_month(d.month, y, leap) + 1;
159
160 d.second = tc - (double)((int)(tc / 60.0)) * 60.0;
161 if (d.second < 0.0)
162 d.second += 60.0;
163
164 tci = (int)tc;
165 tci /= 60;
166 d.minute = tci - (tci / 60) * 60;
167 if (d.minute < 0)
168 d.minute += 60;
169
170 tci /= 60;
171 d.hour = tci - (tci / 24) * 24;
172 if (d.hour < 0)
173 d.hour += 24;
174
175 return d; /* copy struct */
176 }
177