Getting todays date and adding 24hrs

Pages: 12
Im having some trouble figuring out this this part.

We are working on a small project that creates bus tickets that have several classes i.e. 24 Hour ticket, ticket that is only valid for set number of rides, and a personal ticket to a individual.

Im having trouble with the 24 hour ticket part. Ive created a class, but Im strugling to do this:

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
class DayTicket : public Ticket{ //Ticket is a virtual class that will be inherited

public:
  DayTicket();

  void Print(){
    cout << "Serial number: " <<serial <<endl; //Irrelevant at the moment (will be a basic integer)
  }

  void Use(){ // THIS IS THE PART IM STRUGGLING WITH
    if (activated = 1){ /*If activated is true, then it simply needs to check the date it was activated and compare it to todays date.*/
    }

    if (activated = 0){/* If activated is false, then it needs to change it to true and save todays date in the activation date variables. 
It is supposed to be in a single variable "activation_date" but I wasnt sure as to how to do this so I opted to using 
indivudal variables for dates. and when thats done, it needs to change the activated status to true since its
activated at the time of use*/

      activated = 1;
    }
  }

protected:
  int year = 0; //For the activation date I thought it would be easier to split it between individual days/seconds etc. and add //24 hours?

  int month = 0;
  int day = 0;
  int seconds = 0;
  int minutes = 0;
  int hours = 0;

  bool activated = 0;
};


So to summarise, what I need to do is get todays date (when the program is ran) and save it as a variable 'activation_date'
and then if needed, to compare that variable again to the current date and time to check if 24hours has passed yet or not.

I hope this makes sense.

Is there an easy way to do this that Im not seeing?

Thank you.
Last edited on
> if (activated = 1)
Well you need to use == and not =

But since these are boolean variables, it's just easiest to say
1
2
3
4
5
6
if ( activated ) {
  // do something
} else {
  // do the other thing
  activated = true;
}
Oh yeah, thanks!

Its easy for the boolean variables, but I still need to be able to compare the two dates. And generate them in the first place, thats the problem Im having :/
Is there any reason why you don't use the time features that comes with the standard library?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <ctime>

using namespace std;

int main() {
   time_t now = time(0);

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


   tm *ltm = localtime(&now); //This creates a new 

   // 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 << ":"; /*I dont understand why this has +1? Surely with time zones it will 
still generate the time from the computer that ran it, so its kind of irrelevant?*/
   cout << 1 + ltm->tm_sec << endl;
}


I was kind of hoping there might be an easier way around this that Im oblivious to.

With the above example, am I right to think that I can simply assign the values to my own integers?
i.e.:
 
1970 + ltm->tm_year = year;
Last edited on
1970 + ltm->tm_year = year;
Take a look at this:

http://www.cplusplus.com/reference/ctime/tm/

For the local time it is not 1970 but 1900.

With the above example, am I right to think that I can simply assign the values to my own integers?
You could but I would not recommend it. Keeping a single value is easier.

There is also time_point (for calculations):
http://www.cplusplus.com/reference/chrono/time_point/?kw=time_point

With strftime(...) it is simple to get the string representation:
http://www.cplusplus.com/reference/ctime/strftime/?kw=strftime
Makes sense, I did just copy that example to dissect it.

Im kind of getting there I think.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <ctime>

using namespace std;

int main (){
   // current date/tim
   time_t now = time(0);

   // convert now to string form
   char* dt = ctime(&now);

   cout << "The local date and time is: " << dt << endl;

    strftime (now,80,"Now it's %I:%M%p.", dt); // IM getting errors here however, am I using this incorrectly?
// error is : cannot convert 'char*' to 'const tm*' for arguemnt '4'
    
    cout << dt <<endl;

}

Actually, came up with a slightly different way, i dont actually need to conver the time to visual time, i can use the seconds since 1970 method and compare those two.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <ctime>

using namespace std;

int main() {
   // current date/time based on current system
   time_t now = time(0);// This is the local time NOW saved in the variable 'now' in seconds since 1970

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

   return 0;

}


Now with this in hand, I need a way to compare the two variables of seconds i.e. activation_date against temporary_date and see if 24hours has passed in seconds.
Last edited on
IM getting errors here however, am I using this incorrectly?
Yes. Put the result of localtime(...) there.

Now with this in hand, I need a way to compare the two variables of seconds i.e. activation_date against temporary_date and see if 24hours has passed in seconds.
Simple calculation:

(now_seconds - past_seconds) > (24 * 60 * 60)


With time_point it is even easier:
http://www.cplusplus.com/reference/chrono/time_point/operators/
I actually jumped a bit ahead and encountered some problems.
@code777 thanks for the simple calculation, and Im reading up on the time_point now.

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
#include <iostream>
#include <string>
#include <ctime>

using namespace std;

class DayTicket{
public:
  DayTicket();

