fbpx

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.

Chrono library has some nice abstraction. But it doesn’t know anything about leap years, or the fact that February is shorter than March. Listen to the full episode for more or you can also read the full transcript below.

Transcript

This episode continues the explanation of DateTime data types. We’re getting to actual implementations now and languages tend to have very different notions of how to deal with dates and times. This episode will describe the C++ chrono library.

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. It’s not a general purpose DateTime library because it really has no concept of calendars or timezones. The clock is somewhat based on a calendar but not like you might expect.

The way I think of a DateTime is a data type that can manage points in time, durations, and intervals as they all apply to various time zones and calendar systems. To me, there’s very little difference between a year, a week, a day, or an hour, minute, or second other than the length of time involved. The only real difference is that days can sometimes have leap seconds and years can sometimes have an extra day.

We call a year with an extra day, a leap year. But we don’t call a day with an extra second a leap day. I’m always looking for inconsistencies like this. I think the reason is because leap seconds are fairly unnoticeable by the general population. Add an extra second to a day and the day remains mostly unchanged. But an extra day added to a year is enough to affect the year itself.

Notice that I didn’t include months when I said that I don’t see much difference between the various lengths of time. That’s because months are variable.

To be accurate though, the reason there’s such a big distinction between hours, minutes, and seconds which make up a time portion vs. years, months, weeks, and days which make up a date portion has to do with how the earth moves. The spinning of earth is closely related to times and has been traditionally seen as something that’s constant. We now know that it’s not constant and can affect the length of days.

Then there’s the orbit of the earth around the sun which is related to calendars. Throw in the moon and you get months.

Divide the land into countries with irregular borders and you get strange time zones. Add politicians and you get daylight savings time.

When computers were first being created, the full importance of accurate dates and times wasn’t fully understood. And the computers themselves just weren’t that capable yet. Who knows? Fifty years from now, we might look back and say the same thing. The point is, dates and times have been evolving and are likely to continue evolving.

The original C date and time routines kept track of time down to a second. That seems amazingly inaccurate now. But back then, it was incredible. As computers became more advanced and we started using them for more tasks, seconds weren’t good enough anymore. So the library methods had to be changed to support milliseconds or thousandths of a second. This worked well for a few years until milliseconds were no longer sufficient. So the library was changed again to support microseconds or millionths of a second.

Each change like this was disruptive and caused software to need to be updated. But we didn’t learn. If you think about it, the software industry was a bit dense in the early years and shortsighted. The whole Y2K mess came about because programmers never thought their software would still be running 20 years later. But the strange thing is that software was still being written right up until the year 2000 itself and probably even after that wasn’t compliant.

Anyway, it turns out that microseconds weren’t enough either, so the C date and time methods had to be changed yet again to support nanoseconds or billionths of a second.

And that’s when in 2011, the C++ language designers finally decided to create a library that can adapt. Because they saw the pattern and realized that it’s likely to continue. The design is very nice. I’ll explain how it works right after this message from our sponsor.

Before I get too far into the explanation, let me explain some terms.

You already know what a time point is. But I didn’t give you a good analogy yet. 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. That’s spelled e p o c h. 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.

Now, 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.

First, of all, 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 can provide. 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 1000. Microseconds uses a ration of 1 to 1 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.

I’ll do some more research and make a future episode that will give you more information about a good choice for a DateTime library in C++.