nstime: fix unix_epoch_to_nstime().
The text format for UNIX Epoch times is <secs>[[.,]<nsecs>], with <secs> representing "seconds since the Epoch". The format of an nstime is a time_t and a nanoseonds value, where a time_t is normally "seconds since the Epoch" (don't get me started on why that's quoted and why I added "normally"; hint, it involves the words "leap" and "seconds"). So all unix_epoch_to_nstime() needs to do is conveert <secs> from ASCII decimal to binary and use it as the time_t (if it fits) and, if there's a [.,]<nsecs>, convert <nsecs> it from ASCII decimal to binary (as an "after the decimal indicator" value) and use it as the nanoseconds, otherwise set the nanoseconds to 0. It does *not*, in particular, have to involve struct tm in any fashion; doing that runs the risk of dragging in local time, but this isn't local time. This also means that it doesn't depend on strptime supporting "%s"; that's not specified in the Single UNIX Specification.
This commit is contained in:
parent
d6dfd89740
commit
9af86689dd
|
@ -17,6 +17,7 @@
|
|||
#include "epochs.h"
|
||||
#include "time_util.h"
|
||||
#include "to_str.h"
|
||||
#include "strtoi.h"
|
||||
|
||||
/* this is #defined so that we can clearly see that we have the right number of
|
||||
zeros, rather than as a guard against the number of nanoseconds in a second
|
||||
|
@ -524,24 +525,34 @@ iso8601_to_nstime(nstime_t *nstime, const char *ptr, iso8601_fmt_e format)
|
|||
guint8
|
||||
unix_epoch_to_nstime(nstime_t *nstime, const char *ptr)
|
||||
{
|
||||
struct tm tm;
|
||||
char *ptr_new;
|
||||
gint64 secs;
|
||||
const char *ptr_new;
|
||||
|
||||
gint n_chars = 0;
|
||||
guint frac = 0;
|
||||
guint8 ret_val = 0;
|
||||
const char *start = ptr;
|
||||
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
tm.tm_isdst = -1;
|
||||
nstime_set_unset(nstime);
|
||||
|
||||
if (!(ptr_new = ws_strptime(ptr, "%s", &tm))) {
|
||||
/*
|
||||
* Extract the seconds as a 64-bit signed number, as time_t
|
||||
* might be 64-bit.
|
||||
*/
|
||||
if (!ws_strtoi64(ptr, &ptr_new, &secs)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No UTC offset given; ISO 8601 says this means local time */
|
||||
nstime->secs = mktime(&tm);
|
||||
/* For now, reject times before the Epoch. */
|
||||
if (secs < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure it fits. */
|
||||
nstime->secs = (time_t) secs;
|
||||
if (nstime->secs != secs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Now let's test for fractional seconds */
|
||||
if (*ptr_new == '.' || *ptr_new == ',') {
|
||||
|
@ -569,7 +580,7 @@ unix_epoch_to_nstime(nstime_t *nstime, const char *ptr)
|
|||
/* If we didn't get frac, it's still its default of 0 */
|
||||
}
|
||||
else {
|
||||
tm.tm_sec = 0;
|
||||
frac = 0;
|
||||
}
|
||||
nstime->nsecs = frac;
|
||||
|
||||
|
|
Loading…
Reference in New Issue