5 /* Parts adapted from Andrew Plotkin's Cheapglk implementation */
7 /* Copy a GDateTime to a glkdate. */
9 gli_date_from_gdatetime(glkdate_t *date, GDateTime *dt)
11 date->year = g_date_time_get_year(dt);
12 date->month = g_date_time_get_month(dt);
13 date->day = g_date_time_get_day_of_month(dt);
14 /* GDateTime has 1-7, with 1 = Monday; Glk has 0-6, with 0 = Sunday */
15 date->weekday = g_date_time_get_day_of_week(dt) % G_DATE_SUNDAY;
16 date->hour = g_date_time_get_hour(dt);
17 date->minute = g_date_time_get_minute(dt);
18 date->second = g_date_time_get_second(dt);
21 /* Copy a glkdate to a GDateTime.
22 This is used in the "glk_date_to_..." functions, which are supposed
23 to normalize the glkdate. We're going to rely on GDateTime to do that.
24 Returns NULL if the date is not supported by GDateTime.
25 Call g_date_time_unref() on the return value when done.
28 gli_date_to_gdatetime(glkdate_t *date, GTimeZone *tz)
30 /* Combining seconds and microseconds into one floating-point number should
31 * take care of normalizing any negative microseconds or microseconds > one
33 double seconds = date->second + (double)date->microsec / G_USEC_PER_SEC;
34 if( G_UNLIKELY(date->year < 1) ) {
35 WARNING("Years earlier than 1 C.E. are not currently supported.");
38 if( G_UNLIKELY(date->year > 9999) ) {
39 WARNING("Years later than 9999 C.E. are not currently supported.");
42 return g_date_time_new(tz,
51 /* Convert a Unix timestamp (seconds since Jan 1 1970) to a glktimeval,
52 * adding a number of microseconds as well. */
54 gli_unix_time_to_time(gint64 sec, int microsec, glktimeval_t *time)
56 time->high_sec = (sec >> 32) & 0xFFFFFFFF;
57 time->low_sec = sec & 0xFFFFFFFF;
58 time->microsec = microsec;
61 /* Convert a gint64 microseconds value, as returned by g_get_real_time(),
64 gli_real_time_to_time(gint64 real_time, glktimeval_t *time)
66 gint64 unix_time = real_time / G_USEC_PER_SEC;
67 int microsec = real_time % G_USEC_PER_SEC;
68 gli_unix_time_to_time(unix_time, microsec, time);
71 /* Divide a Unix timestamp by a (positive) value. */
73 gli_simplify_time(gint64 timestamp, glui32 factor)
75 /* We want to round towards negative infinity, which takes a little
78 return timestamp / (gint64)factor;
81 return -1 - (((gint64)-1 - timestamp) / (gint64)factor);
87 * @time: pointer to a #glktimeval_t structure.
89 * The current Unix time is stored in the structure @time. (The argument may not
90 * be %NULL.) This is the number of seconds since the beginning of 1970 (UTC).
92 * The first two values in the structure should be considered a single
93 * <emphasis>signed</emphasis> 64-bit number. This allows the #glktimeval_t to
94 * store a reasonable range of values in the future and past. The @high_sec
95 * value will remain zero until sometime in 2106. If your computer is running in
96 * 1969, perhaps due to an unexpected solar flare, then @high_sec will be
99 * The third value in the structure represents a fraction of a second, in
100 * microseconds (from 0 to 999999). The resolution of the glk_current_time()
101 * call is platform-dependent; the @microsec value may not be updated
105 glk_current_time(glktimeval_t *time)
107 g_return_if_fail(time != NULL);
108 gli_real_time_to_time(g_get_real_time(), time);
112 * glk_current_simple_time:
113 * @factor: Factor by which to divide the time value.
115 * If dealing with 64-bit values is awkward, you can also get the current time
116 * as a lower-resolution 32-bit value. This is simply the Unix time divided by
117 * the @factor argument (which must not be zero). For example, if factor is 60,
118 * the result will be the number of minutes since 1970 (rounded towards negative
119 * infinity). If factor is 1, you will get the Unix time directly, but the value
120 * will be truncated starting some time in 2038.
122 * Returns: Unix time divided by @factor, truncated to 32 bits.
125 glk_current_simple_time(glui32 factor)
127 g_return_val_if_fail(factor != 0, 0);
129 gint64 sec = g_get_real_time() / G_USEC_PER_SEC;
130 return gli_simplify_time(sec, factor);
134 * glk_time_to_date_utc:
135 * @time: A #glktimeval_t structure as returned by glk_current_time().
136 * @date: An empty #glkdate_t structure to fill in.
138 * Convert the given timestamp (as returned by glk_current_time()) to a
139 * broken-out structure. This function returns a date and time in universal time
143 * The seconds value may be 60 because of a leap second.
147 glk_time_to_date_utc(glktimeval_t *time, glkdate_t *date)
149 g_return_if_fail(time != NULL);
150 g_return_if_fail(date != NULL);
152 time_t timestamp = time->low_sec;
153 if (sizeof(timestamp) > 4) {
154 timestamp += ((gint64)time->high_sec << 32);
157 GDateTime *dt = g_date_time_new_from_unix_utc(timestamp);
158 gli_date_from_gdatetime(date, dt);
159 g_date_time_unref(dt);
160 date->microsec = time->microsec;
164 * glk_time_to_date_local:
165 * @time: A #glktimeval_t structure as returned by glk_current_time().
166 * @date: An empty #glkdate_t structure to fill in.
168 * Does the same thing as glk_time_to_date_utc(), but this function returns
172 glk_time_to_date_local(glktimeval_t *time, glkdate_t *date)
174 g_return_if_fail(time != NULL);
175 g_return_if_fail(date != NULL);
177 time_t timestamp = time->low_sec;
178 if (sizeof(timestamp) > 4) {
179 timestamp += ((int64_t)time->high_sec << 32);
182 GDateTime *dt = g_date_time_new_from_unix_local(timestamp);
183 gli_date_from_gdatetime(date, dt);
184 g_date_time_unref(dt);
185 date->microsec = time->microsec;
189 * glk_simple_time_to_date_utc:
190 * @time: Timestamp as returned by glk_current_simple_time().
191 * @factor: Factor by which to multiply @time in order to get seconds.
192 * @date: An empty #glkdate_t structure to fill in.
194 * Convert the given timestamp (as returned by glk_current_simple_time()) to a
195 * broken-out structure in universal time. The @time argument is multiplied by
196 * @factor to produce a Unix timestamp.
198 * Since the resolution of glk_simple_time_to_date_utc() and
199 * glk_simple_time_to_date_local() is no better than seconds, they will return
200 * zero for the microseconds value.
203 glk_simple_time_to_date_utc(glsi32 time, glui32 factor, glkdate_t *date)
205 g_return_if_fail(factor != 0);
206 g_return_if_fail(date != NULL);
208 time_t timestamp = (time_t)time * factor;
210 GDateTime *dt = g_date_time_new_from_unix_utc(timestamp);
211 gli_date_from_gdatetime(date, dt);
212 g_date_time_unref(dt);
217 * glk_simple_time_to_date_local:
218 * @time: Timestamp as returned by glk_current_simple_time().
219 * @factor: Factor by which to multiply @time in order to get seconds.
220 * @date: An empty #glkdate_t structure to fill in.
222 * Does the same thing as glk_simple_time_to_date_utc(), but fills in the @date
223 * structure in local time.
226 glk_simple_time_to_date_local(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;
233 GDateTime *dt = g_date_time_new_from_unix_local(timestamp);
234 gli_date_from_gdatetime(date, dt);
235 g_date_time_unref(dt);
240 * glk_date_to_time_utc:
241 * @date: A date in the form of a #glkdate_t structure.
242 * @time: An empty #glktimeval_t structure to fill in.
244 * Convert the broken-out structure (interpreted as universal time) to a
245 * timestamp. The weekday value in @date is ignored. The other values need not
246 * be in their normal ranges; they will be normalized.
248 * If the time cannot be represented by the platform's time library, this may
249 * return -1 for the seconds value. (I.e., the @high_sec and @low_sec fields
250 * both $FFFFFFFF. The microseconds field is undefined in this case.)
251 * <note><title>Chimara</title><para>
252 * Chimara does not currently support years earlier than 1 C.E. or later than
257 glk_date_to_time_utc(glkdate_t *date, glktimeval_t *time)
259 g_return_if_fail(date != NULL);
260 g_return_if_fail(time != NULL);
262 GTimeZone *utc = g_time_zone_new_utc();
263 GDateTime *dt = gli_date_to_gdatetime(date, utc);
264 g_time_zone_unref(utc);
270 gint64 timestamp = g_date_time_to_unix(dt);
271 int microsec = g_date_time_get_microsecond(dt);
272 g_date_time_unref(dt);
273 gli_unix_time_to_time(timestamp, microsec, time);
277 * glk_date_to_time_local:
278 * @date: A date in the form of a #glkdate_t structure.
279 * @time: An empty #glktimeval_t structure to fill in.
281 * Does the same thing as glk_date_to_time_utc(), but interprets the broken-out
282 * structure as local time.
284 * The glk_date_to_time_local() function may not be smart about Daylight Saving
287 * If implemented with the mktime() libc function, it should use the negative
288 * @tm_isdst flag to <quote>attempt to divine whether summer time is in
293 glk_date_to_time_local(glkdate_t *date, glktimeval_t *time)
295 g_return_if_fail(date != NULL);
296 g_return_if_fail(time != NULL);
298 GTimeZone *local = g_time_zone_new_local();
299 GDateTime *dt = gli_date_to_gdatetime(date, local);
300 g_time_zone_unref(local);
306 gint64 timestamp = g_date_time_to_unix(dt);
307 int microsec = g_date_time_get_microsecond(dt);
308 g_date_time_unref(dt);
309 gli_unix_time_to_time(timestamp, microsec, time);
313 * glk_date_to_simple_time_utc:
314 * @date: A date in the form of a #glkdate_t structure.
315 * @factor: Factor by which to divide the time value.
317 * Convert the broken-out structure (interpreted as universal time) to a
318 * timestamp divided by @factor. The weekday value in @date is ignored. The
319 * other values need not be in their normal ranges; they will be normalized.
321 * If the time cannot be represented by the platform's time library, this may
323 * <note><title>Chimara</title><para>
324 * Chimara does not currently support years earlier than 1 C.E. or later than
328 * Returns: a timestamp divided by @factor, and truncated to 32 bits, or -1 on
332 glk_date_to_simple_time_utc(glkdate_t *date, glui32 factor)
334 g_return_val_if_fail(date != NULL, 0);
335 g_return_val_if_fail(factor != 0, 0);
337 GTimeZone *utc = g_time_zone_new_utc();
338 GDateTime *dt = gli_date_to_gdatetime(date, utc);
339 g_time_zone_unref(utc);
342 gint64 timestamp = g_date_time_to_unix(dt);
343 g_date_time_unref(dt);
345 return gli_simplify_time(timestamp, factor);
349 * glk_date_to_simple_time_local:
350 * @date: A date in the form of a #glkdate_t structure.
351 * @factor: Factor by which to divide the time value.
353 * Does the same thing as glk_date_to_simple_time_utc(), but interprets the
354 * broken-out structure as local time.
356 * Returns: a timestamp divided by @factor, and truncated to 32 bits, or -1 on
360 glk_date_to_simple_time_local(glkdate_t *date, glui32 factor)
362 g_return_val_if_fail(date != NULL, 0);
363 g_return_val_if_fail(factor != 0, 0);
365 GTimeZone *local = g_time_zone_new_local();
366 GDateTime *dt = gli_date_to_gdatetime(date, local);
367 g_time_zone_unref(local);
370 gint64 timestamp = g_date_time_to_unix(dt);
371 g_date_time_unref(dt);
373 return gli_simplify_time(timestamp, factor);