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