Line | Count | Source (jump to first uncovered line) |
1 | | /*- |
2 | | * Copyright (c) 2008 Christos Zoulas |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * 1. Redistributions of source code must retain the above copyright |
9 | | * notice, this list of conditions and the following disclaimer. |
10 | | * 2. Redistributions in binary form must reproduce the above copyright |
11 | | * notice, this list of conditions and the following disclaimer in the |
12 | | * documentation and/or other materials provided with the distribution. |
13 | | * |
14 | | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
15 | | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
16 | | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
18 | | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
19 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
20 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
21 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
22 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
23 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
24 | | * POSSIBILITY OF SUCH DAMAGE. |
25 | | */ |
26 | | |
27 | | #include "file.h" |
28 | | |
29 | | #ifndef lint |
30 | | FILE_RCSID("@(#)$File: cdf_time.c,v 1.24 2023/07/17 15:54:44 christos Exp $") |
31 | | #endif |
32 | | |
33 | | #include <time.h> |
34 | | #ifdef TEST |
35 | | #include <err.h> |
36 | | #endif |
37 | | #include <string.h> |
38 | | |
39 | | #include "cdf.h" |
40 | | |
41 | 4.39M | #define isleap(y) ((((y) % 4) == 0) && \ |
42 | 4.39M | ((((y) % 100) != 0) || (((y) % 400) == 0))) |
43 | | |
44 | | static const int mdays[] = { |
45 | | 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
46 | | }; |
47 | | |
48 | | /* |
49 | | * Return the number of days between jan 01 1601 and jan 01 of year. |
50 | | */ |
51 | | static int |
52 | | cdf_getdays(int year) |
53 | 986 | { |
54 | 986 | int days = 0; |
55 | 986 | int y; |
56 | | |
57 | 4.39M | for (y = CDF_BASE_YEAR; y < year; y++) |
58 | 4.39M | days += isleap(y) + 365; |
59 | | |
60 | 986 | return days; |
61 | 986 | } |
62 | | |
63 | | /* |
64 | | * Return the day within the month |
65 | | */ |
66 | | static int |
67 | | cdf_getday(int year, int days) |
68 | 986 | { |
69 | 986 | size_t m; |
70 | | |
71 | 3.11k | for (m = 0; m < __arraycount(mdays); m++) { |
72 | 3.08k | int sub = mdays[m] + (m == 1 && isleap(year)); |
73 | 3.08k | if (days < sub) |
74 | 955 | return days; |
75 | 2.12k | days -= sub; |
76 | 2.12k | } |
77 | 31 | return days; |
78 | 986 | } |
79 | | |
80 | | /* |
81 | | * Return the 0...11 month number. |
82 | | */ |
83 | | static int |
84 | | cdf_getmonth(int year, int days) |
85 | 986 | { |
86 | 986 | size_t m; |
87 | | |
88 | 3.07k | for (m = 0; m < __arraycount(mdays); m++) { |
89 | 3.07k | days -= mdays[m]; |
90 | 3.07k | if (m == 1 && isleap(year)) |
91 | 104 | days--; |
92 | 3.07k | if (days <= 0) |
93 | 986 | return CAST(int, m); |
94 | 3.07k | } |
95 | 0 | return CAST(int, m); |
96 | 986 | } |
97 | | |
98 | | int |
99 | | cdf_timestamp_to_timespec(struct timespec *ts, cdf_timestamp_t t) |
100 | 986 | { |
101 | 986 | struct tm tm; |
102 | 986 | #ifdef HAVE_STRUCT_TM_TM_ZONE |
103 | 986 | static char UTC[] = "UTC"; |
104 | 986 | #endif |
105 | 986 | int rdays; |
106 | | |
107 | | /* Unit is 100's of nanoseconds */ |
108 | 986 | ts->tv_nsec = (t % CDF_TIME_PREC) * 100; |
109 | | |
110 | 986 | t /= CDF_TIME_PREC; |
111 | 986 | tm.tm_sec = CAST(int, t % 60); |
112 | 986 | t /= 60; |
113 | | |
114 | 986 | tm.tm_min = CAST(int, t % 60); |
115 | 986 | t /= 60; |
116 | | |
117 | 986 | tm.tm_hour = CAST(int, t % 24); |
118 | 986 | t /= 24; |
119 | | |
120 | | /* XXX: Approx */ |
121 | 986 | tm.tm_year = CAST(int, CDF_BASE_YEAR + (t / 365)); |
122 | | |
123 | 986 | rdays = cdf_getdays(tm.tm_year); |
124 | 986 | t -= rdays - 1; |
125 | 986 | tm.tm_mday = cdf_getday(tm.tm_year, CAST(int, t)); |
126 | 986 | tm.tm_mon = cdf_getmonth(tm.tm_year, CAST(int, t)); |
127 | 986 | tm.tm_wday = 0; |
128 | 986 | tm.tm_yday = 0; |
129 | 986 | tm.tm_isdst = 0; |
130 | 986 | #ifdef HAVE_STRUCT_TM_TM_GMTOFF |
131 | 986 | tm.tm_gmtoff = 0; |
132 | 986 | #endif |
133 | 986 | #ifdef HAVE_STRUCT_TM_TM_ZONE |
134 | 986 | tm.tm_zone = UTC; |
135 | 986 | #endif |
136 | 986 | tm.tm_year -= 1900; |
137 | 986 | ts->tv_sec = mktime(&tm); |
138 | 986 | if (ts->tv_sec == -1) { |
139 | 0 | errno = EINVAL; |
140 | 0 | return -1; |
141 | 0 | } |
142 | 986 | return 0; |
143 | 986 | } |
144 | | |
145 | | int |
146 | | /*ARGSUSED*/ |
147 | | cdf_timespec_to_timestamp(cdf_timestamp_t *t, const struct timespec *ts) |
148 | 0 | { |
149 | 0 | #ifndef __lint__ |
150 | 0 | (void)&t; |
151 | 0 | (void)&ts; |
152 | 0 | #endif |
153 | | #ifdef notyet |
154 | | struct tm tm; |
155 | | if (gmtime_r(&ts->ts_sec, &tm) == NULL) { |
156 | | errno = EINVAL; |
157 | | return -1; |
158 | | } |
159 | | *t = (ts->ts_nsec / 100) * CDF_TIME_PREC; |
160 | | *t += tm.tm_sec; |
161 | | *t += tm.tm_min * 60; |
162 | | *t += tm.tm_hour * 60 * 60; |
163 | | *t += tm.tm_mday * 60 * 60 * 24; |
164 | | #endif |
165 | 0 | return 0; |
166 | 0 | } |
167 | | |
168 | | char * |
169 | | cdf_ctime(const time_t *sec, char *buf) |
170 | 46 | { |
171 | 46 | char *ptr = *sec > MAX_CTIME ? NULL : ctime_r(sec, buf); |
172 | 46 | if (ptr != NULL) |
173 | 36 | return buf; |
174 | | #ifdef WIN32 |
175 | | (void)snprintf(buf, 26, "*Bad* 0x%16.16I64x\n", |
176 | | CAST(long long, *sec)); |
177 | | #else |
178 | 10 | (void)snprintf(buf, 26, "*Bad* %#16.16" INT64_T_FORMAT "x\n", |
179 | 10 | CAST(long long, *sec)); |
180 | 10 | #endif |
181 | 10 | return buf; |
182 | 46 | } |
183 | | |
184 | | |
185 | | #ifdef TEST_TIME |
186 | | int |
187 | | main(int argc, char *argv[]) |
188 | | { |
189 | | struct timespec ts; |
190 | | char buf[25]; |
191 | | static const cdf_timestamp_t tst = 0x01A5E403C2D59C00ULL; |
192 | | static const char *ref = "Sat Apr 23 01:30:00 1977"; |
193 | | char *p, *q; |
194 | | |
195 | | cdf_timestamp_to_timespec(&ts, tst); |
196 | | p = cdf_ctime(&ts.tv_sec, buf); |
197 | | if ((q = strchr(p, '\n')) != NULL) |
198 | | *q = '\0'; |
199 | | if (strcmp(ref, p) != 0) |
200 | | errx(1, "Error date %s != %s\n", ref, p); |
201 | | return 0; |
202 | | } |
203 | | #endif |