Creating a timeline with timers and events

Pages: 12

Want to thanks JLBorges that helped me to sort out the date/time problems i had with various version of mingw.

Now i have to implements events and listeners (not using boost).

What if i want to compare two date/time up to seconds?
Additions to the old code are highlighted.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <ctime>
#include <string>
#include <cmath>

struct date_time
{
    date_time( std::time_t simulated_time )
        : last_update_time( std::time(nullptr) ), simulated_time(simulated_time) {}

    date_time( int year, int month /* jan == 1 */, int day )
    {
        std::tm tm {} ;
        tm.tm_year = year - 1900 ;
        tm.tm_mon = month - 1 ;
        tm.tm_mday = day ;
        simulated_time = std::mktime( std::addressof(tm) ) ;
        if( simulated_time == -1 ) throw std::out_of_range( "time is out of range" ) ;
        last_update_time = std::time(nullptr) ;
    }

    static double ticks_per_sec() // just to be pedantically safe: almost always is 1 tick per second
    {
        static const int NTICKS = 10000 ;
        static const double ticks_per_second = NTICKS / std::difftime( std::time_t(NTICKS*2), std::time_t(NTICKS) ) ;
        return ticks_per_second ;
    }

    // call to update the simulated time. or call periodically
    // from a background thread (with std::atomic<time_t> simulated_time)
    void update()
    {
        const auto now = std::time(nullptr) ;

        // add the elapsed time between now and last updated time
        simulated_time += ticks_per_sec() * std::difftime( now, last_update_time ) ;

        last_update_time = now ; // and set the last updated time to now
    }

    void advance_secs( int secs )
    {
        update() ;
        simulated_time += secs * ticks_per_sec() ;
    }

    void advance_minutes( int minutes ) { advance_secs( minutes * 60 ) ; }
    void advance_hours( int hrs ) { advance_minutes( hrs * 60 ) ; }
    void advance_days( int days ) { advance_hours( days * 24 ) ; }

    void advance_months( int months )
    {
        update() ;
        std::tm tm = *std::localtime( std::addressof(simulated_time) ) ;
        tm.tm_mon += months ;

        simulated_time = std::mktime( std::addressof(tm) ) ;
        if( simulated_time == -1 ) throw std::out_of_range( "time is out of range" ) ;

        last_update_time = std::time(nullptr) ;
    }

    void advance_years( int yrs ) { advance_months( yrs * 12 ) ; }

    std::time_t current_simulated_time() { update() ; return simulated_time ; }

    std::string current_simulated_time_str()
    {
        update() ;
        const auto ptm = std::localtime( std::addressof(simulated_time) ) ;

        if(ptm) // if the c library supports handling this value for std::tm
        {
            char buffer[1024] {} ;
            std::strftime( buffer, sizeof(buffer), "%A, %B %d %H:%M:%S %Y", ptm ) ;
            return buffer ;
        }

        else return "time beyond what the C library can handle gracefully\n" ;
    }

    double difftime( const date_time& that ) const
    {
        return std::difftime( this->simulated_time, that.simulated_time ) +
               std::difftime( this->last_update_time, that.last_update_time ) ;
    }

    private:
        std::time_t last_update_time ; // actual calendar time
        std::time_t simulated_time ; // simulated time at the time of last update

    // save the state of the date_time (current simulated time) into an output stream
    friend std::ostream& operator << ( std::ostream& stm, const date_time& t )
    { return stm << t.simulated_time ; }

    // save the state of the updated date_time (updated simulated time) into an output stream
    friend std::ostream& operator << ( std::ostream& stm, date_time& t )
    { return stm << t.current_simulated_time() ; }

    // restore the state of the date_time  (current simulated time) from an input stream
    friend std::istream& operator >> ( std::istream& stm, date_time& t )
    {
        std::time_t stime ;
        if( stm >> stime ) t = { stime } ;
        return stm ;
    }

    // date_time comparisons are to within a second
    friend bool operator== ( const date_time& a, const date_time& b )
    { return std::abs( a.difftime(b) ) < 1.0 ; }
    friend bool operator!= ( const date_time& a, const date_time& b ) { return !( a == b ) ; }

    friend bool operator< ( const date_time& a, const date_time& b )
    { return a.difftime(b) <= -1.0 ; }
    friend bool operator> ( const date_time& a, const date_time& b )
    { return a.difftime(b) >= 1.0 ; }

    friend bool operator>= ( const date_time& a, const date_time& b ) { return !( a < b ) ; }
    friend bool operator<= ( const date_time& a, const date_time& b ) { return !( a > b ) ; }
};
Thank you. Should i replace the timer.h you've factorized?
This is struct date_time, while the previous was struct timer.



So difftime should be used?

I thought would be possible to compare in some ways as:

if (dateTime1 == dateTime2) ...


