A real-time clock (RTC) is a clock which keeps time relative to some absolute time epoch, such as counting the number of seconds since January 1, 1970 at midnight UTC/GMT (sometimes written as 1970-01-01 UTC
). This is opposed to a regular clock which might count seconds since boot-up, for instance. Note that a real-time clock has nothing to do with a real-time operating system, which is a completely different concept.
In order to continue to keep time while a computer or system is unplugged, a real-time clock must have a backup battery, such as a tiny coin cell battery, to allow it to keep ticking while the system is without power.
Since real-time clocks keep time from a known epoch, you can use them to obtain the year, month, day, hour, minute, second, etc.
"NTP" time simply means: "Network Time Protocol (NTP)" time. This is a synchronization technique to periodically adjust each computer's local RTC so that they all read the same absolute time, at the same time. It takes real-time clocks to the next level of synchronization, since they can otherwise drift over time. NTP-adjusted RTCs can be within a few milliseconds of each other when on the same network (see: https://en.wikipedia.org/wiki/Network_Time_Protocol).
How to read an NTP-adjusted RTC (Real-time clock) timestamp on Linux
So, to read the real-time clock on Linux you do the same thing you'd do to read the NTP time on Linux, since they are one and the same: the RTC is periodically adjusted according to the NTP synchronization is all.
Obtain such a timestamp with the POSIX/Linux function clock_gettime()
, with the CLOCK_REALTIME
clock chosen. See: https://man7.org/linux/man-pages/man3/clock_gettime.3.html. It states (emphasis added):
All implementations support the system-wide real-time clock, which is
identified by CLOCK_REALTIME
. Its time represents seconds and
nanoseconds since the Epoch. When its time is changed, timers for a
relative interval are unaffected, but timers for an absolute point in
time are affected.
and:
CLOCK_REALTIME
A settable system-wide clock that measures real (i.e., wall-clock) time. Setting this clock requires appropriate privileges. This clock is affected by discontinuous jumps in the system time (e.g., if the system administrator manually changes the clock), and by the incremental adjustments performed by adjtime(3)
and NTP.
Here is an example of getting an NTP-adjusted RTC timestamp in C or C++ on a POSIX or Linux system, with full error checking.
From my code timing_clock_gettime_full_demo.c:
// Obtain a timestamp
struct timespec ts;
int retcode = clock_gettime(CLOCK_REALTIME, &ts);
if (retcode == -1)
{
printf("Failed to get a timestamp. errno = %i: %s\n",
errno, strerror(errno));
}
Now, you have whole seconds stored in ts.tv_sec
and whole nanoseconds from 0-999999999 (< 1 sec) stored in tv.tv_nsec
.
You can print this in all sorts of ways. Here is the full, runnable code with a bunch of advanced printing demos. See the link just above for the full code online.
// This define is required to bring in some of the extra POSIX features defined
// in `<time.h>`. Depending on your compiler settings, it may be required to
// get access to `clock_gettime()`. Using `-std=gnu17`, however, brings it in
// automatically since the compiler then uses the "gnu c" language instead of
// the standard "c" language.
//
// #define _POSIX_C_SOURCE 200112L
// Linux includes
// NA
// C includes
#include <errno.h> // `errno`
#include <inttypes.h> // `PRIu64`
#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h> // For `uint8_t`, `int8_t`, etc.
#include <stdio.h> // For `printf()`
#include <string.h> // `strerror(errno)`
#include <time.h> // Includes `clock_gettime()` on Linux
#define NS_PER_SEC (1000000000L)
/// Convert seconds to nanoseconds
#define SEC_TO_NS(sec) ((sec)*NS_PER_SEC)
// int main(int argc, char *argv[]) // alternative prototype
int main()
{
printf("Obtain an NTP-adjusted Real-time Clock timestamp on Linux.\n\n");
// Obtain a timestamp
struct timespec ts;
int retcode = clock_gettime(CLOCK_REALTIME, &ts);
if (retcode == -1)
{
printf("Failed to get a timestamp. errno = %i: %s\n",
errno, strerror(errno));
}
// Print seconds.nanoseconds
printf("timestamp = %li.%09li sec.\n\n", ts.tv_sec, ts.tv_nsec);
// Convert it to just `uint64_t` nanoseconds
// See: eRCaGuy_hello_world/c/timinglib.c
uint64_t ns = SEC_TO_NS((uint64_t)ts.tv_sec) + (uint64_t)ts.tv_nsec;
printf("timestamp = %" PRIu64 " nanoseconds.\n\n", ns);
// Convert it to a local time stored in `struct tm`. Use the re-entrant
// (thread-safe) version of the function, called `localtime_r()`. See:
// 1. https://man7.org/linux/man-pages/man3/localtime.3p.html
// 1. https://stackoverflow.com/a/47532938/4561887
// 1. `struct tm`: https://man7.org/linux/man-pages/man3/ctime.3.html
struct tm localtime_struct;
// Note: retptr means "return pointer"
struct tm * retptr = localtime_r(&ts.tv_sec, &localtime_struct);
if (retptr == NULL)
{
printf("Failed to convert to localtime. errno = %i: %s\n",
errno, strerror(errno));
}
printf("localtime_struct contains:\n"
" ns = %li\n" // Nanoseconds (0-999999999); NOT FROM THIS STRUCT
" sec = %i\n" // Seconds (0-60)
" min = %i\n" // Minutes (0-59)
" hour = %i\n" // Hours (0-23)
" mday = %i\n" // Day of the month (1-31)
" mon = %i\n" // Month (0-11)
" year = %i\n" // Year - 1900
" wday = %i\n" // Day of the week (0-6, Sunday = 0)
" yday = %i\n" // Day in the year (0-365, 1 Jan = 0)
" isdst = %i\n" // Daylight saving time
"\n",
ts.tv_nsec,
localtime_struct.tm_sec,
localtime_struct.tm_min,
localtime_struct.tm_hour,
localtime_struct.tm_mday,
localtime_struct.tm_mon,
localtime_struct.tm_year,
localtime_struct.tm_wday,
localtime_struct.tm_yday,
localtime_struct.tm_isdst);
// Convert the `struct tm` localtime struct to a human-readable string in
// normal human time units of Day, Month, Year, etc.
// - This is the format string required to output timestamps in the exact
// same format as `git` uses when you `git commit`.
const char * time_format_str = "%a %b %-d %H:%M:%S %Y %z";
char time_str[100];
size_t bytes_written = strftime(time_str, sizeof(time_str),
time_format_str, &localtime_struct);
if (bytes_written == 0)
{
printf("Failed to convert `struct tm` to a human-readable "
"time string.\n");
}
printf("Formatted local time string = %s\n\n", time_str);
return 0;
}
Sample build and run command, and output:
eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=gnu17 timing_clock_gettime_full_demo.c -o bin/a && bin/a
Obtain an NTP-adjusted Real-time Clock timestamp on Linux.
timestamp = 1650056712.080211270 sec.
timestamp = 1650056712080211270 nanoseconds.
localtime_struct contains:
ns = 80211270
sec = 12
min = 5
hour = 14
mday = 15
mon = 3
year = 122
wday = 5
yday = 104
isdst = 0
Formatted local time string = Fri Apr 15 14:05:12 2022 -0700
Use a system call or pipe
Keep in mind that you can also call any system call in C or C++ too, if you want. Meaning: any command-line call you can call by hand yourself in the terminal, you can call in C or C++ too.
So, if there is some system call that you can't find a C or C++ API to, just call it as a command-line system call.
The command is system()
. I have an example of that here: C equivalent of Python's exec() function.
If you need to read the output from the system call, you'll need to use a pipe, however. Here are the steps:
How to read from a pipe to read output from a system call in C:
- Run a cmd and open a pipe with
popen()
.
- Read the command response from the pipe with
fgets()
, using the file ptr to
the pipe obtained from popen()
.
- Close the pipe file with
pclose()
.
For a demo of that, study my answer here: Pipe demo: how to read keyboard presses from a system call pipe in C.
References:
- My code above, in my eRCaGuy_hello_world repo: timing_clock_gettime_full_demo.c
- Retrieve Linux Time using struct timespec
- *****https://man7.org/linux/man-pages/man3/clock_gettime.3.html
- RTC: https://en.wikipedia.org/wiki/Real-time_clock
- NTP: https://en.wikipedia.org/wiki/Network_Time_Protocol
- https://man7.org/linux/man-pages/man3/localtime.3p.html - contains a great
example of
strftime()
at the bottom too!
struct tm
: https://man7.org/linux/man-pages/man3/ctime.3.html
- https://man7.org/linux/man-pages/man3/strftime.3p.html
- My timing library
- timinglib.h
- timinglib.c
See also
- [my answer] Retrieve Linux Time using struct timespec