Comparing a time_t to a struct timespec (in C)

2.4k views Asked by At

I have multiple struct timespec values and a time_t value. I want to see which struct timespec value is the closest to the time_t value. Should I just compare the seconds and ignore the nanoseconds? Or should I convert both to total nanoseconds since the epoch? Or maybe convert both to total nanoseconds since the Epoch adding half a second to the time_t?

Background: A struct timespec has two members: .tv_sec containing the seconds since the Epoch, and .tv_nsec with additional nanoseconds. A time_t is just the seconds. In my case, the struct timespec values are from file system attributes, while the time_t value is converted from a local time string. I don't know if system calls to get the local time round nanoseconds or truncate them, so I don't know if, hypothetically, the time_t might be plus or minus a second from a struct timespec generated at the exact same time.

I could just compare the .tv_sec in each struct timespec value to the time_r value, or I could multiply each tv_sec by 1,000,000,000 and add it to its tv_nsec, and then multiply the time_t by 1,000,000,000, and then compare them? Or also add a half second to the time_r? Would converting to nanoseconds since the Epoch be worth the hassle? Also, what type should I use for that? unsigned long long?

(I don't know if I'm overthinking this or underthinking it.)

1

There are 1 answers

2
chux - Reinstate Monica On BEST ANSWER

Concern about local time should not apply as time_t (and .tv_sec which is also time_t) are time zone agnostic. They both refer to a time since a common epoch.

Use both members of timespec. Use a struct timespec to keep track of differences to negate concerns about adequate range and achieve the best answer.

Unchecked code, but enough to give OP an idea.

#include <time.h>

// Reasonable to assume .tv_nsec is in the normal range [0-999999999]
// and .tv_sec >= 0.
// Else add code to handle -1 .tv_sec and out of range ones.

// Absolute value of the difference.
static struct timespec abs_timespec(struct timespec t, time_t ref) {
  if (t.tv_sec >= ref) {
    t.tv_sec -= ref;
  } else {
    t.tv_sec = ref - t.tv_sec;
    if (t.tv_nsec > 0) {
      t.tv_nsec = 1000000000 - t.tv_nsec;
      t.tv_sec--;
    }
  }
  return t;
}

const struct timespec* compare(size_t n, const struct timespec *t, time_t ref) {
  if (n == 0) {
    return NULL;
  }

  const struct timespec *closest = &t[0];
  struct timespec best_diff = abs_timespec(t[0], ref);

  for (size_t i = 1; i < n; i++) {
    struct timespec diff = abs_timespec(t[i], ref);
    if (diff.tv_sec <= best_diff.tv_sec
        && (diff.tv_sec < best_diff.tv_sec || diff.tv_nsec < best_diff.tv_nsec)) {
      best_diff = diff;
      closest = &t[i];
    }
  }
  return closest;
}