  void Use(){

    if (activated == false){

      time_t tmp_activation_date = time(0); //generates a current date.

      activation_date = tmp_activation_date; // activaiton_date is set to the date that was just generated, is this
//correct? Im not getting errors here, so I assume this is right. I want the date thats generated above to be saved
//in the double activation_date variable.

      activated = true;
      cout << "Has been activated" <<endl;
    }
  }

protected:
  double activation_date;
  bool activated = false;

};

int main()
{
    DayTicket test; //IM GETTING AN ERROR HERE WTF :D error is - undefined reference to "DayTicket::DayTicket()"

    test.Use();

    return 0;
}
activaiton_date is set to the date that was just generated, is this correct?
Yes.

IM GETTING AN ERROR HERE WTF :D error is - undefined reference to "DayTicket::DayTicket()"
You did not implement the constructor DayTicket() (i.e. it has no body). Since the constructor does nothing you can remove line 9.

I suggest to always initialize [POD] member variables:
1
2
protected:
  double activation_date = 0;
Awesome, fixed the issue.

And good point on the initializing of member variables. Im trying to get in the habit of it.

Thanks so much for all the help on this!
Sooo I thought I had it, and its working as it should, but its not printing out the ''activation_date'' as it should.
Im sure I did everything right, and I cant seem to figure out why its not printing anything!

main.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using namespace std;

int main(){

    DayTicket diana;
    BusTicket *first = &diana;
    first->Print();

    cout <<"\n";

    pirmais->Use();
    pirmais->Print();

    return 0;
}


DayTicket.h:
1
2
3
4
5
6
7
8
9
10
11
12
13

class DayTicket: public BusTicket{
    public:
        DayTicket();
        void Print();

        void Use();


    protected:
        long int activation_date = 0;
        bool activated = false;
};


and DayTicket.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

using namespace std;

DayTicket::DayTicket(){
}

void DayTicket::Print(){
    cout << "Activated = " << boolalpha << activated <<endl; //Returns true or false if its activated

        struct tm * activation_date;
        char buffer[256];
        strftime(buffer, 256, "%m/%d/%y %H:%M", activation_date); //This is here to convert the activation date to a string that can be printed

    cout << "Activated on = " << buffer <<endl; //This is where it would be printed i.e. Activated on 05/05/2019 20:19. But it just doesnt print anything - blank.
    cout << "Activation date test = " << activation_date <<endl; //Put this here to test what it shows if I print it directly, and this works, it shows the seconds
}

void DayTicket::Use(){
    if (activated == true){

      time_t test_date = time(0); // If true it compares the activation date against a temporary test_date to see if 24hours has passed

      if((test_date - activation_date) > (24*60*60)){
        cout <<"24 Hours has passed, this ticket is no longer valid. " <<endl;
        cout << "RED" <<endl;
      }

    }

    if (activated == false){ // if false, it generates a time at that moment and assigns it to the permanent activation_date variable
      time_t tmp_activation_date = time(0);
      activation_date = tmp_activation_date;

      activated = true;
      cout <<"GREEN" <<endl;
    }
}
Last edited on
Im sure I did everything right
:) When the program doesn't do what you want you can be sure that you did something wrong...

