5 /* Parts adapted from Andrew Plotkin's Cheapglk implementation */
7 /* Copy a GDateTime to a glkdate. */
9 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 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 GDateTime *retval = g_date_time_new(tz,
41 if( G_UNLIKELY(retval == NULL) ) {
43 WARNING("Years earlier than 1 C.E. are not currently supported.");
44 else if(date->year > 9999)
45 WARNING("Years later than 9999 C.E. are not currently supported.");
47 WARNING("Date is not supported or not valid.");
52 /* Convert a Unix timestamp (seconds since Jan 1 1970) to a glktimeval,
53 * adding a number of microseconds as well. */
55 unix_time_to_time(gint64 sec, int microsec, glktimeval_t *time)
57 time->high_sec = (sec >> 32) & 0xFFFFFFFF;
58 time->low_sec = sec & 0xFFFFFFFF;
59 time->microsec = microsec;
62 /* Convert a gint64 microseconds value, as returned by g_get_real_time(),
65 real_time_to_time(gint64 real_time, glktimeval_t *time)
67 gint64 unix_time = real_time / G_USEC_PER_SEC;
68 int microsec = real_time % G_USEC_PER_SEC;
69 unix_time_to_time(unix_time, microsec, time);
72 /* Divide a Unix timestamp by a (positive) value. */
74 simplify_time(gint64 timestamp, glui32 factor)
76 /* We want to round towards negative infinity, which takes a little
79 return timestamp / (gint64)factor;
82 return -1 - (((gint64)-1 - timestamp) / (gint64)factor);
86 /* Convert a glkdate to a glktimeval, in the given time zone. */
88 date_to_time(glkdate_t *date, glktimeval_t *tv, GTimeZone *tz)
90 GDateTime *dt = date_to_gdatetime(date, tz);
96 gint64 timestamp = g_date_time_to_unix(dt);
97 int microsec = g_date_time_get_microsecond(dt);
98 g_date_time_unref(dt);
99 unix_time_to_time(timestamp, microsec, tv);
102 /* Convert a glkdate to a Unix timestamp divided by a value, in the given time
105 date_to_simple_time(glkdate_t *date, glui32 factor, GTimeZone *tz)
107 GDateTime *dt = date_to_gdatetime(date, tz);
110 gint64 timestamp = g_date_time_to_unix(dt);
111 g_date_time_unref(dt);
113 return simplify_time(timestamp, factor);
118 * @time: pointer to a #glktimeval_t structure.
120 * The current Unix time is stored in the structure @time. (The argument may not
121 * be %NULL.) This is the number of seconds since the beginning of 1970 (UTC).
123 * The first two values in the structure should be considered a single
124 * <emphasis>signed</emphasis> 64-bit number. This allows the #glktimeval_t to
125 * store a reasonable range of values in the future and past. The @high_sec
126 * value will remain zero until sometime in 2106. If your computer is running in
127 * 1969, perhaps due to an unexpected solar flare, then @high_sec will be
130 * The third value in the structure represents a fraction of a second, in
131 * microseconds (from 0 to 999999). The resolution of the glk_current_time()
132 * call is platform-dependent; the @microsec value may not be updated
136 glk_current_time(glktimeval_t *time)
138 g_return_if_fail(time != NULL);
139 real_time_to_time(g_get_real_time(), time);
143 * glk_current_simple_time:
144 * @factor: Factor by which to divide the time value.
146 * If dealing with 64-bit values is awkward, you can also get the current time
147 * as a lower-resolution 32-bit value. This is simply the Unix time divided by
148 * the @factor argument (which must not be zero). For example, if factor is 60,
149 * the result will be the number of minutes since 1970 (rounded towards negative
150 * infinity). If factor is 1, you will get the Unix time directly, but the value
151 * will be truncated starting some time in 2038.
153 * Returns: Unix time divided by @factor, truncated to 32 bits.
156 glk_current_simple_time(glui32 factor)
158 g_return_val_if_fail(factor != 0, 0);
160 gint64 sec = g_get_real_time() / G_USEC_PER_SEC;
161 return simplify_time(sec, factor);
165 * glk_time_to_date_utc:
166 * @time: A #glktimeval_t structure as returned by glk_current_time().
167 * @date: An empty #glkdate_t structure to fill in.
169 * Convert the given timestamp (as returned by glk_current_time()) to a
170 * broken-out structure. This function returns a date and time in universal time
174 * The seconds value may be 60 because of a leap second.
178 glk_time_to_date_utc(glktimeval_t *time, glkdate_t *date)
180 g_return_if_fail(time != NULL);
181 g_return_if_fail(date != NULL);
183 time_t timestamp = time->low_sec;
184 if (sizeof(timestamp) > 4) {
185 timestamp += ((gint64)time->high_sec << 32);
188 GDateTime *dt = g_date_time_new_from_unix_utc(timestamp);
189 date_from_gdatetime(date, dt);
190 g_date_time_unref(dt);
191 date->microsec = time->microsec;
195 * glk_time_to_date_local:
196 * @time: A #glktimeval_t structure as returned by glk_current_time().
197 * @date: An empty #glkdate_t structure to fill in.
199 * Does the same thing as glk_time_to_date_utc(), but this function returns
203 glk_time_to_date_local(glktimeval_t *time, glkdate_t *date)
205 g_return_if_fail(time != NULL);
206 g_return_if_fail(date != NULL);
208 time_t timestamp = time->low_sec;
209 if (sizeof(timestamp) > 4) {
210 timestamp += ((int64_t)time->high_sec << 32);
213 GDateTime *dt = g_date_time_new_from_unix_local(timestamp);
214 date_from_gdatetime(date, dt);
215 g_date_time_unref(dt);
216 date->microsec = time->microsec;
220 * glk_simple_time_to_date_utc:
221 * @time: Timestamp as returned by glk_current_simple_time().
222 * @factor: Factor by which to multiply @time in order to get seconds.
223 * @date: An empty #glkdate_t structure to fill in.
225 * Convert the given timestamp (as returned by glk_current_simple_time()) to a
226 * broken-out structure in universal time. The @time argument is multiplied by
227 * @factor to produce a Unix timestamp.
229 * Since the resolution of glk_simple_time_to_date_utc() and
230 * glk_simple_time_to_date_local() is no better than seconds, they will return
231 * zero for the microseconds value.
234 glk_simple_time_to_date_utc(glsi32 time, glui32 factor, glkdate_t *date)
236 g_return_if_fail(factor != 0);
237 g_return_if_fail(date != NULL);
239 time_t timestamp = (time_t)time * factor;
241 GDateTime *dt = g_date_time_new_from_unix_utc(timestamp);
242 date_from_gdatetime(date, dt);
243 g_date_time_unref(dt);
248 * glk_simple_time_to_date_local:
249 * @time: Timestamp as returned by glk_current_simple_time().
250 * @factor: Factor by which to multiply @time in order to get seconds.
251 * @date: An empty #glkdate_t structure to fill in.
253 * Does the same thing as glk_simple_time_to_date_utc(), but fills in the @date
254 * structure in local time.
257 glk_simple_time_to_date_local(glsi32 time, glui32 factor, glkdate_t *date)
259 g_return_if_fail(factor != 0);
260 g_return_if_fail(date != NULL);
262 time_t timestamp = (time_t)time * factor;
264 GDateTime *dt = g_date_time_new_from_unix_local(timestamp);
265 date_from_gdatetime(date, dt);
266 g_date_time_unref(dt);
271 * glk_date_to_time_utc:
272 * @date: A date in the form of a #glkdate_t structure.
273 * @time: An empty #glktimeval_t structure to fill in.
275 * Convert the broken-out structure (interpreted as universal time) to a
276 * timestamp. The weekday value in @date is ignored. The other values need not
277 * be in their normal ranges; they will be normalized.
279 * If the time cannot be represented by the platform's time library, this may
280 * return -1 for the seconds value. (I.e., the @high_sec and @low_sec fields
281 * both $FFFFFFFF. The microseconds field is undefined in this case.)
282 * <note><title>Chimara</title><para>
283 * Chimara does not currently support years earlier than 1 C.E. or later than
288 glk_date_to_time_utc(glkdate_t *date, glktimeval_t *time)
290 g_return_if_fail(date != NULL);
291 g_return_if_fail(time != NULL);
293 GTimeZone *utc = g_time_zone_new_utc();
294 date_to_time(date, time, utc);
295 g_time_zone_unref(utc);
299 * glk_date_to_time_local:
300 * @date: A date in the form of a #glkdate_t structure.
301 * @time: An empty #glktimeval_t structure to fill in.
303 * Does the same thing as glk_date_to_time_utc(), but interprets the broken-out
304 * structure as local time.
306 * The glk_date_to_time_local() function may not be smart about Daylight Saving
309 * If implemented with the mktime() libc function, it should use the negative
310 * @tm_isdst flag to <quote>attempt to divine whether summer time is in
315 glk_date_to_time_local(glkdate_t *date, glktimeval_t *time)
317 g_return_if_fail(date != NULL);
318 g_return_if_fail(time != NULL);
320 GTimeZone *local = g_time_zone_new_local();
321 date_to_time(date, time, local);
322 g_time_zone_unref(local);
326 * glk_date_to_simple_time_utc:
327 * @date: A date in the form of a #glkdate_t structure.
328 * @factor: Factor by which to divide the time value.
330 * Convert the broken-out structure (interpreted as universal time) to a
331 * timestamp divided by @factor. The weekday value in @date is ignored. The
332 * other values need not be in their normal ranges; they will be normalized.
334 * If the time cannot be represented by the platform's time library, this may
336 * <note><title>Chimara</title><para>
337 * Chimara does not currently support years earlier than 1 C.E. or later than
341 * Returns: a timestamp divided by @factor, and truncated to 32 bits, or -1 on
345 glk_date_to_simple_time_utc(glkdate_t *date, glui32 factor)
347 g_return_val_if_fail(date != NULL, 0);
348 g_return_val_if_fail(factor != 0, 0);
350 GTimeZone *utc = g_time_zone_new_utc();
351 glsi32 retval = date_to_simple_time(date, factor, utc);
352 g_time_zone_unref(utc);
357 * glk_date_to_simple_time_local:
358 * @date: A date in the form of a #glkdate_t structure.
359 * @factor: Factor by which to divide the time value.
361 * Does the same thing as glk_date_to_simple_time_utc(), but interprets the
362 * broken-out structure as local time.
364 * Returns: a timestamp divided by @factor, and truncated to 32 bits, or -1 on
368 glk_date_to_simple_time_local(glkdate_t *date, glui32 factor)
370 g_return_val_if_fail(date != NULL, 0);
371 g_return_val_if_fail(factor != 0, 0);
373 GTimeZone *local = g_time_zone_new_local();
374 glsi32 retval = date_to_simple_time(date, factor, local);
375 g_time_zone_unref(local);