Question

Measuring Elapsed Time in C with time() and gettimeofday()

ccpplinuxtimemeasurement

Question

I want to measure how long parts of my C program take to run.

I first tried using time() like this:

printf("**MyProgram::before time= %ld\n", time(NULL));

doSomething();
doSomethingLong();

printf("**MyProgram::after time= %ld\n", time(NULL));

What I do not understand is why the before and after values are sometimes the same.

I know this is not full profiling. I just want to measure elapsed time for a piece of code.

I also tried this approach:

struct timeval diff, startTV, endTV;

gettimeofday(&startTV, NULL);

doSomething();
doSomethingLong();

gettimeofday(&endTV, NULL);

timersub(&endTV, &startTV, &diff);

printf("**time taken = %ld %ld\n", diff.tv_sec, diff.tv_usec);

How should I interpret output like these?

  • time taken = 0 26339
  • time taken = 4 45025

Does 0 26339 mean 26,339 nanoseconds, or 26.339 milliseconds?

Does 4 45025 mean 4 seconds and 25 milliseconds, or something else?

Short Answer

By the end of this page, you will understand why time() often shows the same value before and after fast code, how gettimeofday() measures shorter durations, and how to correctly read tv_sec and tv_usec in C. You will also see safer modern alternatives and practical examples for timing code.

Concept

time() and gettimeofday() both deal with time, but they are used at different levels of precision.

time() returns the current calendar time in whole seconds since the Unix epoch. That means it has 1-second resolution. If your code finishes in less than one second, the value before and after may be identical.

For example, if both calls happen during the same second:

time_t a = time(NULL);
/* code runs quickly */
time_t b = time(NULL);

a and b can be equal even though time did pass.

gettimeofday() gives you a struct timeval, which contains:

  • tv_sec: whole seconds
  • tv_usec: microseconds

A microsecond is 1/1,000,000 of a second.

So this structure lets you measure much smaller intervals than time().

Example:

struct timeval tv;
gettimeofday(&tv, NULL);

If you subtract two timeval values, the result tells you elapsed time as:

  • diff.tv_sec = seconds
  • diff.tv_usec = leftover microseconds

So:

  • 0 26339 means 0 seconds and 26,339 microseconds
  • 4 45025 means 4 seconds and 45,025 microseconds

That is:

  • 26,339 microseconds = 26.339 milliseconds
  • 45,025 microseconds = 45.025 milliseconds

So 4 45025 means 4.045025 seconds total.

Why this matters in real programming:

  • performance checks often need sub-second precision
  • network, file, and database operations are often measured in milliseconds
  • debugging slow code requires more detail than whole seconds

One important note: gettimeofday() gives wall-clock time, which can be affected by system clock changes. In modern C on POSIX systems, clock_gettime() with a monotonic clock is often preferred for elapsed timing.

Mental Model

Think of time() as a wall clock that only shows hours, minutes, and seconds, but no fractions of a second. If you look at it twice very quickly, it may show the same second both times.

Think of gettimeofday() as a stopwatch that shows:

  • seconds
  • tiny fractions of a second

So if time() is like saying, "The race started at 10:15:03 and ended at 10:15:03," gettimeofday() is like saying, "It took 0.026339 seconds."

Another way to picture struct timeval:

  • tv_sec = the big unit bucket
  • tv_usec = the leftover small-unit bucket

Together they describe one elapsed duration.

So 4 45025 is not two unrelated numbers. It means:

  • 4 full seconds
  • plus 45,025 microseconds
  • total: 4.045025 seconds
Take Quiz

Syntax and Examples

The basic syntax with gettimeofday() looks like this:

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

int main(void) {
    struct timeval start, end, diff;

    gettimeofday(&start, NULL);

    /* code to measure */

    gettimeofday(&end, NULL);
    timersub(&end, &start, &diff);

    printf("Elapsed: %ld.%06ld seconds\n", diff.tv_sec, diff.tv_usec);
    return 0;
}

What the fields mean

  • diff.tv_sec is the number of whole seconds
  • diff.tv_usec is the remaining microseconds
  • %06ld prints microseconds with leading zeros so the decimal-style output looks correct

Example with a delay

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

int main(void) {
    struct timeval start, end, diff;

    gettimeofday(&start, NULL);

    usleep(26339); /* sleep for 26,339 microseconds */

    gettimeofday(&end, NULL);
    timersub(&end, &start, &diff);

    printf("Elapsed: %ld seconds and %ld microseconds\n", diff.tv_sec, diff.tv_usec);
    printf("Elapsed: %ld.%06ld seconds\n", diff.tv_sec, diff.tv_usec);

    return 0;
}

Possible output:

Elapsed: 0 seconds and 26339 microseconds
Elapsed: 0.026339 seconds

Convert to milliseconds

long milliseconds = diff.tv_sec * 1000L + diff.tv_usec / 1000L;
printf("Elapsed: %ld ms\n", milliseconds);

Be aware that integer division removes fractions. If you want decimal milliseconds:

double ms = diff.tv_sec * 1000.0 + diff.tv_usec / 1000.0;
printf("Elapsed: %.3f ms\n", ms);

