Branch data Line data Source code
1 : : /* GLIB - Library of useful routines for C programming
2 : : * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This library 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 GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 : : */
19 : :
20 : : /*
21 : : * Modified by the GLib Team and others 1997-2000. See the AUTHORS
22 : : * file for a list of people on the GLib Team. See the ChangeLog
23 : : * files for a list of changes. These files are distributed with
24 : : * GLib at ftp://ftp.gtk.org/pub/gtk/.
25 : : */
26 : :
27 : : /*
28 : : * MT safe
29 : : */
30 : :
31 : : #include "config.h"
32 : : #include "glibconfig.h"
33 : :
34 : : #include <stdlib.h>
35 : :
36 : : #ifdef G_OS_UNIX
37 : : #include <unistd.h>
38 : : #endif /* G_OS_UNIX */
39 : :
40 : : #ifdef HAVE_SYS_TIME_H
41 : : #include <sys/time.h>
42 : : #endif
43 : : #include <time.h>
44 : : #ifndef G_OS_WIN32
45 : : #include <errno.h>
46 : : #endif /* G_OS_WIN32 */
47 : :
48 : : #ifdef G_OS_WIN32
49 : : #include <windows.h>
50 : : #endif /* G_OS_WIN32 */
51 : :
52 : : #include "gtimer.h"
53 : :
54 : : #include "gmem.h"
55 : : #include "gstrfuncs.h"
56 : : #include "gtestutils.h"
57 : : #include "gmain.h"
58 : :
59 : : /**
60 : : * GTimer:
61 : : *
62 : : * `GTimer` records a start time, and counts microseconds elapsed since
63 : : * that time.
64 : : *
65 : : * This is done somewhat differently on different platforms, and can be
66 : : * tricky to get exactly right, so `GTimer` provides a portable/convenient interface.
67 : : */
68 : : struct _GTimer
69 : : {
70 : : guint64 start;
71 : : guint64 end;
72 : :
73 : : guint active : 1;
74 : : };
75 : :
76 : : /**
77 : : * g_timer_new: (constructor)
78 : : *
79 : : * Creates a new timer, and starts timing (i.e. g_timer_start() is
80 : : * implicitly called for you).
81 : : *
82 : : * Returns: (transfer full): a new #GTimer.
83 : : **/
84 : : GTimer*
85 : 7064 : g_timer_new (void)
86 : : {
87 : : GTimer *timer;
88 : :
89 : 7064 : timer = g_new (GTimer, 1);
90 : 7064 : timer->active = TRUE;
91 : :
92 : 7064 : timer->start = g_get_monotonic_time ();
93 : :
94 : 7064 : return timer;
95 : : }
96 : :
97 : : /**
98 : : * g_timer_destroy:
99 : : * @timer: a #GTimer to destroy.
100 : : *
101 : : * Destroys a timer, freeing associated resources.
102 : : **/
103 : : void
104 : 6937 : g_timer_destroy (GTimer *timer)
105 : : {
106 : 6937 : g_return_if_fail (timer != NULL);
107 : :
108 : 6937 : g_free (timer);
109 : : }
110 : :
111 : : /**
112 : : * g_timer_start:
113 : : * @timer: a #GTimer.
114 : : *
115 : : * Marks a start time, so that future calls to g_timer_elapsed() will
116 : : * report the time since g_timer_start() was called. g_timer_new()
117 : : * automatically marks the start time, so no need to call
118 : : * g_timer_start() immediately after creating the timer.
119 : : **/
120 : : void
121 : 7257 : g_timer_start (GTimer *timer)
122 : : {
123 : 7257 : g_return_if_fail (timer != NULL);
124 : :
125 : 7257 : timer->active = TRUE;
126 : :
127 : 7257 : timer->start = g_get_monotonic_time ();
128 : : }
129 : :
130 : : /**
131 : : * g_timer_stop:
132 : : * @timer: a #GTimer.
133 : : *
134 : : * Marks an end time, so calls to g_timer_elapsed() will return the
135 : : * difference between this end time and the start time.
136 : : **/
137 : : void
138 : 7090 : g_timer_stop (GTimer *timer)
139 : : {
140 : 7090 : g_return_if_fail (timer != NULL);
141 : :
142 : 7090 : timer->active = FALSE;
143 : :
144 : 7090 : timer->end = g_get_monotonic_time ();
145 : : }
146 : :
147 : : /**
148 : : * g_timer_reset:
149 : : * @timer: a #GTimer.
150 : : *
151 : : * This function is useless; it's fine to call g_timer_start() on an
152 : : * already-started timer to reset the start time, so g_timer_reset()
153 : : * serves no purpose.
154 : : **/
155 : : void
156 : 5 : g_timer_reset (GTimer *timer)
157 : : {
158 : 5 : g_return_if_fail (timer != NULL);
159 : :
160 : 5 : timer->start = g_get_monotonic_time ();
161 : : }
162 : :
163 : : /**
164 : : * g_timer_continue:
165 : : * @timer: a #GTimer.
166 : : *
167 : : * Resumes a timer that has previously been stopped with
168 : : * g_timer_stop(). g_timer_stop() must be called before using this
169 : : * function.
170 : : *
171 : : * Since: 2.4
172 : : **/
173 : : void
174 : 2 : g_timer_continue (GTimer *timer)
175 : : {
176 : : guint64 elapsed;
177 : :
178 : 2 : g_return_if_fail (timer != NULL);
179 : 2 : g_return_if_fail (timer->active == FALSE);
180 : :
181 : : /* Get elapsed time and reset timer start time
182 : : * to the current time minus the previously
183 : : * elapsed interval.
184 : : */
185 : :
186 : 1 : elapsed = timer->end - timer->start;
187 : :
188 : 1 : timer->start = g_get_monotonic_time ();
189 : :
190 : 1 : timer->start -= elapsed;
191 : :
192 : 1 : timer->active = TRUE;
193 : : }
194 : :
195 : : /**
196 : : * g_timer_elapsed:
197 : : * @timer: a #GTimer.
198 : : * @microseconds: return location for the fractional part of seconds
199 : : * elapsed, in microseconds (that is, the total number
200 : : * of microseconds elapsed, modulo 1000000), or %NULL
201 : : *
202 : : * If @timer has been started but not stopped, obtains the time since
203 : : * the timer was started. If @timer has been stopped, obtains the
204 : : * elapsed time between the time it was started and the time it was
205 : : * stopped. The return value is the number of seconds elapsed,
206 : : * including any fractional part. The @microseconds out parameter is
207 : : * essentially useless.
208 : : *
209 : : * Returns: seconds elapsed as a floating point value, including any
210 : : * fractional part.
211 : : **/
212 : : gdouble
213 : 7249 : g_timer_elapsed (GTimer *timer,
214 : : gulong *microseconds)
215 : : {
216 : : gdouble total;
217 : : gint64 elapsed;
218 : :
219 : 7249 : g_return_val_if_fail (timer != NULL, 0);
220 : :
221 [ + + ]: 7249 : if (timer->active)
222 : 178 : timer->end = g_get_monotonic_time ();
223 : :
224 : 7249 : elapsed = timer->end - timer->start;
225 : :
226 : 7249 : total = elapsed / 1e6;
227 : :
228 [ + + ]: 7249 : if (microseconds)
229 : 1 : *microseconds = elapsed % 1000000;
230 : :
231 : 7249 : return total;
232 : : }
233 : :
234 : : /**
235 : : * g_timer_is_active:
236 : : * @timer: a #GTimer.
237 : : *
238 : : * Exposes whether the timer is currently active.
239 : : *
240 : : * Returns: %TRUE if the timer is running, %FALSE otherwise
241 : : * Since: 2.62
242 : : **/
243 : : gboolean
244 : 2 : g_timer_is_active (GTimer *timer)
245 : : {
246 : 2 : g_return_val_if_fail (timer != NULL, FALSE);
247 : :
248 : 2 : return timer->active;
249 : : }
250 : :
251 : : /**
252 : : * g_usleep:
253 : : * @microseconds: number of microseconds to pause
254 : : *
255 : : * Pauses the current thread for the given number of microseconds.
256 : : *
257 : : * There are 1 million microseconds per second (represented by the
258 : : * %G_USEC_PER_SEC macro). g_usleep() may have limited precision,
259 : : * depending on hardware and operating system; don't rely on the exact
260 : : * length of the sleep.
261 : : */
262 : : void
263 : 76766 : g_usleep (gulong microseconds)
264 : : {
265 [ + + ]: 76766 : if G_UNLIKELY (microseconds == 0)
266 : 1187 : return;
267 : :
268 : : #ifdef G_OS_WIN32
269 : : /* Round up to the next millisecond */
270 : : Sleep (microseconds ? (1 + (microseconds - 1) / 1000) : 0);
271 : : #else
272 : : struct timespec request, remaining;
273 : 75579 : request.tv_sec = microseconds / G_USEC_PER_SEC;
274 : 75579 : request.tv_nsec = 1000 * (microseconds % G_USEC_PER_SEC);
275 [ - + - - ]: 75579 : while (nanosleep (&request, &remaining) == -1 && errno == EINTR)
276 : 0 : request = remaining;
277 : : #endif
278 : : }
279 : :
280 : : /**
281 : : * g_time_val_add:
282 : : * @time_: a #GTimeVal
283 : : * @microseconds: number of microseconds to add to @time
284 : : *
285 : : * Adds the given number of microseconds to @time_. @microseconds can
286 : : * also be negative to decrease the value of @time_.
287 : : *
288 : : * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use `guint64` for
289 : : * representing microseconds since the epoch, or use #GDateTime.
290 : : **/
291 : : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
292 : : void
293 : 7 : g_time_val_add (GTimeVal *time_, glong microseconds)
294 : : {
295 : 7 : g_return_if_fail (time_ != NULL &&
296 : : time_->tv_usec >= 0 &&
297 : : time_->tv_usec < G_USEC_PER_SEC);
298 : :
299 [ + + ]: 7 : if (microseconds >= 0)
300 : : {
301 : 5 : time_->tv_usec += microseconds % G_USEC_PER_SEC;
302 : 5 : time_->tv_sec += microseconds / G_USEC_PER_SEC;
303 [ + + ]: 5 : if (time_->tv_usec >= G_USEC_PER_SEC)
304 : : {
305 : 1 : time_->tv_usec -= G_USEC_PER_SEC;
306 : 1 : time_->tv_sec++;
307 : : }
308 : : }
309 : : else
310 : : {
311 : 2 : microseconds *= -1;
312 : 2 : time_->tv_usec -= microseconds % G_USEC_PER_SEC;
313 : 2 : time_->tv_sec -= microseconds / G_USEC_PER_SEC;
314 [ + + ]: 2 : if (time_->tv_usec < 0)
315 : : {
316 : 1 : time_->tv_usec += G_USEC_PER_SEC;
317 : 1 : time_->tv_sec--;
318 : : }
319 : : }
320 : : }
321 : : G_GNUC_END_IGNORE_DEPRECATIONS
322 : :
323 : : /* converts a broken down date representation, relative to UTC,
324 : : * to a timestamp; it uses timegm() if it's available.
325 : : */
326 : : static time_t
327 : 48 : mktime_utc (struct tm *tm)
328 : : {
329 : : time_t retval;
330 : :
331 : : #ifndef HAVE_TIMEGM
332 : : static const gint days_before[] =
333 : : {
334 : : 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
335 : : };
336 : : #endif
337 : :
338 : : #ifndef HAVE_TIMEGM
339 : : if (tm->tm_mon < 0 || tm->tm_mon > 11)
340 : : return (time_t) -1;
341 : :
342 : : retval = (tm->tm_year - 70) * 365;
343 : : retval += (tm->tm_year - 68) / 4;
344 : : retval += days_before[tm->tm_mon] + tm->tm_mday - 1;
345 : :
346 : : if (tm->tm_year % 4 == 0 && tm->tm_mon < 2)
347 : : retval -= 1;
348 : :
349 : : retval = ((((retval * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 + tm->tm_sec;
350 : : #else
351 : 48 : retval = timegm (tm);
352 : : #endif /* !HAVE_TIMEGM */
353 : :
354 : 48 : return retval;
355 : : }
356 : :
357 : : /**
358 : : * g_time_val_from_iso8601:
359 : : * @iso_date: an ISO 8601 encoded date string
360 : : * @time_: (out): a #GTimeVal
361 : : *
362 : : * Converts a string containing an ISO 8601 encoded date and time
363 : : * to a #GTimeVal and puts it into @time_.
364 : : *
365 : : * @iso_date must include year, month, day, hours, minutes, and
366 : : * seconds. It can optionally include fractions of a second and a time
367 : : * zone indicator. (In the absence of any time zone indication, the
368 : : * timestamp is assumed to be in local time.)
369 : : *
370 : : * Any leading or trailing space in @iso_date is ignored.
371 : : *
372 : : * This function was deprecated, along with #GTimeVal itself, in GLib 2.62.
373 : : * Equivalent functionality is available using code like:
374 : : * |[
375 : : * GDateTime *dt = g_date_time_new_from_iso8601 (iso8601_string, NULL);
376 : : * gint64 time_val = g_date_time_to_unix (dt);
377 : : * g_date_time_unref (dt);
378 : : * ]|
379 : : *
380 : : * Returns: %TRUE if the conversion was successful.
381 : : *
382 : : * Since: 2.12
383 : : * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use
384 : : * g_date_time_new_from_iso8601() instead.
385 : : */
386 : : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
387 : : gboolean
388 : 124 : g_time_val_from_iso8601 (const gchar *iso_date,
389 : : GTimeVal *time_)
390 : : {
391 : 124 : struct tm tm = {0};
392 : : long val;
393 : : long mday, mon, year;
394 : : long hour, min, sec;
395 : :
396 : 124 : g_return_val_if_fail (iso_date != NULL, FALSE);
397 : 124 : g_return_val_if_fail (time_ != NULL, FALSE);
398 : :
399 : : /* Ensure that the first character is a digit, the first digit
400 : : * of the date, otherwise we don't have an ISO 8601 date
401 : : */
402 [ + + ]: 134 : while (g_ascii_isspace (*iso_date))
403 : 10 : iso_date++;
404 : :
405 [ + + ]: 124 : if (*iso_date == '\0')
406 : 2 : return FALSE;
407 : :
408 [ + + + + ]: 122 : if (!g_ascii_isdigit (*iso_date) && *iso_date != '+')
409 : 6 : return FALSE;
410 : :
411 : 116 : val = strtoul (iso_date, (char **)&iso_date, 10);
412 [ + + ]: 116 : if (*iso_date == '-')
413 : : {
414 : : /* YYYY-MM-DD */
415 : 76 : year = val;
416 : 76 : iso_date++;
417 : :
418 : 76 : mon = strtoul (iso_date, (char **)&iso_date, 10);
419 [ + + ]: 76 : if (*iso_date++ != '-')
420 : 2 : return FALSE;
421 : :
422 : 74 : mday = strtoul (iso_date, (char **)&iso_date, 10);
423 : : }
424 : : else
425 : : {
426 : : /* YYYYMMDD */
427 : 40 : mday = val % 100;
428 : 40 : mon = (val % 10000) / 100;
429 : 40 : year = val / 10000;
430 : : }
431 : :
432 : : /* Validation. */
433 [ + + + + ]: 114 : if (year < 1900 || year > G_MAXINT)
434 : 8 : return FALSE;
435 [ + + + + ]: 106 : if (mon < 1 || mon > 12)
436 : 8 : return FALSE;
437 [ + + + + ]: 98 : if (mday < 1 || mday > 31)
438 : 8 : return FALSE;
439 : :
440 : 90 : tm.tm_mday = mday;
441 : 90 : tm.tm_mon = mon - 1;
442 : 90 : tm.tm_year = year - 1900;
443 : :
444 [ + + ]: 90 : if (*iso_date != 'T')
445 : 8 : return FALSE;
446 : :
447 : 82 : iso_date++;
448 : :
449 : : /* If there is a 'T' then there has to be a time */
450 [ + + ]: 82 : if (!g_ascii_isdigit (*iso_date))
451 : 4 : return FALSE;
452 : :
453 : 78 : val = strtoul (iso_date, (char **)&iso_date, 10);
454 [ + + ]: 78 : if (*iso_date == ':')
455 : : {
456 : : /* hh:mm:ss */
457 : 52 : hour = val;
458 : 52 : iso_date++;
459 : 52 : min = strtoul (iso_date, (char **)&iso_date, 10);
460 : :
461 [ + + ]: 52 : if (*iso_date++ != ':')
462 : 2 : return FALSE;
463 : :
464 : 50 : sec = strtoul (iso_date, (char **)&iso_date, 10);
465 : : }
466 : : else
467 : : {
468 : : /* hhmmss */
469 : 26 : sec = val % 100;
470 : 26 : min = (val % 10000) / 100;
471 : 26 : hour = val / 10000;
472 : : }
473 : :
474 : : /* Validation. Allow up to 2 leap seconds when validating @sec. */
475 [ + + ]: 76 : if (hour > 23)
476 : 4 : return FALSE;
477 [ + + ]: 72 : if (min > 59)
478 : 4 : return FALSE;
479 [ + + ]: 68 : if (sec > 61)
480 : 4 : return FALSE;
481 : :
482 : 64 : tm.tm_hour = hour;
483 : 64 : tm.tm_min = min;
484 : 64 : tm.tm_sec = sec;
485 : :
486 : 64 : time_->tv_usec = 0;
487 : :
488 [ + + + + ]: 64 : if (*iso_date == ',' || *iso_date == '.')
489 : : {
490 : 33 : glong mul = 100000;
491 : :
492 [ + + + + ]: 207 : while (mul >= 1 && g_ascii_isdigit (*++iso_date))
493 : : {
494 : 174 : time_->tv_usec += (*iso_date - '0') * mul;
495 : 174 : mul /= 10;
496 : : }
497 : :
498 : : /* Skip any remaining digits after we’ve reached our limit of precision. */
499 [ + + ]: 118 : while (g_ascii_isdigit (*iso_date))
500 : 85 : iso_date++;
501 : : }
502 : :
503 : : /* Now parse the offset and convert tm to a time_t */
504 [ + + ]: 64 : if (*iso_date == 'Z')
505 : : {
506 : 20 : iso_date++;
507 : 20 : time_->tv_sec = mktime_utc (&tm);
508 : : }
509 [ + + + + ]: 44 : else if (*iso_date == '+' || *iso_date == '-')
510 : 28 : {
511 [ + + ]: 36 : gint sign = (*iso_date == '+') ? -1 : 1;
512 : :
513 : 36 : val = strtoul (iso_date + 1, (char **)&iso_date, 10);
514 : :
515 [ + + ]: 36 : if (*iso_date == ':')
516 : : {
517 : : /* hh:mm */
518 : 20 : hour = val;
519 : 20 : min = strtoul (iso_date + 1, (char **)&iso_date, 10);
520 : : }
521 : : else
522 : : {
523 : : /* hhmm */
524 : 16 : hour = val / 100;
525 : 16 : min = val % 100;
526 : : }
527 : :
528 [ + + ]: 36 : if (hour > 99)
529 : 4 : return FALSE;
530 [ + + ]: 32 : if (min > 59)
531 : 4 : return FALSE;
532 : :
533 : 28 : time_->tv_sec = mktime_utc (&tm) + (time_t) (60 * (gint64) (60 * hour + min) * sign);
534 : : }
535 : : else
536 : : {
537 : : /* No "Z" or offset, so local time */
538 : 8 : tm.tm_isdst = -1; /* locale selects DST */
539 : 8 : time_->tv_sec = mktime (&tm);
540 : : }
541 : :
542 [ + + ]: 72 : while (g_ascii_isspace (*iso_date))
543 : 16 : iso_date++;
544 : :
545 : 56 : return *iso_date == '\0';
546 : : }
547 : : G_GNUC_END_IGNORE_DEPRECATIONS
548 : :
549 : : /**
550 : : * g_time_val_to_iso8601:
551 : : * @time_: a #GTimeVal
552 : : *
553 : : * Converts @time_ into an RFC 3339 encoded string, relative to the
554 : : * Coordinated Universal Time (UTC). This is one of the many formats
555 : : * allowed by ISO 8601.
556 : : *
557 : : * ISO 8601 allows a large number of date/time formats, with or without
558 : : * punctuation and optional elements. The format returned by this function
559 : : * is a complete date and time, with optional punctuation included, the
560 : : * UTC time zone represented as "Z", and the @tv_usec part included if
561 : : * and only if it is nonzero, i.e. either
562 : : * "YYYY-MM-DDTHH:MM:SSZ" or "YYYY-MM-DDTHH:MM:SS.fffffZ".
563 : : *
564 : : * This corresponds to the Internet date/time format defined by
565 : : * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt),
566 : : * and to either of the two most-precise formats defined by
567 : : * the W3C Note
568 : : * [Date and Time Formats](http://www.w3.org/TR/NOTE-datetime-19980827).
569 : : * Both of these documents are profiles of ISO 8601.
570 : : *
571 : : * Use g_date_time_format() or g_strdup_printf() if a different
572 : : * variation of ISO 8601 format is required.
573 : : *
574 : : * If @time_ represents a date which is too large to fit into a `struct tm`,
575 : : * %NULL will be returned. This is platform dependent. Note also that since
576 : : * `GTimeVal` stores the number of seconds as a `glong`, on 32-bit systems it
577 : : * is subject to the year 2038 problem. Accordingly, since GLib 2.62, this
578 : : * function has been deprecated. Equivalent functionality is available using:
579 : : * |[
580 : : * GDateTime *dt = g_date_time_new_from_unix_utc (time_val);
581 : : * iso8601_string = g_date_time_format_iso8601 (dt);
582 : : * g_date_time_unref (dt);
583 : : * ]|
584 : : *
585 : : * The return value of g_time_val_to_iso8601() has been nullable since GLib
586 : : * 2.54; before then, GLib would crash under the same conditions.
587 : : *
588 : : * Returns: (nullable): a newly allocated string containing an ISO 8601 date,
589 : : * or %NULL if @time_ was too large
590 : : *
591 : : * Since: 2.12
592 : : * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use
593 : : * g_date_time_format_iso8601(dt) instead.
594 : : */
595 : : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
596 : : gchar *
597 : 3 : g_time_val_to_iso8601 (GTimeVal *time_)
598 : : {
599 : : gchar *retval;
600 : : struct tm *tm;
601 : : #ifdef HAVE_GMTIME_R
602 : : struct tm tm_;
603 : : #endif
604 : : time_t secs;
605 : :
606 : 3 : g_return_val_if_fail (time_ != NULL &&
607 : : time_->tv_usec >= 0 &&
608 : : time_->tv_usec < G_USEC_PER_SEC, NULL);
609 : :
610 : 3 : secs = time_->tv_sec;
611 : : #ifdef _WIN32
612 : : tm = gmtime (&secs);
613 : : #else
614 : : #ifdef HAVE_GMTIME_R
615 : 3 : tm = gmtime_r (&secs, &tm_);
616 : : #else
617 : : tm = gmtime (&secs);
618 : : #endif
619 : : #endif
620 : :
621 : : /* If the gmtime() call has failed, time_->tv_sec is too big. */
622 [ + + ]: 3 : if (tm == NULL)
623 : 1 : return NULL;
624 : :
625 [ + + ]: 2 : if (time_->tv_usec != 0)
626 : : {
627 : : /* ISO 8601 date and time format, with fractionary seconds:
628 : : * YYYY-MM-DDTHH:MM:SS.MMMMMMZ
629 : : */
630 : 1 : retval = g_strdup_printf ("%4d-%02d-%02dT%02d:%02d:%02d.%06ldZ",
631 : 1 : tm->tm_year + 1900,
632 : 1 : tm->tm_mon + 1,
633 : : tm->tm_mday,
634 : : tm->tm_hour,
635 : : tm->tm_min,
636 : : tm->tm_sec,
637 : : time_->tv_usec);
638 : : }
639 : : else
640 : : {
641 : : /* ISO 8601 date and time format:
642 : : * YYYY-MM-DDTHH:MM:SSZ
643 : : */
644 : 1 : retval = g_strdup_printf ("%4d-%02d-%02dT%02d:%02d:%02dZ",
645 : 1 : tm->tm_year + 1900,
646 : 1 : tm->tm_mon + 1,
647 : : tm->tm_mday,
648 : : tm->tm_hour,
649 : : tm->tm_min,
650 : : tm->tm_sec);
651 : : }
652 : :
653 : 2 : return retval;
654 : : }
655 : : G_GNUC_END_IGNORE_DEPRECATIONS
|