Shifting calendar time values on a struct tm

Posted by Diego Assencio on 2016.01.23 under Programming (C/C++)

A struct tm object (or, equivalently, std::tm in C++) stores a calendar time value with precision of one second.

Programmers who deal with time values often need to solve the following problem: if one adds a fixed amount of time to a given calendar time, what will be the resulting calendar time? For instance, given an instance of struct tm storing the calendar time "Fri Jan 22 12:35:20 2016", what will be the resulting calendar time if we add, say, 15 days and 12 hours to it?

Fortunately, the solution to this problem is very easy. As a first step, we just add any amount of time shift we wish to the original struct tm object, even if the resulting object becomes invalid (e.g. if we add 65 to the tm_min field, it will no longer represent a valid "minutes" value as it will be larger than 59). After that, we use the mktime function to "renormalize" the fields of the struct_tm object. Specifically, mktime corrects all fields of a struct tm object to make them fall inside valid ranges (e.g. tm_min will again be in the closed interval [0,59]). In the process, the time shifts are applied in the same way as we would like them to. For example, if the value of tm_min is 75 after we modify it, it will be corrected to 15 and the value of tm_hour will be increased by one. If this makes the value of tm_hour larger than 23, it will be corrected as well and the value of tm_mday will be increased appropriately and so on. The example below shows what we just described:

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

int main()
	/* Fri Jan 22 12:35:20 2016 */
	struct tm caltime = {
		.tm_year = 2016 - 1900,
		.tm_yday = 21,
		.tm_mon = 0,
		.tm_wday = 5,
		.tm_mday = 22,
		.tm_hour = 12,
		.tm_min = 35,
		.tm_sec = 20,
		.tm_isdst = 0

	/* print the calendar time in human-readable format */
	printf("Original time: %s", asctime(&caltime));

	 * add 15 days and 12 hours to caltime (the final values of
	 * the members tm_mday and tm_hour will be invalid, but we
	 * will renormalize them below)
	caltime.tm_mday += 15;
	caltime.tm_hour += 12;

	/* renormalize caltime to get a valid calendar time */

	/* print the renormalized time in human-readable format */
	printf("Shifted time : %s", asctime(&caltime));

	return 0;

The output of this program is:

Original time: Fri Jan 22 12:35:20 2016
Shifted time : Sun Feb  7 00:35:20 2016

When using the technique above for adding time shifts to calendar times, keep in mind that the fields tm_wday and tm_yday are ignored by mktime, so they may not be used for this purpose.


No comments posted yet.