Why time() shows the same value

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

int main(void) {
    time_t start = time(NULL);

    /* fast code */

    time_t end = time(NULL);

    printf("Start: %ld\n", (long)start);
    printf("End:   %ld\n", (long)end);
    printf("Diff:  %ld seconds\n", (long)(end - start));

    return 0;
}

If the code runs in under one second, Diff may be 0. That is expected.

Step by Step Execution

Consider this example:

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

int main(void) {
    struct timeval start, end, diff;

    gettimeofday(&start, NULL);
    usleep(45025);
    gettimeofday(&end, NULL);

    timersub(&end, &start, &diff);

    printf("%ld %ld\n", diff.tv_sec, diff.tv_usec);
    return 0;
}

Step by step

  1. gettimeofday(&start, NULL);

    • The current time is stored in start.
    • Example:
      • start.tv_sec = 100
      • start.tv_usec = 200000
  2. usleep(45025);

    • The program waits about 45,025 microseconds.
    • That is about 45.025 milliseconds.
  3. gettimeofday(&end, NULL);

    • The current time is stored in end.
    • Example:
      • end.tv_sec = 100
      • end.tv_usec = 245025
  4. timersub(&end, &start, &diff);

    • diff = end - start
    • Result:
      • diff.tv_sec = 0
      • diff.tv_usec = 45025
  5. printf("%ld %ld\n", diff.tv_sec, diff.tv_usec);

    • Prints:
0 45025

Another example crossing a second boundary

Suppose:

  • start = 100 sec, 980000 usec
  • end = 105 sec, 25000 usec

After subtraction:

  • elapsed = 4 sec and 45025 usec

So the result becomes:

4 45025

This means:

  • 4 whole seconds
  • plus 45,025 microseconds
  • total = 4.045025 seconds

Unit conversions

ValueMeaning
1 second1,000 milliseconds
1 millisecond1,000 microseconds
1 microsecond1,000 nanoseconds

So:

  • 26339 microseconds = 26.339 milliseconds
  • not 26,339 nanoseconds

That is because tv_usec is microseconds, not nanoseconds.

Real World Use Cases

Measuring elapsed time is common in many kinds of C programs.

1. Benchmarking a function

You may want to compare two implementations of the same algorithm.

gettimeofday(&start, NULL);
sort_data(items, count);
gettimeofday(&end, NULL);

2. Measuring file I/O

You can check how long it takes to read or write a large file.

  • loading logs
  • parsing CSV data
  • saving reports

3. Monitoring network calls

If your program talks to a server, timing helps identify slow requests.

  • DNS lookup
  • socket connect
  • data receive

4. Checking startup performance

Developers often time stages such as:

  • reading configuration
  • initializing libraries
  • connecting to databases

5. Debugging user complaints

If users say a feature is slow, small timing logs can reveal where time is spent.

Example:

printf("Loading config...\n");
gettimeofday(&start, NULL);
load_config();
gettimeofday(&end, NULL);

6. Batch and data-processing scripts

For scripts that process many records, it helps to know:

  • total runtime
  • time per batch
  • time per major step
Take Quiz

Real Codebase Usage

In real projects, developers usually do more than print two timestamps.

Common patterns

Guard timing around specific blocks

gettimeofday(&start, NULL);
if (load_data() != 0) {
    return 1;
}
gettimeofday(&end, NULL);

This isolates the time for one operation.

Log both total time and stage time

Large programs often measure phases separately:

  • initialization
  • processing
  • cleanup

Wrap timing in helper functions or macros

Instead of repeating timing code everywhere, teams often create utilities.

double elapsed_ms(struct timeval start, struct timeval end) {
    return (end.tv_sec - start.tv_sec) * 1000.0 +
           (end.tv_usec - start.tv_usec) / 1000.0;
}

Use early returns carefully

If your function has multiple exits, make sure timing still gets recorded when needed.

Prefer monotonic clocks for elapsed time

In production code, clock_gettime(CLOCK_MONOTONIC, ...) is often better than gettimeofday() because it is not affected by wall-clock adjustments.

Example helper-based usage

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

double elapsed_ms(struct timeval start, struct timeval end) {
    return (end.tv_sec - start.tv_sec) * 1000.0 +
           (end.tv_usec - start.tv_usec) / 1000.0;
}

int main(void) {
    struct timeval start, end;

    gettimeofday(&start, NULL);
    /* run task */
    gettimeofday(&end, NULL);

    printf("Task took %.3f ms\n", elapsed_ms(start, end));
    return 0;
}

This style is easier to reuse and read.

Common Mistakes

1. Confusing microseconds with nanoseconds

tv_usec means microseconds, not nanoseconds.

Broken interpretation:

/* Wrong idea: 26339 means nanoseconds */

Correct interpretation:

  • 26339 usec = 26.339 ms

2. Expecting time() to measure fast code

time() only has second-level resolution.

Broken expectation:

printf("%ld\n", time(NULL));
fast_function();
printf("%ld\n", time(NULL));

If fast_function() takes under one second, both values may match.

