3 #include <strings.h> /* for bzero() */
7 /* FIXME: GDateTime was introduced in GLib 2.26, which is not standard on all
8 platforms yet. Therefore, we adapt Andrew Plotkin's implementation for now, and
9 will replace it with the (presumably) more portable GLib facilities later. */
11 /* Copy a POSIX tm structure to a glkdate. */
13 gli_date_from_tm(glkdate_t *date, struct tm *tm)
15 date->year = 1900 + tm->tm_year;
16 date->month = 1 + tm->tm_mon;
17 date->day = tm->tm_mday;
18 date->weekday = tm->tm_wday;
19 date->hour = tm->tm_hour;
20 date->minute = tm->tm_min;
21 date->second = tm->tm_sec;
24 /* Copy a glkdate to a POSIX tm structure.
25 This is used in the "glk_date_to_..." functions, which are supposed
26 to normalize the glkdate. We're going to rely on the mktime() /
27 timegm() functions to do that -- except they don't handle microseconds.
28 So we'll have to do that normalization here, adjust the tm_sec value,
29 and return the normalized number of microseconds.
32 gli_date_to_tm(glkdate_t *date, struct tm *tm)
36 bzero(tm, sizeof(tm));
37 tm->tm_year = date->year - 1900;
38 tm->tm_mon = date->month - 1;
39 tm->tm_mday = date->day;
40 tm->tm_wday = date->weekday;
41 tm->tm_hour = date->hour;
42 tm->tm_min = date->minute;
43 tm->tm_sec = date->second;
44 microsec = date->microsec;
46 if (microsec >= G_USEC_PER_SEC) {
47 tm->tm_sec += (microsec / G_USEC_PER_SEC);
48 microsec = microsec % G_USEC_PER_SEC;
50 else if (microsec < 0) {
51 microsec = -1 - microsec;
52 tm->tm_sec -= (1 + microsec / G_USEC_PER_SEC);
53 microsec = (G_USEC_PER_SEC - 1) - (microsec % G_USEC_PER_SEC);
59 /* Convert a GTimeVal, along with a microseconds value, to a glktimeval. */
61 gli_timestamp_to_time(long sec, long microsec, glktimeval_t *time)
63 if (sizeof(sec) <= 4) {
64 /* This platform has 32-bit time, but we can't do anything
65 about that. Hope it's not 2038 yet. */
73 /* The cast to gint64 shouldn't be necessary, but it
74 suppresses a pointless warning in the 32-bit case.
75 (Remember that we won't be executing this line in the
77 time->high_sec = (((gint64)sec) >> 32) & 0xFFFFFFFF;
78 time->low_sec = sec & 0xFFFFFFFF;
81 time->microsec = microsec;
84 /* Divide a Unix timestamp by a (positive) value. */
86 gli_simplify_time(long timestamp, glui32 factor)
88 /* We want to round towards negative infinity, which takes a little
91 return timestamp / (time_t)factor;
94 return -1 - (((long)-1 - timestamp) / (long)factor);
100 * @time: pointer to a #glktimeval_t structure.
102 * The current Unix time is stored in the structure @time. (The argument may not
103 * be %NULL.) This is the number of seconds since the beginning of 1970 (UTC).
105 * The first two values in the structure should be considered a single
106 * <emphasis>signed</emphasis> 64-bit number. This allows the #glktimeval_t to
107 * store a reasonable range of values in the future and past. The @high_sec
108 * value will remain zero until sometime in 2106. If your computer is running in
109 * 1969, perhaps due to an unexpected solar flare, then @high_sec will be
112 * The third value in the structure represents a fraction of a second, in
113 * microseconds (from 0 to 999999). The resolution of the glk_current_time()
114 * call is platform-dependent; the @microsec value may not be updated
118 glk_current_time(glktimeval_t *time)
120 g_return_if_fail(time != NULL);
123 g_get_current_time(&tv);
124 gli_timestamp_to_time(tv.tv_sec, tv.tv_usec, time);
128 * glk_current_simple_time:
129 * @factor: Factor by which to divide the time value.
131 * If dealing with 64-bit values is awkward, you can also get the current time
132 * as a lower-resolution 32-bit value. This is simply the Unix time divided by
133 * the @factor argument (which must not be zero). For example, if factor is 60,
134 * the result will be the number of minutes since 1970 (rounded towards negative
135 * infinity). If factor is 1, you will get the Unix time directly, but the value
136 * will be truncated starting some time in 2038.
138 * Returns: Unix time divided by @factor, truncated to 32 bits.
141 glk_current_simple_time(glui32 factor)
143 g_return_val_if_fail(factor != 0, 0);
146 g_get_current_time(&tv);
147 return gli_simplify_time(tv.tv_sec, factor);
151 * glk_time_to_date_utc:
152 * @time: A #glktimeval_t structure as returned by glk_current_time().
153 * @date: An empty #glkdate_t structure to fill in.
155 * Convert the given timestamp (as returned by glk_current_time()) to a
156 * broken-out structure. This function returns a date and time in universal time
160 * The seconds value may be 60 because of a leap second.
164 glk_time_to_date_utc(glktimeval_t *time, glkdate_t *date)
166 g_return_if_fail(time != NULL);
167 g_return_if_fail(date != NULL);
172 timestamp = time->low_sec;
173 if (sizeof(timestamp) > 4) {
174 timestamp += ((gint64)time->high_sec << 32);
177 gmtime_r(×tamp, &tm);
179 gli_date_from_tm(date, &tm);
180 date->microsec = time->microsec;
184 * glk_time_to_date_local:
185 * @time: A #glktimeval_t structure as returned by glk_current_time().
186 * @date: An empty #glkdate_t structure to fill in.
188 * Does the same thing as glk_time_to_date_utc(), but this function returns
192 glk_time_to_date_local(glktimeval_t *time, glkdate_t *date)
194 g_return_if_fail(time != NULL);
195 g_return_if_fail(date != NULL);
200 timestamp = time->low_sec;
201 if (sizeof(timestamp) > 4) {
202 timestamp += ((int64_t)time->high_sec << 32);
205 localtime_r(×tamp, &tm);
207 gli_date_from_tm(date, &tm);
208 date->microsec = time->microsec;
212 * glk_simple_time_to_date_utc:
213 * @time: Timestamp as returned by glk_current_simple_time().
214 * @factor: Factor by which to multiply @time in order to get seconds.
215 * @date: An empty #glkdate_t structure to fill in.
217 * Convert the given timestamp (as returned by glk_current_simple_time()) to a
218 * broken-out structure in universal time. The @time argument is multiplied by
219 * @factor to produce a Unix timestamp.
221 * Since the resolution of glk_simple_time_to_date_utc() and
222 * glk_simple_time_to_date_local() is no better than seconds, they will return
223 * zero for the microseconds value.
226 glk_simple_time_to_date_utc(glsi32 time, glui32 factor, glkdate_t *date)
228 g_return_if_fail(factor != 0);
229 g_return_if_fail(date != NULL);
231 time_t timestamp = (time_t)time * factor;
234 gmtime_r(×tamp, &tm);
236 gli_date_from_tm(date, &tm);
241 * glk_simple_time_to_date_local:
242 * @time: Timestamp as returned by glk_current_simple_time().
243 * @factor: Factor by which to multiply @time in order to get seconds.
244 * @date: An empty #glkdate_t structure to fill in.
246 * Does the same thing as glk_simple_time_to_date_utc(), but fills in the @date
247 * structure in local time.
250 glk_simple_time_to_date_local(glsi32 time, glui32 factor, glkdate_t *date)
252 g_return_if_fail(factor != 0);
253 g_return_if_fail(date != NULL);
255 time_t timestamp = (time_t)time * factor;
258 localtime_r(×tamp, &tm);
260 gli_date_from_tm(date, &tm);
265 * glk_date_to_time_utc:
266 * @date: A date in the form of a #glkdate_t structure.
267 * @time: An empty #glktimeval_t structure to fill in.
269 * Convert the broken-out structure (interpreted as universal time) to a
270 * timestamp. The weekday value in @date is ignored. The other values need not
271 * be in their normal ranges; they will be normalized.
273 * If the time cannot be represented by the platform's time library, this may
274 * return -1 for the seconds value. (I.e., the @high_sec and @low_sec fields
275 * both $FFFFFFFF. The microseconds field is undefined in this case.)
278 glk_date_to_time_utc(glkdate_t *date, glktimeval_t *time)
280 g_return_if_fail(date != NULL);
281 g_return_if_fail(time != NULL);
287 microsec = gli_date_to_tm(date, &tm);
288 /* The timegm function is not standard POSIX. If it's not available
289 on your platform, try setting the env var "TZ" to "", calling
290 mktime(), and then resetting "TZ". */
292 timestamp = timegm(&tm);
294 gli_timestamp_to_time(timestamp, microsec, time);
298 * glk_date_to_time_local:
299 * @date: A date in the form of a #glkdate_t structure.
300 * @time: An empty #glktimeval_t structure to fill in.
302 * Does the same thing as glk_date_to_time_utc(), but interprets the broken-out
303 * structure as local time.
305 * The glk_date_to_time_local() function may not be smart about Daylight Saving
308 * If implemented with the mktime() libc function, it should use the negative
309 * @tm_isdst flag to <quote>attempt to divine whether summer time is in
314 glk_date_to_time_local(glkdate_t *date, glktimeval_t *time)
316 g_return_if_fail(date != NULL);
317 g_return_if_fail(time != NULL);
323 microsec = gli_date_to_tm(date, &tm);
325 timestamp = mktime(&tm);
327 gli_timestamp_to_time(timestamp, microsec, time);
331 * glk_date_to_simple_time_utc:
332 * @date: A date in the form of a #glkdate_t structure.
333 * @factor: Factor by which to divide the time value.
335 * Convert the broken-out structure (interpreted as universal time) to a
336 * timestamp divided by @factor. The weekday value in @date is ignored. The
337 * other values need not be in their normal ranges; they will be normalized.
339 * If the time cannot be represented by the platform's time library, this may
342 * Returns: a timestamp divided by @factor, and truncated to 32 bits, or -1 on
346 glk_date_to_simple_time_utc(glkdate_t *date, glui32 factor)
348 g_return_val_if_fail(date != NULL, 0);
349 g_return_val_if_fail(factor != 0, 0);
354 gli_date_to_tm(date, &tm);
355 /* The timegm function is not standard POSIX. If it's not available
356 on your platform, try setting the env var "TZ" to "", calling
357 mktime(), and then resetting "TZ". */
359 timestamp = timegm(&tm);
361 return gli_simplify_time(timestamp, factor);
365 * glk_date_to_simple_time_local:
366 * @date: A date in the form of a #glkdate_t structure.
367 * @factor: Factor by which to divide the time value.
369 * Does the same thing as glk_date_to_simple_time_utc(), but interprets the
370 * broken-out structure as local time.
372 * Returns: a timestamp divided by @factor, and truncated to 32 bits, or -1 on
376 glk_date_to_simple_time_local(glkdate_t *date, glui32 factor)
378 g_return_val_if_fail(date != NULL, 0);
379 g_return_val_if_fail(factor != 0, 0);
384 gli_date_to_tm(date, &tm);
386 timestamp = mktime(&tm);
388 return gli_simplify_time(timestamp, factor);