Reading Calendar Time: gettimeofday() & time()

Reading Calendar Time: gettimeofday() & time()
Chapter 10 Series — Part 3: System Calls for Getting Current Time
µs
Microsecond Precision
2
System Calls Covered
timeval
Key Structure

How Does Your Program Read the Current Time?

Your program cannot read the hardware clock directly. It asks the Linux kernel through a system call. Linux provides two system calls for reading the current calendar time: time() (seconds precision) and gettimeofday() (microsecond precision). This post explains both, when to use each, and the structures involved.

Keywords in This Post

gettimeofday() time() struct timeval tv_sec tv_usec suseconds_t sys/time.h

🕐 gettimeofday() — Microsecond Precision

gettimeofday() fills a struct timeval with the current time broken into seconds and microseconds since the Epoch. Include <sys/time.h> to use it.

#include <sys/time.h>

int gettimeofday(struct timeval *tv, struct timezone *tz);
/* Returns 0 on success, -1 on error */

struct timeval {
    time_t      tv_sec;   /* Seconds since the Epoch */
    suseconds_t tv_usec;  /* Additional microseconds (0 to 999999) */
};

Field Type What it holds Example value
tv_sec time_t Whole seconds since Epoch 1747267215
tv_usec suseconds_t Additional microseconds (fractional part) 715616

What does microsecond precision mean in practice?
If you are benchmarking a sorting algorithm that runs in 2.4 milliseconds, you need gettimeofday()time() with its 1-second precision would show both “start” and “end” as the same second and give you a duration of 0.

The second argument tz (of type struct timezone) is a historical leftover from older UNIX. It was meant to carry timezone information, but the design was flawed. On Linux, it is completely ignored. Always pass NULL.

#include <sys/time.h>
#include <stdio.h>

int main(void)
{
    struct timeval tv;

    if (gettimeofday(&tv, NULL) == -1) {
        perror("gettimeofday");
        return 1;
    }

    printf("Seconds since Epoch : %ld\n", (long)tv.tv_sec);
    printf("Additional microsecs: %ld\n", (long)tv.tv_usec);

    /* Convert to a floating-point timestamp */
    double now = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
    printf("Combined timestamp  : %.6f\n", now);

    return 0;
}

Sample output:
Seconds since Epoch : 1747267215
Additional microsecs: 715616
Combined timestamp : 1747267215.715616

⏰ Practical Example: Benchmarking Code with gettimeofday()

A common use case is measuring how long a section of code takes to run. Take two timestamps — one before and one after — then compute the difference.

#include <sys/time.h>
#include <stdio.h>

/* Returns elapsed time in milliseconds between two timevals */
double elapsed_ms(struct timeval *start, struct timeval *end)
{
    long sec_diff  = end->tv_sec  - start->tv_sec;
    long usec_diff = end->tv_usec - start->tv_usec;
    return (double)(sec_diff * 1000) + (double)(usec_diff / 1000.0);
}

int main(void)
{
    struct timeval t_start, t_end;

    gettimeofday(&t_start, NULL);

    /* ---- code to benchmark ---- */
    volatile long sum = 0;
    for (long i = 0; i < 10000000L; i++)
        sum += i;
    /* ---- end of timed section -- */

    gettimeofday(&t_end, NULL);

    printf("Loop took %.3f ms\n", elapsed_ms(&t_start, &t_end));
    return 0;
}

🕑 time() — The Simple Seconds-Only Version

time() is the older, simpler sibling of gettimeofday(). It returns the current calendar time as a plain time_t (seconds since Epoch). No microseconds, no structure — just one integer.

#include <time.h>

time_t time(time_t *timep);
/* Returns seconds since Epoch, or (time_t)-1 on error */

There are two ways to use it — both are equivalent:

#include <time.h>
#include <stdio.h>

int main(void)
{
    time_t t1, t2;

    /* Method 1: pass a pointer, result stored in both return value AND t1 */
    time(&t1);

    /* Method 2: pass NULL — cleaner, result only in return value */
    t2 = time(NULL);

    printf("t1 = %ld\n", (long)t1);
    printf("t2 = %ld\n", (long)t2);

    /* t1 and t2 will be the same (or 1 second apart at most) */
    return 0;
}

Why does time() exist when gettimeofday() is strictly better?
Historical reasons — time() appeared in early UNIX; gettimeofday() was added later in BSD. Today, time() is implemented as a thin wrapper over gettimeofday() on Linux. Use time(NULL) when you only need whole seconds (e.g., timestamping a log entry, seeding srand()). Use gettimeofday() when sub-second precision matters.

📋 Comparison: time() vs gettimeofday()
Feature time() gettimeofday()
Header <time.h> <sys/time.h>
Precision Seconds only Microseconds
Return type time_t int (fills struct timeval)
Use case Log timestamps, srand() seed Benchmarking, network RTT
Portability POSIX standard Widely available (not strictly POSIX)

Up Next in This Series

Part 4 covers time conversion functions — how to go from a raw time_t value to human-readable output using ctime(), gmtime(), localtime(), and mktime().

Next: Time Conversion Functions → All Linux Posts

Leave a Reply

Your email address will not be published. Required fields are marked *