Last edited on
> Should i replace the timer.h you've factorized? This is struct date_time, while the previous was struct timer.

I renamed the old timer as date_time because that appeared to be the terminology that you wanted to use:
"What if i want to compare two date/time up to seconds?"


> I thought would be possible to compare in some ways as: if (dateTime1 == dateTime2)

Yes; all the relational operators are overloaded. See lines 107-118 in the previous post.

Here's the factorised version:

date_time.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#ifndef DATE_TIME_H_INCLUDED
#define DATE_TIME_H_INCLUDED

#include <iostream>
#include <ctime>
#include <string>
#include <cmath>
#include <stdexcept>

struct date_time
{
    date_time( std::time_t simulated_time )
        : last_update_time( std::time(nullptr) ), simulated_time(simulated_time) {}

    date_time( int year, int month /* jan == 1 */, int day ) ;

    static const double ticks_per_sec ; // just to be pedantically safe: almost always is 1 tick per second

    // call to update the simulated time. or call periodically
    // from a background thread (with std::atomic<time_t> simulated_time)
    void update()
    {
        const auto now = std::time(nullptr) ;
        // add the elapsed time between now and last updated time
        simulated_time += ticks_per_sec * std::difftime( now, last_update_time ) ;
        last_update_time = now ; // and set the last updated time to now
    }

    void advance_secs( int secs )
    {
        update() ;
        simulated_time += secs * ticks_per_sec ;
    }

    void advance_minutes( int minutes ) { advance_secs( minutes * 60 ) ; }
    void advance_hours( int hrs ) { advance_minutes( hrs * 60 ) ; }
    void advance_days( int days ) { advance_hours( days * 24 ) ; }

    void advance_months( int months ) ;
    void advance_years( int yrs ) { advance_months( yrs * 12 ) ; }

    std::time_t current_simulated_time() const { return simulated_time ; }
    std::time_t current_simulated_time() { update() ; return simulated_time ; }

    std::string current_simulated_time_str() const ;
    std::string current_simulated_time_str()
    {
        update() ;
        return const_cast< const date_time* >(this)->current_simulated_time_str() ;
    }

    double difftime( const date_time& that ) const
    {
        return std::difftime( this->simulated_time, that.simulated_time ) +
               std::difftime( this->last_update_time, that.last_update_time ) ;
    }

    private:
        std::time_t last_update_time ; // actual calendar time
        std::time_t simulated_time ; // simulated time at the time of last update

    // save the state of the date_time (current simulated time) into an output stream
    friend std::ostream& operator << ( std::ostream& stm, const date_time& t )
    { return stm << t.simulated_time ; }

    // save the state of the updated date_time (updated simulated time) into an output stream
    friend std::ostream& operator << ( std::ostream& stm, date_time& t )
    { return stm << t.current_simulated_time() ; }

    // restore the state of the date_time  (current simulated time) from an input stream
    friend std::istream& operator >> ( std::istream& stm, date_time& t )
    {
        std::time_t stime ;
        if( stm >> stime ) t = { stime } ;
        return stm ;
    }

    // date_time comparisons are to within a second
    friend bool operator== ( const date_time& a, const date_time& b )
    { return std::abs( a.difftime(b) ) < 1.0 ; }
    friend bool operator!= ( const date_time& a, const date_time& b ) { return !( a == b ) ; }

    friend bool operator< ( const date_time& a, const date_time& b )
    { return a.difftime(b) <= -1.0 ; }
    friend bool operator> ( const date_time& a, const date_time& b )
    { return a.difftime(b) >= 1.0 ; }

    friend bool operator>= ( const date_time& a, const date_time& b ) { return !( a < b ) ; }
    friend bool operator<= ( const date_time& a, const date_time& b ) { return !( a > b ) ; }
};

#endif // DATE_TIME_H_INCLUDED 


date_time.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "date_time.h"

date_time::date_time( int year, int month, int day )
{
    std::tm tm {} ;
    tm.tm_year = year - 1900 ;
    tm.tm_mon = month - 1 ;
    tm.tm_mday = day ;
    simulated_time = std::mktime( std::addressof(tm) ) ;
    if( simulated_time == -1 ) throw std::out_of_range( "time is out of range" ) ;
    last_update_time = std::time(nullptr) ;
}


void date_time::advance_months( int months )
{
    update() ;
    std::tm tm = *std::localtime( std::addressof(simulated_time) ) ;
    tm.tm_mon += months ;

    simulated_time = std::mktime( std::addressof(tm) ) ;
    if( simulated_time == -1 ) throw std::out_of_range( "time is out of range" ) ;

    last_update_time = std::time(nullptr) ;
}

