There are no notfications.

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

  1. Line 6–10: The variables day, month and year are assigned to the date 1 January 2020. The tm_year member variable of tm is 1900-based (Unix epoch), therefore the year must be represented as the number of years since the Unix epoch.
  2. Line 12–19: A variable of type tm is constructed from the previously constructed date. The member variables tm_sec, tm_min and tm_hour are purposely assigned values outside their respective ranges.
  3. Line 22–35: The member variables of dateTime are outputted before normalisation, both as individual components of the type tm but also as a formatted string by invoking the asctime function.
  4. Line 37: The main function invokes the mktime function and passes it the dateTime 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 variables tm_wday and tm_yday are also assigned their respective appropriate values. The mktime function then converts the normalised date into time_t and returns it.
  5. Line 41–54: The member variables of dateTime are outputted after normalisation, both as individual components of the type tm but also as a formatted string by invoking the asctime 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 be TIME_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(&currentTime, 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 formatted tm *.

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

  1. Line 6–10: The variables day, month and year are assigned to the date 1 January 2020. The tm_year member variable of tm is 1900-based (Unix epoch), therefore the year must be represented as the number of years since the Unix epoch.
  2. Line 12–17: A variable of type tm is constructed from the previously constructed date.
  3. Line 19: The main function invokes the mktime function and passes it the dateTime variable for normalisation.
  4. Line 21: The main function passes a call to the asctime function, which itself takes a variable of the type tm, as an argument to the printf function. The asctime function returns a formatted string representation of the tm variable which is consumed by the printf function.

ctime function

char *ctime(const time_t *timer);
Returns a char * (string) of a formatted time_t * in local time.
Equivalent to asctime(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 of time_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 of time_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 of tm * in a specified format.
Returns the number of resulting characters (including null character) placed into s *.
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

  1. Line 6–10: The variables day, month and year are assigned to the date 1 January 2020. The tm_year member variable of tm is 1900-based (Unix epoch), therefore the year must be represented as the number of years since the Unix epoch.
  2. Line 12–17: A variable of type tm is constructed from the previously constructed date.
  3. Line 19: The main function invokes the mktime function and passes it the dateTime variable for normalisation.
  4. Line 21: A char array is declared to hold the formatted representation of the constructed date and time.
  5. Line 23: The strftime function is invoked inside an if-statement. It is passed the char array, its size, format specification and constructed date. If successful, the block is entered and the formatted representation is outputted.