Search code examples
c++timetimestampc++-chrono

How do I create a timer that I can query during the program and whose format is int, long or double?


I want to start a clock at the beginning of my program and use its elapsed time during the program to do some calculations, so the time should be in a int, long or double format. For example i want to calculate a debounce time but when i try it like this i get errors because the chrono high resolution clock is not in an int, long or double format and therefore i can't subtract 50ms from that (my debounceDelay) or save that value to a double (my lastDebounceTime). Originally i had a working Arduino Game (Pong) with an LCD and i want to convert this into a C++ console application. On the Arduino there was this function "millis()" that gave me the runtime in ms and this worked perfectly fine. I can't find a similar function for C++.

double lastDebounceTime = 0;
double debounceDelay = 50;

void Player1Pos() {

if ((std::chrono::high_resolution_clock::now() - lastDebounceTime) > debounceDelay) {

    if ((GetKeyState('A') & 0x8000) && (Player1Position == 0)) {
        Player1Position = 1;
        lastDebounceTime = std::chrono::high_resolution_clock::now();
    }
    else if ((GetKeyState('A') & 0x8000) && (Player1Position == 1)) {
        Player1Position = 0;
        lastDebounceTime = std::chrono::high_resolution_clock::now();
    }
}

I am very new to C++ so any help is greatly appreciated. Thank you all!


Solution

  • I find the question misguided in its attempt to force the answer to use "int, long, or double". Those are not appropriate types for the task at hand. For references, see A: Cast chrono::milliseconds to uint64_t? and A: C++ chrono - get duration as float or long long. The question should have asked about obtaining the desired functionality (whatever the code block is supposed to do), rather than asking about a pre-chosen approach to the desired functionality. So that is what I will answer first.


    Getting the desired result

    To get the code block to compile, you just have to drop the insistence that the variables be "int, long, or double". Instead, use time-oriented types for time-oriented data. Here are the first two variables in the code block:

    double lastDebounceTime = 0;
    double debounceDelay = 50;
    

    The first is supposed to represent a point in time, and the second a time duration. The C++ type for representing a point in time is std::chrono::time_point, and the C++ type for a time duration is a std::chrono::duration. Almost. Technically, these are not types, but type templates. To get actual types, some template arguments need to be supplied. Fortunately, we can get the compiler to synthesize the arguments for us.

    The following code block compiles. You might note that I left out details that I consider irrelevant to the question at hand, hence that I feel should have been left out of the minimal reproducible example. Take this as an example of how to simplify code when asking questions in the future.

    // Use the <chrono> library when measuring time
    #include <chrono>
    
    // Enable use of the `ms` suffix.
    using namespace std::chrono_literals;
    
    std::chrono::high_resolution_clock::time_point lastDebounceTime;
    // Alternatively, if the initialization to zero is not crucial:
    // auto lastDebounceTime = std::chrono::high_resolution_clock::now();
    auto debounceDelay = 50ms;
    
    void Player1Pos() {
        if ((std::chrono::high_resolution_clock::now() - lastDebounceTime) > debounceDelay) {
            // Do stuff
            lastDebounceTime = std::chrono::high_resolution_clock::now();
        }
    }
    

    Subtracting two time_points produces a duration, which can be compared to another duration. The logic works and now is type-safe.


    Getting the desired approach

    OK, back to the question that was actually asked. You can convert the value returned by now() to an arithmetic type (integer or floating point) with the following code. You should doubts about using this code after reading the comment that goes with it.

    // Get the number of [some time units] since [some special time].
    std::chrono::high_resolution_clock::now().time_since_epoch().count();
    

    The time units involved are not specified by the standard, but are instead whatever std::chrono::high_resolution_clock::period corresponds to, not necessarily milliseconds. The special time is called the clock's epoch, which could be anything. Fortunately for your use case, the exact epoch does not matter – you just need it to be constant for each run of the program, which it is. However, the unknown units could be a problem, requiring more code to handle correctly.

    I find the appropriate types easier to use than trying to get this conversion correct. Especially since it required no change to your function.