DateTimes in C++ require quite a bit of a learning curve. They’re still evolving and nowhere near to being full-featured or friendly to use.
Up until C++11, the best you could do with the builtin date and time types came from the C libraries. C++11 defines the chrono library which allows you to specify durations, time points, and clocks. Think of a time point as a specific point on a number line. This is good because number lines have positive and negative numbers and that means there has to be some point on the number line that represents zero. All the other points are relative to this zero point.
In computer dates and times, this zero point is called the epoch. It represents some point that all the dates and times are relative to. Different systems have different epochs. Here’s just three of the more famous epoch dates. There have been more and there still are more epoch dates being used. And there will likely be others.
- January 1st in the year 1. This is currently used by C#.
- January 1st, 1601. This is used in the Windows file system.
- January 1st 1970. This is the UNIX epoch and is used extensively today in a lot of languages including C++, Java, PHP, Python, and Ruby. It’s also used in Linux and Mac computers.
You can think of a time interval as the amount of time between two time points on the number line. And a duration can be thought of like a piece of string that matches the length of some interval but is not attached to any specific point.
So what’s a clock? You can think of this as something that places regular marks along the number line. This is like a drummer beating out a regular rhythm. When did the drummer first start beating the drum? You see, a clock isn’t just a bunch of regular marks. A clock needs a starting point. And that starting point is the epoch. Unlike a drummer, a clock can place regular marks before the epoch. These marks are called ticks.
Because the clock generates regular ticks, all we need to do is count how many ticks we want either before or after the epoch in order to place a specific time point. These ticks have been the source of many of the troubles that programmers have had to deal with. Computers don’t store arbitrarily large numbers. There are limits and that means that clocks like this have specific minimum and maximum time points. As the ticks get faster, the clock gets more accurate but also needs a bigger number to store time points. And traditionally, durations were also specified in terms of the same tick rate. A duration is like a time point that’s just not attached to the number line. In other words, it’s not attached to the epoch.
This is where the chrono library made some good choices. The duration class can be specified not in terms of ticks but in whatever spacing of marks you want. Want a duration that works in terms of hours? No problem. Seconds? Well, that’s what it actually uses as a starting point. Milliseconds? No problem. But it’s more powerful than this. Want durations based on a third of a second? How about 42 second marks?
You get to specify a ratio based on a second that defines whatever unit of time you want to use to count out your duration. The chrono library decoupled durations from the system clock and lets you decide what to use. This lets durations be defined however an application needs instead of what the system clock provides. If you want your durations to count out 42 second chunks of time, then specify a ratio of 42 to 1. The 1 in the ratio represents the second. If you want a duration to count out even chunks that are 1 second each, then the ratio is 1 to 1. If you want milliseconds, then the ration is 1 to one thousand. Microseconds uses a ration of 1 to one million.
The point is that the chrono library has some nice abstraction. But it doesn’t know anything about leap years, or the fact that February is shorter than March.