A portable and flexible header-only C++ stopwatch class compatible with std::chrono
clocks and types.
Just include stopwatch.hpp in your project and you can use it right away.
It works on any platform with a C++17 compiler, as it doesn't rely on any platform-specific APIs.
A lot of C++ stopwatch classes I've seen online have a questionable implementation. Many have problems like using non-monotonic clocks (chrono::high_resolution_clock
can be such), having non-standard code, unsafe conversions, inefficient code generation and more. This is why I wanted to make a more ideal version. It was for myself at first, but I hope others will find it useful as well.
- Simple but flexible API.
- Efficient code generation. Most compilers can optimize the library away entirely.
- Compatibility with
chrono::duration
types. - A custom
duration_components
type to help with formatted output. - Option to use any clock type via a template argument.
- If you don't need this,
stopwatch
is a ready-to-go typedef that useschrono::steady_clock
.
- If you don't need this,
- Type-safety and correctness through using
chrono
utilities (no hand-written arithmetic).
auto timer = sw::stopwatch();
timer.start();
some_work();
auto elapsed = timer.get_elapsed<sw::d_seconds>();
std::cout
<< "Elapsed time: "
<< elapsed.count()
<< " seconds\n";
auto laps = std::vector<std::chrono::milliseconds>();
auto timer = sw::stopwatch();
laps.reserve(5);
timer.start();
for (int i{}; i < 5; i++) {
some_work(i);
// start() doubles as a "lap" function.
// It restarts the stopwatch and returns the elapsed time.
// timer.start<T>() is a shorthand for sw::convert_time<T>(timer.start())
auto elapsed = timer.start<std::chrono::milliseconds>();
laps.push_back(elapsed);
}
for (auto& lap : laps) std::cout << lap.count() << " ms\n";
auto timer = sw::stopwatch();
timer.start();
some_work();
// timer.get_elapsed<T>() is a shorthand for sw::convert_time<T>(timer.get_elapsed())
auto elapsed = timer.get_elapsed<sw::duration_components>();
std::cout
<< elapsed.hours
<< "h "
<< elapsed.minutes
<< "m "
<< elapsed.seconds
<< "s "
<< elapsed.milliseconds
<< "ms\n";
using namespace std::literals::chrono_literals;
auto starting_time = 1002ms;
auto components = sw::convert_time<sw::duration_components> (starting_time);
auto round_trip = sw::convert_time<std::chrono::milliseconds> (components);
auto round_trip_double_sec = sw::convert_time<sw::d_seconds> (round_trip);
// Prints 1 2
std::cout << components.seconds << ' ' << components.milliseconds << '\n';
// Prints 1002
std::cout << round_trip.count() << '\n';
// Prints 1.002
std::cout << round_trip_double_sec.count() << '\n';
Tests run automatically after code changes (see Actions), so there's no need to run them yourself.
If you still want to, the tests can be executed either with make
on Linux, or by building the Visual Studio 2019 solution on Windows. They include -Werror
and /WX
respectively, alongside with generous warning levels for correctness. The tests use Catch2 v2.
- v1.0
- Initial release
- v1.1
- Added support for negative values in
duration_components
which are now handled correctly in both directions byconvert_time()
.
- Added support for negative values in
- v1.1.1
- Code improvements.
- v1.1.2
- More code improvements.
- v1.2
- Renamed the
get_time()
method toget_elapsed()
. This better reflects that this is a duration. - Added
clock
member type to the class, which is an alias for the underlying clock type.
- Renamed the
- v1.2.1
- Removed a restriction in
convert_time()
that wouldn't allow achrono::duration
type to be converted to the same type.
- Removed a restriction in
- v1.2.2
- Slight code changes.
- v1.2.3
- Slight code changes.
Distributed under the MIT License.