3. Printing elapsed time in a confusing format

This output:

printf("%ld %ld\n", diff.tv_sec, diff.tv_usec);

is technically correct, but easy to misread.

Prefer:

printf("%ld.%06ld seconds\n", diff.tv_sec, diff.tv_usec);

4. Forgetting zero padding for microseconds

Broken:

printf("%ld.%ld\n", diff.tv_sec, diff.tv_usec);

If tv_usec is 25, this prints something like 4.25, which looks like 4.25 seconds, but really means 4.000025 seconds.

Correct:

printf("%ld.%06ld\n", diff.tv_sec, diff.tv_usec);

5. Using wall-clock time for precise benchmarking

gettimeofday() can be affected by system time changes.

For better elapsed timing on POSIX systems, use monotonic clocks when available.

6. Doing manual subtraction incorrectly

If you subtract microseconds yourself, crossing a second boundary can be tricky.

Broken code:

long sec = end.tv_sec - start.tv_sec;
long usec = end.tv_usec - start.tv_usec;

If end.tv_usec < start.tv_usec, usec becomes negative.

Safer:

timersub(&end, &start, &diff);

7. Timing code only once

A single run can be noisy because of:

  • OS scheduling
  • cache warmup
  • background tasks

For rough benchmarking, run several times and average the results.

Comparisons

MethodResolutionGood forLimitation
time()SecondsLogging wall time, coarse timestampsToo coarse for fast operations
gettimeofday()MicrosecondsSimple elapsed timing, debuggingAffected by system clock changes
clock()CPU time ticksMeasuring CPU time used by the processNot the same as real elapsed time
clock_gettime(CLOCK_MONOTONIC)Usually very fineBest choice for elapsed timing on POSIXSlightly more setup

time() vs gettimeofday()

  • Use time() when whole seconds are enough.
  • Use gettimeofday() when you need sub-second detail.

gettimeofday() vs clock_gettime()

  • gettimeofday() measures wall-clock time.
  • clock_gettime(CLOCK_MONOTONIC, ...) measures steadily increasing time for elapsed duration.

clock() vs wall-clock time

clock() measures CPU time consumed by the program, not necessarily the real time a user waits.

If your program sleeps or waits on I/O, clock() may not reflect that delay.

Take Quiz

Cheat Sheet

  • time(NULL) returns current time in seconds.
  • Fast code may show the same time() value before and after.
  • gettimeofday() fills a struct timeval.
  • tv_sec = seconds
  • tv_usec = microseconds
  • 1 ms = 1000 usec
  • 1 usec = 1000 ns

Read these results

  • 0 26339 = 0 seconds + 26339 microseconds
  • 0 26339 = 26.339 ms
  • 4 45025 = 4 seconds + 45025 microseconds
  • 4 45025 = 4.045025 s

Typical timing pattern

struct timeval start, end, diff;
gettimeofday(&start, NULL);

/* code */

gettimeofday(&end, NULL);
timersub(&end, &start, &diff);
printf("%ld.%06ld seconds\n", diff.tv_sec, diff.tv_usec);

Convert to milliseconds

double ms = diff.tv_sec * 1000.0 + diff.tv_usec / 1000.0;

Better display format

printf("%ld.%06ld seconds\n", diff.tv_sec, diff.tv_usec);

Watch out for

  • tv_usec is microseconds, not nanoseconds
  • time() is too coarse for short tasks
  • %06ld is important for proper formatting
  • gettimeofday() is wall-clock based
  • clock_gettime(CLOCK_MONOTONIC, ...) is often better for elapsed timing

FAQ

Why are time() values before and after my function the same?

Because time() only measures whole seconds. If your code runs in less than one second, both calls can return the same value.

Does tv_usec mean nanoseconds?

No. tv_usec means microseconds.

How many milliseconds is 26339 microseconds?

26339 microseconds is 26.339 milliseconds.

What does 4 45025 mean in struct timeval output?

It means 4 seconds and 45,025 microseconds, which is 4.045025 seconds total.

Is gettimeofday() good for benchmarking?

It is good for simple measurements, but for more reliable elapsed timing, clock_gettime(CLOCK_MONOTONIC, ...) is usually better.

Should I print tv_sec and tv_usec separately?

You can, but printing as seconds.microseconds is usually easier to read.

Why use %06ld when printing microseconds?

Because microseconds should always take 6 digits. This preserves the correct decimal-style format.

Can I use clock() instead?

Yes, but clock() measures CPU time, not real elapsed wall time. That can give different results.

Take Quiz

Mini Project

Description

Build a small C program that times several tasks and prints the elapsed duration in both microseconds and milliseconds. This demonstrates how to measure code execution more clearly than using time() alone.

Goal

Create a timing utility that measures short operations and prints human-readable elapsed times.

Requirements

  • Use gettimeofday() to capture a start and end time.
  • Measure at least two separate operations.
  • Print the elapsed result as seconds, microseconds, and milliseconds.
  • Format microseconds correctly using zero padding.
  • Include one short operation and one longer operation for comparison.
Take Quiz

Keep learning

Related questions

View more