std::string date_time::current_simulated_time_str() const
{
    const auto ptm = std::localtime( std::addressof(simulated_time) ) ;

    if(ptm) // if the c library supports handling this value for std::tm
    {
        char buffer[1024] {} ;
        std::strftime( buffer, sizeof(buffer), "%A, %B %d %H:%M:%S %Y", ptm ) ;
        return buffer ;
    }

    else return "time beyond what the C library can handle gracefully\n" ;
}

constexpr int NTICKS = 10000 ;
const double date_time::ticks_per_sec = NTICKS / std::difftime( std::time_t(NTICKS*2), std::time_t(NTICKS) ) ;


date_time_relops_test.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "date_time.h"

int main() // simle test driver for relational operations
{
    const date_time a( 2140, 10, 17 ) ;
    std::cout << "a == " << a.current_simulated_time_str() << '\n' ;

    date_time b(a) ;
    std::cout << "b == " << b.current_simulated_time_str() << '\n' ;
    // a relop b: == true  != false  < false  > false  <= true  >= true
    std::cout << std::boolalpha << (a==b) << ' ' << (a!=b) << ' ' << (a<b) << ' '
              << (a>b) << ' ' << (a<=b) << ' ' << (a>=b) << '\n' ;

    b.advance_secs(1) ;
    std::cout << "\nb == " << b.current_simulated_time_str() << '\n' ;
    // a relop b: == false  != true  < true  > false  <= true  >= false
    std::cout << std::boolalpha << (a==b) << ' ' << (a!=b) << ' ' << (a<b) << ' '
              << (a>b) << ' ' << (a<=b) << ' ' << (a>=b) << '\n' ;

    b.advance_secs(-2) ;
    std::cout << "\nb == " << b.current_simulated_time_str() << '\n' ;
    // a relop b: == false  != true  < false  > true  <= false  >= true
    std::cout << std::boolalpha << (a==b) << ' ' << (a!=b) << ' ' << (a<b) << ' '
              << (a>b) << ' ' << (a<=b) << ' ' << (a>=b) << '\n' ;
}
Thank you. I think one of the fastest programmer on earth :)


The time_t structure offers the possibility to access year/month/day separately, right?

> The time_t structure offers the possibility to access year/month/day separately, right?

std::time_t is a type alias for a simple arithmetic type (usually an integer type)
std::tm has fields representing the various components of a calendar time.

It is possible to perform conversions between the two.
http://en.cppreference.com/w/cpp/chrono/c/localtime
http://en.cppreference.com/w/cpp/chrono/c/mktime
Since i'm using a simulated time, i have to extract the year,month and day from the simulated time not from the original structure.

with this const date_time a( 2140, 10, 17 ) ; i can set the date, but what about the time?

I would like to store the date/time to a file, in order to retrieve the old simulated date/time when the program is restarted.

> i have to extract the year,month and day from the simulated time

date_time::current_simulated_time() returns the current simulated time as std::time_t

To extract the components of the calendar time the value returned, use std::localtime()
http://en.cppreference.com/w/cpp/chrono/c/localtime


> with this const date_time a( 2140, 10, 17 ) ; i can set the date, but what about the time?

Either modify the constructor to take three more parameters (hour, minute, second)
and/or subsequently use the advance_xxx functions.


> I would like to store the date/time to a file,
> in order to retrieve the old simulated date/time when the program is restarted.

See lines 62-68 in date_time.h
Last edited on
Thank you. Done a little routines.

Please, have a look at this tutorial: https://www.tutorialspoint.com/cplusplus/cpp_date_time.htm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <ctime>

using namespace std;

int main() {
   // current date/time based on current system
   time_t now = time(0);

   cout << "Number of sec since January 1,1970:" << now << endl;

   tm *ltm = localtime(&now);

   // print various components of tm structure.
   cout << "Year" << 1970 + ltm->tm_year<<endl;
   cout << "Month: "<< 1 + ltm->tm_mon<< endl;
   cout << "Day: "<<  ltm->tm_mday << endl;
   cout << "Time: "<< 1 + ltm->tm_hour << ":";
   cout << 1 + ltm->tm_min << ":";
   cout << 1 + ltm->tm_sec << endl;
}


> cout << "Number of sec since January 1,1970:" << now << endl;

This works as expected almost always, though it is not pedantically correct.
The standard does not require that this must be an integer type (it can be any arithmetic type) or that it must correspond to the Unix time (seconds - excluding leap seconds - since 00:00:00 January first 1970).
To be pedantically correct, see lines 41-42 in date_time.cpp.


1
2
3
>    cout << "Time: "<< 1 + ltm->tm_hour << ":";
>   cout << 1 + ltm->tm_min << ":";
>   cout << 1 + ltm->tm_sec << endl;

Do not add one to the hour, minute and second fields; or we can end up with a time like 24:60:61
See: http://en.cppreference.com/w/cpp/chrono/c/tm
Topic archived. No new replies allowed.
Pages: 12