Skip to content

Commit

Permalink
common/utime: make parse() handle (our) ISO 8601 output
Browse files Browse the repository at this point in the history
- optional subsecond values
- optional timezone offset

Signed-off-by: Sage Weil <sage@redhat.com>
(cherry picked from commit 668d6e7)
  • Loading branch information
liewegas authored and cbodley committed May 30, 2019
1 parent 50f8b3a commit df9dc90
Showing 1 changed file with 46 additions and 8 deletions.
54 changes: 46 additions & 8 deletions src/include/utime.h
Expand Up @@ -348,7 +348,8 @@ class utime_t {
static int invoke_date(const std::string& date_str, utime_t *result) {
char buf[256];

SubProcess bin_date("/bin/date", SubProcess::CLOSE, SubProcess::PIPE, SubProcess::KEEP);
SubProcess bin_date("/bin/date", SubProcess::CLOSE, SubProcess::PIPE,
SubProcess::KEEP);
bin_date.add_cmd_args("-d", date_str.c_str(), "+%s %N", NULL);

int r = bin_date.spawn();
Expand Down Expand Up @@ -381,17 +382,45 @@ class utime_t {

const char *p = strptime(date.c_str(), "%Y-%m-%d", &tm);
if (p) {
if (*p == ' ') {
if (*p == ' ' || *p == 'T') {
p++;
p = strptime(p, " %H:%M:%S", &tm);
if (!p)
// strptime doesn't understand fractional/decimal seconds, and
// it also only takes format chars or literals, so we have to
// get creative.
char fmt[32] = {0};
strncpy(fmt, p, sizeof(fmt) - 1);
fmt[0] = '%';
fmt[1] = 'H';
fmt[2] = ':';
fmt[3] = '%';
fmt[4] = 'M';
fmt[6] = '%';
fmt[7] = 'S';
const char *subsec = 0;
char *q = fmt + 8;
if (*q == '.') {
++q;
subsec = p + 9;
q = fmt + 9;
while (*q && isdigit(*q)) {
++q;
}
}
// look for tz...
if (*q == '-' || *q == '+' || *q == 'Z') {
*q = '%';
*(q+1) = 'z';
*(q+2) = 0;
}
p = strptime(p, fmt, &tm);
if (!p) {
return -EINVAL;
if (nsec && *p == '.') {
++p;
}
if (nsec && subsec) {
unsigned i;
char buf[10]; /* 9 digit + null termination */
for (i = 0; (i < sizeof(buf) - 1) && isdigit(*p); ++i, ++p) {
buf[i] = *p;
for (i = 0; (i < sizeof(buf) - 1) && isdigit(*subsec); ++i, ++subsec) {
buf[i] = *subsec;
}
for (; i < sizeof(buf) - 1; ++i) {
buf[i] = '0';
Expand All @@ -418,10 +447,19 @@ class utime_t {
*nsec = (uint64_t)usec * 1000;
}
}

// apply the tm_gmtoff manually below, since none of mktime,
// gmtime, and localtime seem to do it. zero it out here just in
// case some other libc *does* apply it. :(
auto gmtoff = tm.tm_gmtoff;
tm.tm_gmtoff = 0;

time_t t = internal_timegm(&tm);
if (epoch)
*epoch = (uint64_t)t;

*epoch -= gmtoff;

if (out_date) {
char buf[32];
strftime(buf, sizeof(buf), "%F", &tm);
Expand Down

0 comments on commit df9dc90

Please sign in to comment.