Date and time manipulation and conversion
The time.h
header provides functionality for date and time manipulation and conversion.
Manipulation
clock function
clock_t clock(void);
- Returns the processor time used by the program since it started.
If the processor time used is not available, −1 is returned.
Code
#include <stdio.h> // "printf" and "puts".
#include <time.h> // "clock", "clock_t" and "CLOCKS_PER_SEC".
void print_time(void);
int main(void)
{
print_time();
puts("Entering loop.");
for (int i = 0; i < 1000000000; ++i)
{
// Looping a billion times.
}
puts("Exited loop.");
print_time();
return 0;
}
void print_time(void)
{
clock_t ticks = clock();
printf("Seconds since start: %f\n", (double)ticks / (double)CLOCKS_PER_SEC);
}
Execution
Standard output stream:
Seconds since start: 0.000500 Entering loop. Exited loop. Seconds since start: 1.500000
The numbers will be determined by the processor clock rate.
Explanation
The main
function invokes the print_time
function which prints out the number of seconds since the program started. This is achieved by invoking the clock
function which returns the number of ticks since the program started. The number of ticks is divided by CLOCKS_PER_SEC
to get the number of seconds.
Duration or the length of time a task takes can be computed by subtracting an older clock_t
from a newer clock_t
. By subtracting 0.000500 from 1.500000, the length of time it took to loop a billion times is determined (1.499500 seconds).
difftime function
double difftime(time_t time1, time_t time0);
- Computes difference between two calender times and returns it.
Code
#include <stdio.h> // "printf" and "puts".
#include <time.h> // "difftime", "NULL" and "time_t".
int main(void)
{
time_t timeBefore = time(NULL);
puts("Entering loop.");
for (int i = 0; i < 1000000000; ++i)
{
// Looping a billion times.
}
puts("Exited loop.");
time_t timeAfter = time(NULL);
printf("Task duration: %.f\n", difftime(timeAfter, timeBefore));
return 0;
}
Execution
Standard output stream:
Entering loop. Exited loop. Task duration: 2
The duration will be determined by the processor clock rate.
Explanation
The main
function records the time before and after running the loop. It then invokes the difftime
function which calculates the difference between the two times, i.e. the duration of the loop.
The same result can be obtained by subtracting an older time_t
from a newer time_t
as that is essentially what the function does. Note that the function returns a double
.
mktime function
time_t mktime(struct tm *timeptr);
- Normalises calendar date and time broken down into its components and returns it as calendar time since Unix epoch (00:00:00 UTC on 1 January 1970).
If calendar time can not be represented, −1 is returned.
Categorically, this function performs both manipulation and conversion.
Code
#include <stdio.h> // "printf" and "puts".
#include <time.h> // "asctime", "mktime" and "tm".
int main(void)
{
int const unixEpoch = 1900;
int day = 1; // First day of the month (1-based).
int month = 0; // First month of the year (0-based).
int year = 2020 - unixEpoch; // Year 2020 (1990-based).
struct tm dateTime =
{
.tm_sec = 61, // Invalid. Range is 0 to 60.
.tm_min = 60, // Invalid. Range is 0 to 59.
.tm_hour = 24, // Invalid. Range is 0 to 23.
.tm_mday = day, // Valid.
.tm_mon = month, // Valid.
.tm_year = year // Valid.
};
puts("Before normalisation (invalid):");
puts("");
printf("%s\n", asctime(&dateTime));
printf("tm_sec: %i\n", dateTime.tm_sec);
printf("tm_min: %i\n", dateTime.tm_min);
printf("tm_hour: %i\n", dateTime.tm_hour);
printf("tm_mday: %i\n", dateTime.tm_mday);
printf("tm_mon: %i\n", dateTime.tm_mon);
printf("tm_year: %i\n", dateTime.tm_year);
printf("tm_wday: %i\n", dateTime.tm_wday);
printf("tm_yday: %i\n", dateTime.tm_yday);
printf("tm_isdst: %i\n", dateTime.tm_isdst);
mktime(&dateTime);
puts("");
puts("After normalisation (valid):");
puts("");
printf("%s\n", asctime(&dateTime));
printf("tm_sec: %i\n", dateTime.tm_sec);
printf("tm_min: %i\n", dateTime.tm_min);
printf("tm_hour: %i\n", dateTime.tm_hour);
printf("tm_mday: %i\n", dateTime.tm_mday);
printf("tm_mon: %i\n", dateTime.tm_mon);
printf("tm_year: %i\n", dateTime.tm_year);
printf("tm_wday: %i\n", dateTime.tm_wday);
printf("tm_yday: %i\n", dateTime.tm_yday);
printf("tm_isdst: %i\n", dateTime.tm_isdst);
return 0;
}
Execution
Standard output stream:
Before normalisation (invalid): Sun Jan 1 24:60:61 2020 tm_sec: 61 tm_min: 60 tm_hour: 24 tm_mday: 1 tm_mon: 0 tm_year: 120 tm_wday: 0 tm_yday: 0 tm_isdst: 0 After normalisation (valid): Thu Jan 2 01:01:01 2020 tm_sec: 1 tm_min: 1 tm_hour: 1 tm_mday: 2 tm_mon: 0 tm_year: 120 tm_wday: 4 tm_yday: 1 tm_isdst: 0
Explanation
- Line 6–10: The variables
day
,month
andyear
are assigned to the date 1 January 2020. Thetm_year
member variable oftm
is 1900-based (Unix epoch), therefore the year must be represented as the number of years since the Unix epoch. - Line 12–19: A variable of type
tm
is constructed from the previously constructed date. The member variablestm_sec
,tm_min
andtm_hour
are purposely assigned values outside their respective ranges. - Line 22–35: The member variables of
dateTime
are outputted before normalisation, both as individual components of the typetm
but also as a formatted string by invoking theasctime
function. - Line 37: The
main
function invokes themktime
function and passes it thedateTime
variable for normalisation. During normalisation, the date rolls over from 1 January 2020 to 2 January 2020 due to the seconds, minutes and hours being out of their respective ranges. The member variablestm_wday
andtm_yday
are also assigned their respective appropriate values. Themktime
function then converts the normalised date intotime_t
and returns it. - Line 41–54: The member variables of
dateTime
are outputted after normalisation, both as individual components of the typetm
but also as a formatted string by invoking theasctime
function.
time function
time_t time(time_t *timer);
- Determines the current calendar time and returns it.
If*timer
is not a null pointer, the determined value is assigned to it.
If calendar time is not available, −1 is returned.
Code
#include <stdio.h> // "printf" and "puts".
#include <time.h> // "NULL", "time" and "time_t".
void print_time(void);
int main(void)
{
print_time();
puts("Entering loop.");
for (int i = 0; i < 1000000000; ++i)
{
// Looping a billion times.
}
puts("Exited loop.");
print_time();
return 0;
}
void print_time(void)
{
time_t currentTime = time(NULL);
printf("Time since Unix epoch: %li seconds\n", currentTime);
}
Execution
Standard output stream:
Time since Unix epoch: 1577836800 seconds Entering loop. Exited loop. Time since Unix epoch: 1577836802 seconds
The numbers will be determined by the processor clock rate and the time at which the code is run.
Explanation
The main
function invokes the print_time
function which prints out the number of seconds since the Unix epoch (00:00:00 UTC on 1 January 1970). This is achieved by invoking the time
function which returns the number of seconds.
Duration or the length of time a task takes can be computed by subtracting an older time_t
from a newer time_t
. By subtracting 1577836800 from 1577836802, the length of time it took to loop a billion times is determined (2 seconds).
timespec_get function
int timespec_get(struct timespec *ts, int base);
- Determines the current calendar time in the specified time base and assigns it to
*ts
.
Base will always beTIME_UTC
for GCC/glibc.
If successful, base is returned, otherwise 0.
Code
#include <stdio.h> // "printf" and "puts".
#include <time.h> // "TIME_UTC", "timespec" and "timespec_get".
void print_time(void);
int main(void)
{
print_time();
puts("Entering loop.");
for (int i = 0; i < 1000000000; ++i)
{
// Looping a billion times.
}
puts("Exited loop.");
print_time();
return 0;
}
void print_time(void)
{
struct timespec currentTime;
timespec_get(¤tTime, TIME_UTC);
printf("Time since Unix epoch: %li seconds, %li nanoseconds\n", currentTime.tv_sec, currentTime.tv_nsec);
}
Execution
Standard output stream:
Time since Unix epoch: 1577836800 seconds, 500 nanoseconds Entering loop. Exited loop. Time since Unix epoch: 1577836801 seconds, 500000 nanoseconds
The numbers will be determined by the processor clock rate and the time at which the code is run.
Explanation
The main
function invokes the print_time
function which prints out the number of seconds and nanoseconds since the Unix epoch (00:00:00 UTC on 1 January 1970). This is achieved by invoking the timespec_get
function which assigns the number of seconds and nanoseconds to the currentTime
variable.
Conversion
asctime function
char *asctime(const struct tm *timeptr);
- Returns a
char *
(string) of a formattedtm *
.
Code
#include <stdio.h> // "printf".
#include <time.h> // "asctime", "mktime" and "tm".
int main(void)
{
int const unixEpoch = 1900;
int day = 1; // First day of the month (1-based).
int month = 0; // First month of the year (0-based).
int year = 2020 - unixEpoch; // Year 2020 (1990-based).
struct tm dateTime =
{
.tm_mday = day,
.tm_mon = month,
.tm_year = year
};
mktime(&dateTime); // Normalisation.
printf("%s\n", asctime(&dateTime));
return 0;
}
Execution
Standard output stream:
Wed Jan 1 00:00:00 2020
The date and time is not affected by local time but once the date is normalised, the tm_isdst
member variable of tm
will be set according to the time zone of the host environment or program. The asctime
function does however not show information about daylight saving time.
Explanation
- Line 6–10: The variables
day
,month
andyear
are assigned to the date 1 January 2020. Thetm_year
member variable oftm
is 1900-based (Unix epoch), therefore the year must be represented as the number of years since the Unix epoch. - Line 12–17: A variable of type
tm
is constructed from the previously constructed date. - Line 19: The
main
function invokes themktime
function and passes it thedateTime
variable for normalisation. - Line 21: The
main
function passes a call to theasctime
function, which itself takes a variable of the typetm
, as an argument to theprintf
function. Theasctime
function returns a formatted string representation of thetm
variable which is consumed by theprintf
function.
ctime function
char *ctime(const time_t *timer);
- Returns a
char *
(string) of a formattedtime_t *
in local time.
Equivalent toasctime(localtime(timer))
.
Code
#include <stdio.h> // "printf".
#include <stdlib.h> // "setenv".
#include <time.h> // "asctime", "ctime", "time_t" and "tm".
int main(void)
{
time_t dateTime = 1577836800L; // 00:00:00 UTC on 1 January 2020.
setenv("TZ", "America/Santiago", 1); // Posix.
printf("Local time: %s", ctime(&dateTime));
return 0;
}
Execution
Standard output stream:
Local time: Tue Dec 31 21:00:00 2019
The date and time will depend on local time, i.e. the time zone of the host environment or program.
Explanation
The dateTime
variable is assigned a value representing the date and time 00:00:00 UTC on 1 January 2020. The setenv
function sets the time zone environment variable for the program to "America/Santiago". The ctime
function is invoked which converts dateTime
into the local time.
gmtime function
struct tm *gmtime(const time_t *timer);
- Returns a
tm *
representation oftime_t *
in UTC.
Code
#include <stdio.h> // "printf".
#include <stdlib.h> // "setenv".
#include <time.h> // "asctime", "gmtime", "time_t" and "tm".
int main(void)
{
time_t dateTime = 1577836800L; // 00:00:00 UTC on 1 January 2020.
setenv("TZ", "America/Santiago", 1); // Posix.
struct tm *utcDateTime = gmtime(&dateTime);
printf("UTC: %s", asctime(utcDateTime));
return 0;
}
Execution
Standard output stream:
UTC: Wed Jan 1 00:00:00 2020
The date and time will never be different for UTC.
Explanation
The dateTime
variable is assigned a value representing the date and time 00:00:00 UTC on 1 January 2020. The setenv
function sets the time zone environment variable for the program to "America/Santiago". The gmtime
function is invoked which returns a tm *
converted from the dateTime
variable. The asctime
function is invoked to return a formatted string representation of the tm *
variable which is consumed by the printf
function. Changing the time zone of the program has no impact on the conversion as the gmtime
function operates in UTC and not local time.
localtime function
struct tm *localtime(const time_t *timer);
- Returns a
tm *
representation oftime_t *
in local time.
Code
#include <stdio.h> // "printf".
#include <stdlib.h> // "setenv".
#include <time.h> // "asctime", "localtime", "time_t" and "tm".
int main(void)
{
time_t dateTime = 1577836800L; // 00:00:00 UTC on 1 January 2020.
setenv("TZ", "America/Santiago", 1); // Posix.
struct tm *localDateTime = localtime(&dateTime);
printf("Local time: %s", asctime(localDateTime));
return 0;
}
Execution
Standard output stream:
Local time: Tue Dec 31 21:00:00 2019
The date and time will depend on local time, i.e. the time zone of the host environment or program.
Explanation
The dateTime
variable is assigned a value representing the date and time 00:00:00 UTC on 1 January 2020. The setenv
function sets the time zone environment variable for the program to "America/Santiago". The localtime
function is invoked which returns a tm *
converted from the dateTime
variable. The asctime
function is invoked to return a formatted string representation of the tm *
variable which is consumed by the printf
function.
strftime function
size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
- Populates a
char *
(string) with a representation oftm *
in a specified format.
Returns the number of resulting characters (including null character) placed intos *
.
If the memory allocated for the string is too small, then 0 is returned.
Code
#include <stdio.h> // "puts".
#include <time.h> // "strftime" and "tm".
int main(void)
{
int const unixEpoch = 1900;
int day = 1; // First day of the month (1-based).
int month = 0; // First month of the year (0-based).
int year = 2020 - unixEpoch; // Year 2020 (1990-based).
struct tm dateTime =
{
.tm_mday = day,
.tm_mon = month,
.tm_year = year
};
mktime(&dateTime); // Normalisation.
char formattedDate[70];
if (strftime(formattedDate, sizeof formattedDate, "%c", &dateTime))
{
puts(formattedDate);
}
return 0;
}
Execution
Standard output stream:
Sun Jan 1 00:00:00 2020
The date and time is not affected by local time but once the date is normalised, the tm_isdst
member variable of tm
will be set according to the time zone of the host environment. The strftime
function will show information about daylight saving time if passed the z
or Z
format specifier.
Explanation
- Line 6–10: The variables
day
,month
andyear
are assigned to the date 1 January 2020. Thetm_year
member variable oftm
is 1900-based (Unix epoch), therefore the year must be represented as the number of years since the Unix epoch. - Line 12–17: A variable of type
tm
is constructed from the previously constructed date. - Line 19: The
main
function invokes themktime
function and passes it thedateTime
variable for normalisation. - Line 21: A
char
array is declared to hold the formatted representation of the constructed date and time. - Line 23: The
strftime
function is invoked inside an if-statement. It is passed thechar
array, its size, format specification and constructed date. If successful, the block is entered and the formatted representation is outputted.