Skip to Content
Course content

249: std::chrono for Time and Durations

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this happen in almost every code review I've done for junior devs moving from C or Python to C++: they treat time as a simple number. They'll create an int or a double called elapsed_time, assume it's in milliseconds, and then spend the next three hours debugging a production crash because one library returned seconds and another returned microseconds.

Stop treating time as a raw integer

The biggest misconception about std::chrono is that it's just a "clunky" way to get the current time. In reality, it's a type-safety system designed specifically to stop you from accidentally adding "5 apples" to "10 oranges"—or in this case, adding 5 seconds to 10 milliseconds.

Look at this common mistake:

auto start = std::chrono::steady_clock::now();
// ... some heavy work ...
auto end = std::chrono::steady_clock::now();

// WRONG: This won't even compile.
auto duration = end - start;
int ms = duration; 

You'll get a mountain of template error messages. Why? Because duration isn't an integer; it's a std::chrono::duration object. C++ refuses to implicitly convert a typed duration into a raw number because that's exactly where the "is this seconds or milliseconds?" bugs come from. I used to fight this when I first learned it, but once you realize the type system is actually protecting you from yourself, it becomes a superpower.

Distinguishing Time Points from Durations

To use chrono effectively, you have to keep two concepts strictly separate in your head: time_point and duration.

  • time_point: A specific moment in time (like "Tuesday at 2:00 PM"). In code, this is usually what you get from std::chrono::steady_clock::now().
  • duration: A span of time (like "42 milliseconds"). This is the result of subtracting one time_point from another.

If you want to represent a specific amount of time, use the built-in aliases like std::chrono::milliseconds or std::chrono::seconds. They make the code read like English:

#include <chrono>
#include <iostream>
#include <thread>

void wait_for_server() {
    using namespace std::chrono_literals; // Enables suffixes like 500ms
    
    std::cout <"Waiting for response..."< std::endl;
    
    // We pass a duration here
    std::this_thread::sleep_for(500ms); 
    
    std::cout <"Done!"< std::endl;
}

Handling precision with duration_cast

Here is where things get a bit annoying. C++ allows implicit conversions if you are moving from a coarse unit to a fine unit (e.g., seconds to milliseconds), because there's no loss of data. But it forbids them in the other direction.

If you have a duration in nanoseconds and you want to store it as milliseconds, you're losing precision. C++ forces you to be explicit about this using std::chrono::duration_cast. I consider this a "sanity check" for the developer.

Here is the professional way to time a block of code:

auto start = std::chrono::steady_clock::now();

// Simulate work
std::this_thread::sleep_for(std::chrono::milliseconds(123));

auto end = std::chrono::steady_clock::now();

// Subtracting two time_points gives us a duration
auto diff = end - start;

// Explicitly cast to the unit you actually want to print/use
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(diff);

std::cout < "Elapsed time: " < ms.count() < "ms" < std::endl;

Note the .count() member function. That is the only place where the type-safe duration turns back into a raw number. Use it only at the very last second—usually right when you're printing to the console or saving to a database.




📋 Practical Task

Build a High-Precision Ability Cooldown Tracker

In game development, you often need to ensure an ability (like a "Fireball") cannot be used more than once every X milliseconds. Your task is to implement a CooldownManager class that handles this using std::chrono.

Requirements:

  • Create a class CooldownManager.
  • It should have a constructor that takes a std::chrono::milliseconds value to set the cooldown period.
  • Implement a method bool can_use_ability().
    • It returns true if the cooldown has expired and updates the "last used" timestamp to the current time.
    • It returns false if the ability is still on cooldown.
  • Use std::chrono::steady_clock to ensure the timer isn't affected by the user changing the system wall-clock time.

Test Case: Initialize the manager with a 500ms cooldown. Call can_use_ability() once (should be true), call it again immediately (should be false), sleep for 600ms, and call it again (should be true).

Rating
0 0

There are no comments for now.

to be the first to leave a comment.