1 | /* time.c -- Time and date
|
---|
2 | Copyright (c) 1994-1995 by Eberhard Mattes
|
---|
3 |
|
---|
4 | This file is part of emx.
|
---|
5 |
|
---|
6 | emx is free software; you can redistribute it and/or modify it
|
---|
7 | under the terms of the GNU General Public License as published by
|
---|
8 | the Free Software Foundation; either version 2, or (at your option)
|
---|
9 | any later version.
|
---|
10 |
|
---|
11 | emx 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 General Public License for more details.
|
---|
15 |
|
---|
16 | You should have received a copy of the GNU General Public License
|
---|
17 | along with emx; see the file COPYING. If not, write to
|
---|
18 | the Free Software Foundation, 59 Temple Place - Suite 330,
|
---|
19 | Boston, MA 02111-1307, USA.
|
---|
20 |
|
---|
21 | As special exception, emx.dll can be distributed without source code
|
---|
22 | unless it has been changed. If you modify emx.dll, this exception
|
---|
23 | no longer applies and you must remove this paragraph from all source
|
---|
24 | files for emx.dll. */
|
---|
25 |
|
---|
26 |
|
---|
27 | #define INCL_DOSMISC
|
---|
28 | #include <os2emx.h>
|
---|
29 | #include "emxdll.h"
|
---|
30 | #include <limits.h>
|
---|
31 | #include <sys/timeb.h>
|
---|
32 | #include <sys/time.h>
|
---|
33 |
|
---|
34 |
|
---|
35 | /* Day number, relative to 01-Jan-1970, of 01-Jan for the years 1970
|
---|
36 | through 2106 */
|
---|
37 |
|
---|
38 | static ULONG const year_table[] =
|
---|
39 | {
|
---|
40 | 0, 365, 730, 1096, 1461, 1826, 2191, 2557, 2922, 3287, 3652, 4018,
|
---|
41 | 4383, 4748, 5113, 5479, 5844, 6209, 6574, 6940, 7305, 7670, 8035,
|
---|
42 | 8401, 8766, 9131, 9496, 9862, 10227, 10592, 10957, 11323, 11688,
|
---|
43 | 12053, 12418, 12784, 13149, 13514, 13879, 14245, 14610, 14975,
|
---|
44 | 15340, 15706, 16071, 16436, 16801, 17167, 17532, 17897, 18262,
|
---|
45 | 18628, 18993, 19358, 19723, 20089, 20454, 20819, 21184, 21550,
|
---|
46 | 21915, 22280, 22645, 23011, 23376, 23741, 24106, 24472, 24837,
|
---|
47 | 25202, 25567, 25933, 26298, 26663, 27028, 27394, 27759, 28124,
|
---|
48 | 28489, 28855, 29220, 29585, 29950, 30316, 30681, 31046, 31411,
|
---|
49 | 31777, 32142, 32507, 32872, 33238, 33603, 33968, 34333, 34699,
|
---|
50 | 35064, 35429, 35794, 36160, 36525, 36890, 37255, 37621, 37986,
|
---|
51 | 38351, 38716, 39082, 39447, 39812, 40177, 40543, 40908, 41273,
|
---|
52 | 41638, 42004, 42369, 42734, 43099, 43465, 43830, 44195, 44560,
|
---|
53 | 44926, 45291, 45656, 46021, 46387, 46752, 47117, 47482, 47847,
|
---|
54 | 48212, 48577, 48942, 49308, 49673, ULONG_MAX
|
---|
55 | };
|
---|
56 |
|
---|
57 | /* Day number, relative to 01-Jan, of day 01 for January through
|
---|
58 | December. */
|
---|
59 |
|
---|
60 | static ULONG const month_table_non_leap[] =
|
---|
61 | {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, ULONG_MAX};
|
---|
62 |
|
---|
63 | static ULONG const month_table_leap[] =
|
---|
64 | {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, ULONG_MAX};
|
---|
65 |
|
---|
66 |
|
---|
67 | /* Convert a my_datetime structure to Unix time format. */
|
---|
68 |
|
---|
69 | static time_t time2unix (const struct my_datetime *src)
|
---|
70 | {
|
---|
71 | ULONG t, y;
|
---|
72 |
|
---|
73 | if (src->day < 1 || src->day > 31 || src->month < 1 || src->month > 12
|
---|
74 | || src->year < 1970 || src->year > 2105
|
---|
75 | || src->seconds >= 60 || src->minutes >= 60 || src->hours >= 24)
|
---|
76 | return 0;
|
---|
77 |
|
---|
78 | t = src->year * 365 + (src->month - 1) * 31 + src->day;
|
---|
79 | if (src->month <= 2)
|
---|
80 | {
|
---|
81 | /* Jan and Feb. */
|
---|
82 | y = src->year - 1;
|
---|
83 | }
|
---|
84 | else
|
---|
85 | {
|
---|
86 | /* Mar through Dec. */
|
---|
87 | y = src->year;
|
---|
88 | t -= (4 * src->month + 23) / 10;
|
---|
89 | }
|
---|
90 | t += y / 4;
|
---|
91 | t -= (3 * (y / 100 + 1)) / 4;
|
---|
92 | t -= 719528; /* 01-Jan-1970 */
|
---|
93 | return ((t * 24 + src->hours) * 60 + src->minutes) * 60 + src->seconds;
|
---|
94 | }
|
---|
95 |
|
---|
96 |
|
---|
97 | /* Return 1 if Y is a leap year, return 0 otherwise. */
|
---|
98 |
|
---|
99 | static int leap_year (ULONG y)
|
---|
100 | {
|
---|
101 | if (y % 4 != 0)
|
---|
102 | return 0;
|
---|
103 | else if (y % 100 != 0)
|
---|
104 | return 1;
|
---|
105 | else if (y % 400 != 0)
|
---|
106 | return 0;
|
---|
107 | else
|
---|
108 | return 1;
|
---|
109 | }
|
---|
110 |
|
---|
111 |
|
---|
112 | /* Convert a Unix time value to a my_datetime structure. */
|
---|
113 |
|
---|
114 | void unix2time (struct my_datetime *dst, ULONG t)
|
---|
115 | {
|
---|
116 | ULONG lo, hi, i;
|
---|
117 | const ULONG *p;
|
---|
118 |
|
---|
119 | dst->seconds = t % 60; t /= 60;
|
---|
120 | dst->minutes = t % 60; t /= 60;
|
---|
121 | dst->hours = t % 24; t /= 24;
|
---|
122 |
|
---|
123 | /* Find an i such that year_table[i] <= t < year_table[i+1]. */
|
---|
124 |
|
---|
125 | lo = 0; hi = sizeof (year_table) / sizeof (year_table[0]) - 2;
|
---|
126 | for (;;)
|
---|
127 | {
|
---|
128 | i = (lo + hi) / 2;
|
---|
129 | if (year_table[i] > (int)t)
|
---|
130 | hi = i - 1;
|
---|
131 | else if (year_table[i+1] <= (int)t)
|
---|
132 | lo = i + 1;
|
---|
133 | else
|
---|
134 | break;
|
---|
135 | }
|
---|
136 | dst->year = i + 1970;
|
---|
137 | t -= year_table[i];
|
---|
138 |
|
---|
139 | p = (leap_year (dst->year) ? month_table_leap : month_table_non_leap);
|
---|
140 | for (i = 0; t >= p[i+1]; ++i)
|
---|
141 | ;
|
---|
142 | dst->month = i + 1;
|
---|
143 | dst->day = t - p[i] + 1;
|
---|
144 | }
|
---|
145 |
|
---|
146 |
|
---|
147 | /* Get current time and store it in Unix format to the TIMEB structure
|
---|
148 | pointed to by DST. */
|
---|
149 |
|
---|
150 | void do_ftime (struct timeb *dst)
|
---|
151 | {
|
---|
152 | DATETIME dt;
|
---|
153 | struct my_datetime tmp;
|
---|
154 |
|
---|
155 | DosGetDateTime (&dt);
|
---|
156 | tmp.seconds = dt.seconds;
|
---|
157 | tmp.minutes = dt.minutes;
|
---|
158 | tmp.hours = dt.hours;
|
---|
159 | tmp.day = dt.day;
|
---|
160 | tmp.month = dt.month;
|
---|
161 | tmp.year = dt.year;
|
---|
162 | dst->time = time2unix (&tmp);
|
---|
163 | dst->dstflag = 0;
|
---|
164 | dst->millitm = dt.hundredths * 10;
|
---|
165 | dst->timezone = dt.timezone; /* This will be overridden by ftime() */
|
---|
166 | }
|
---|
167 |
|
---|
168 |
|
---|
169 | /* Convert packed time and date to Unix format. */
|
---|
170 |
|
---|
171 | ULONG packed2unix (FDATE date, FTIME time)
|
---|
172 | {
|
---|
173 | struct my_datetime tmp;
|
---|
174 |
|
---|
175 | tmp.seconds = time.twosecs * 2;
|
---|
176 | tmp.minutes = time.minutes;
|
---|
177 | tmp.hours = time.hours;
|
---|
178 | tmp.day = date.day;
|
---|
179 | tmp.month = date.month;
|
---|
180 | tmp.year = date.year + 1980;
|
---|
181 | return time2unix (&tmp);
|
---|
182 | }
|
---|
183 |
|
---|
184 |
|
---|
185 | /* Return the number of 1/100 seconds elapsed since the process has
|
---|
186 | been started.
|
---|
187 |
|
---|
188 | This function no longer tries to use QSV_TIME_LOW and QSV_TIME_HIGH
|
---|
189 | to increase the time before the return value wraps around. Now, it
|
---|
190 | will wrap around after 49 days. */
|
---|
191 |
|
---|
192 | unsigned long long get_clock (int init_flag)
|
---|
193 | {
|
---|
194 | ULONG ms;
|
---|
195 | static ULONG clock0_ms;
|
---|
196 |
|
---|
197 | ms = querysysinfo (QSV_MS_COUNT);
|
---|
198 | if (init_flag)
|
---|
199 | {
|
---|
200 | clock0_ms = ms;
|
---|
201 | return 0;
|
---|
202 | }
|
---|
203 | else
|
---|
204 | return (ms - clock0_ms) / 10;
|
---|
205 | }
|
---|
206 |
|
---|
207 |
|
---|
208 | int do_settime (const struct timeval *tp, int *errnop)
|
---|
209 | {
|
---|
210 | DATETIME dt;
|
---|
211 | struct my_datetime mdt;
|
---|
212 | ULONG rc;
|
---|
213 |
|
---|
214 | /* Preserve the value of DATETIME.timezone. */
|
---|
215 |
|
---|
216 | rc = DosGetDateTime (&dt);
|
---|
217 | if (rc != 0)
|
---|
218 | {
|
---|
219 | *errnop = set_error (rc);
|
---|
220 | return -1;
|
---|
221 | }
|
---|
222 |
|
---|
223 | unix2time (&mdt, tp->tv_sec + tp->tv_usec / 1000000);
|
---|
224 |
|
---|
225 | /* Keep dt.timezone! */
|
---|
226 |
|
---|
227 | dt.day = mdt.day;
|
---|
228 | dt.month = mdt.month;
|
---|
229 | dt.year = mdt.year;
|
---|
230 | dt.weekday = 0;
|
---|
231 |
|
---|
232 | dt.hours = mdt.hours;
|
---|
233 | dt.minutes = mdt.minutes;
|
---|
234 | dt.seconds = mdt.seconds;
|
---|
235 | dt.hundredths = (tp->tv_usec / 10000) % 100;
|
---|
236 |
|
---|
237 | rc = DosSetDateTime (&dt);
|
---|
238 | if (rc != 0)
|
---|
239 | {
|
---|
240 | *errnop = set_error (rc);
|
---|
241 | return -1;
|
---|
242 | }
|
---|
243 | *errnop = 0;
|
---|
244 | return 0;
|
---|
245 | }
|
---|