Line 10 of DayTicket.cpp: activation_date shadows the member variable with the same name. Since it is not initialized it has no valid value. You need localtime(...) (or gmtime(...) see: http://www.cplusplus.com/reference/ctime/gmtime/ ) in order to use strftime(...):
1
2
3
4
5
6
7
8
9
10
void DayTicket::Print(){
    cout << "Activated = " << boolalpha << activated <<endl; //Returns true or false if its activated

        struct tm * activation_date;
        char buffer[256];
        strftime(buffer, 256, "%m/%d/%y %H:%M", localtime(&activation_date)); //This is here to convert the activation date to a string that can be printed

    cout << "Activated on = " << buffer <<endl; //This is where it would be printed i.e. Activated on 05/05/2019 20:19. But it just doesnt print anything - blank.
    cout << "Activation date test = " << activation_date <<endl; //Put this here to test what it shows if I print it directly, and this works, it shows the seconds
}


By the way, you can simplify things:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void DayTicket::Use(){
    if (activated){ // It is less dangerous without == true

      if((time(0) - activation_date) > (24*60*60)){ // No test_date needed
        cout <<"24 Hours has passed, this ticket is no longer valid. " <<endl;
        cout << "RED" <<endl;
      }

    }
    else { // if (activated == false) is not needed
      activation_date = time(0); // tmp_activation_date is not needed

      activated = true;
      cout <<"GREEN" <<endl;
    }
}
And why not
1
2
    protected:
        time_t activation_date = 0;
?
I guess I was kind of close? :D

Ill have to read up more on this to understand the whole concept, cause it took way too long for me to understand this...

I have taken your advice on simplifying it as well, thank you!



Now the second part of this assignment.. creating an array of 2 objects for each class and then running the individual functions from those classes. Lets hope that goes better than the time thing..
Since a time_t starts in 1970, you can use activationTime==0 to indicate that it hasn't been activated yet.

Pro tip: in the real world, the ticket would actually be activated for a little more than 24 hours to account for clock drift between different ticket readers.

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
class DayTicket : public Ticket {
public:
  void Print(){
      char buf[128];
      cout << "Activation time: ";
      if (activationTime) {
          strftime(buf, sizeof(buf), "%c", localtime(&activationTime));
          cout << buf << '\n';
      } else {
          cout << "None\n";
      }
  }

  void Use() {
      time_t now = time(0);
      if (activationTime == 0) { // first time?
          activationTime = now;  // activate it
      }

      if (now > activationTime + 60*60*24) {
          cout << "24 hours has passed. This ticket is no longer valid.\n";
          cout << "RED\n";
      }
  }

protected:
    time_t activationTime = 0;
};

Modern C++ is really pretty friendly when it comes to manipulating time.

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
#include <chrono>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <string>


//-------------------------------------------------------------------------------------------------
// Helper overloads for printing time_points
// https://en.cppreference.com/w/cpp/io/manip/put_time
//
auto put_time( const std::string& format, const std::chrono::system_clock::time_point& tp )
{
  const time_t t = std::chrono::system_clock::to_time_t( tp );
  return std::put_time( std::localtime( &t ), format.c_str() );
}

auto put_time( const std::chrono::system_clock::time_point& tp, const std::string& format = "%c" )
{
  return put_time( format, tp );
}


//-------------------------------------------------------------------------------------------------
//   H O W   T O   A D D  /  M A N I U P L A T E   T I M E   I N   C + +
//-------------------------------------------------------------------------------------------------

int main()
{
  // The time_point literal operators are your friends here.
  // You do not actually need them, but you should use them anyway.
  // Choose:
  using namespace std::chrono_literals;  // all of them, or
  //using std::chrono::operator""h;      // just the one we need

  // Do the thing!
  auto today    = std::chrono::system_clock::now();
  auto tomorrow = today + 24h;  // <----------------------------------------THIS
  
  // All done
  std::cout << "Today    = " << put_time( today    ) << "\n";
  std::cout << "Tomorrow = " << put_time( tomorrow ) << "\n";
}

You will have to evaluate whether your assignment requires you to keep separate track of days, hours, minutes, seconds, etc, or if you can replace that all with a single time_point.

For future reference, if you really want to do it right, you should be using Howard Hinnant's date library, which will (hopefully) become part of <chrono> in C++2a. https://github.com/HowardHinnant/date

Hope this helps.
Modern C++ is really pretty friendly when it comes to manipulating time.
I have to disagree. Here's the same functionality using the 40-ish year old C time interface:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <ctime>
#include <iostream>

using std::cout;

int main()
{
    time_t today = time(0);
    auto tomorrow = today + 24*60*60;
    char buf[100];

    // All done
    strftime(buf, sizeof(buf), "%c", localtime(&today));
    std::cout << "Today    = " << buf << "\n";
    strftime(buf, sizeof(buf), "%c", localtime(&tomorrow));
    std::cout << "Tomorrow = " << buf << "\n";
}

Here's the same functionality...

And in contrast it compiles on http://cpp.sh/ and https://www.onlinegdb.com/online_c++_compiler
But -- I did not take the time to search for this detail -- does it also respect local settings of DST?
You disagree that modern C++ is friendly when manipulating time?

1
2
auto today = std::chrono::system_clock::now();
auto tomorrow = today + 24h;
isn’t as friendly as
1
2
time_t today = time(0);
auto tomorrow = today + 24*60*60;

? Because they look very alike to me.

See, simple examples mean nothing. It is when you get down into the details that C++ makes life a little nicer to look at. Click through the “date” links to get an idea of what the differences are, and maybe learn something useful.


RE: same functionality
Um, yes?

The stuff in <chrono> has the same functionality as the stuff in <ctime> a priori — <chrono> is an explicit wrapper for <ctime>.


RE: doesn’t compile on old stuff
So what? Get yourself a modern compiler.

If you are stuck with something old and you cannot update its libraries in any way, then you won’t care about cool modern abstractions anyway, and keep plugging along with the old stuff without the fancy abstractions.

The purpose of modern C++ is improved abstraction. With respect to date-time stuff, it means you can manipulate time_points with high abstractions instead of lots of code playing around with lots of lines of std::tm stuff.


RE: DST
Well, since <chrono> is a wrapper for <ctime>, and DST is a function of your system locale, the answer is the same for both: it depends. AFAIK, most systems properly handle DST with localtime().




Still not sure why suggesting using modern C++ was an issue.
Pages: 12