Problem with scope and objects

In setup(), this works:

Timezone tz(dSt, sTd);

tz.toLocal(systime) correctly returns a time that is 60 minutes past systime.

This doesn't work, and no errors are generated. The method below, tz.toLocal(systime) = systime, which is wrong.

if (x == true) Timezone tz(dSt,sTd);

I included this along with other prototype functions in the initialization section because an error was generated when compiled and that resolved the error, but I'm not sure if it was the correct solution because it is instantiating an object, and it did not resolve the problem.

Also, the exact code below works when included in setup(), localTime is 60 minutes past sysTime, but called as a function as below, no errors are generated, but locTime = sysTime.

Thanks in advance for the help.

void sTime() {

  sysTime = now();
  if (preset[36] != 0) { // if DST hour is set, use DST function
    locTime = tz.toLocal(sysTime);
    setTime(locTime); // DST
     }  
}

Thanks in advance for the help.

Without seeing all of your code, that won't be possible.

The program is about 40k of code. Here’s the other code that relates to Timezone.

includes and prototypes in initialization section:

#include <Time.h>
#include <Timezone.h>
TimeChangeRule dSt = {"DST", 0, 0, 0, 0, 0};
TimeChangeRule sTd = {"STD", 0, 0, 0, 0, 0};
Timezone tz(dSt, sTd);
void sTime();

Setup():

TimeChangeRule dSt = {"DST", preset[37], preset[38], preset[36], preset[39], tzOffset};
TimeChangeRule sTd = {"STD", preset[43], preset[44], preset[42], preset[45], 0};
Timezone tz(dSt, sTd); // set rules

If necessary, I can put the code in a small program with only Time.h and Timezone.h included, to demonstrate the problem.

If necessary, I can put the code in a small program with only Time.h and Timezone.h included, to demonstrate the problem.

That would be very helpful.

This will demonstrate the problem:

//Try this way first - local and utc will be 14400 seconds apart, which is correct
//Then uncomment the two lines above Timezone() and comment Timezone myTZ(myDST, mySTD) - both numbers will be 
//equal, which is not correct.

//Next, back to the first way that worked, and comment utc = now(), and local = myTZ.toLocal(utc). Uncomment sTime(). 
//The same method but in a function, will not throw errors but it will not work.

#include <Time.h>
#include <Timezone.h>
time_t utc, local;

// prototypes
TimeChangeRule myDST = {"DST", 0, 0, 0, 0, 0};
TimeChangeRule mySTD = {"STD", 0, 0, 0, 0, 0};
Timezone myTZ(myDST, mySTD);

void setup() {

  Serial.begin(9600);
  
  setTime(12,0,0,24,7,2015); // set to 12:00PM, 7/24/15
  

  TimeChangeRule myDST = {"EDT", Second, Sun, Mar, 2, -240};    //Daylight time = UTC - 4 hours
  TimeChangeRule mySTD = {"EST", First, Sun, Nov, 2, -300};     //Standard time = UTC - 5 hours

//Try this both ways *****************************

//This does not work
//int x=2;
//if (x > 1) Timezone myTZ(myDST, mySTD);

//This does work
Timezone myTZ(myDST, mySTD);
//************************************************


//Then try this **********************************

//This does not work
// sTime();

// This does work
  utc = now();
  local = myTZ.toLocal(utc);
//************************************************

  Serial.println(utc);
  Serial.println(local);

}

void loop() {
  // put your main code here, to run repeatedly:

}


void sTime() {

  utc = now();
     local = myTZ.toLocal(utc);
   
}

The problem is that what you think is a prototype is actually a constructor for a time zone object. Get rid of the “prototype”, since that actually instantiates the object. Take a look at this code and I think you’ll see the problem.

//Try this way first - local and utc will be 14400 seconds apart, which is correct
//Then uncomment the two lines above Timezone() and comment Timezone myTZ(myDST, mySTD) - both numbers will be
//equal, which is not correct.

//Next, back to the first way that worked, and comment utc = now(), and local = myTZ.toLocal(utc). Uncomment sTime().
//The same method but in a function, will not throw errors but it will not work.

#include <Time.h>
#include <Timezone.h>
time_t utc, local;

// prototypes
TimeChangeRule myDST = {"DST", 0, 0, 0, 0, 0};
TimeChangeRule mySTD = {"STD", 0, 0, 0, 0, 0};
//Timezone myTZ(myDST, mySTD);

void setup() {

  Serial.begin(9600);

  setTime(12, 0, 0, 24, 7, 2015); // set to 12:00PM, 7/24/15


  TimeChangeRule myDST = {"EDT", Second, Sun, Mar, 2, -240};    //Daylight time = UTC - 4 hours
  TimeChangeRule mySTD = {"EST", First, Sun, Nov, 2, -300};     //Standard time = UTC - 5 hours

  //Try this both ways *****************************

  //This does not work
  int x = 0;

  Timezone myTZ(myDST, mySTD);    // This instantiates the object

  if (x > 1) {                         // You can change x above to test the other branch
    sTime(myTZ);
  } else {
    utc = now();
    local = myTZ.toLocal(utc);
  }

  Serial.println(utc);
  Serial.println(local);

}

void loop() {
  // put your main code here, to run repeatedly:

}


void sTime(Timezone myTZ) {

  utc = now();
  local = myTZ.toLocal(utc);

}

Yes, I see. Thank you very much! Obviously I have lots to learn about objects.

One more question -

When Serial.println(myTZ.locIsDST(utc)); or any reference to myTZ is put in loop(), a compiler error, "'myTZ' was not defined in this scope", was generated. How can it be made global, without the prototype function?

//This does not work
//int x=2;
//if (x > 1) Timezone myTZ(myDST, mySTD);

If you used curly braces, you'd see the problem:
//This does not work

int x=2;
if (x > 1)
{
   Timezone myTZ(myDST, mySTD);
}

That particular myTZ object goes out of scope when the } is encountered, which is immediately.

Thank you. That makes sense.

Regarding post #7, I thought about instantiating another object in loop(), but that seems more like a kluge. If there is no good way of doing this, I'll move the code to a function within the program.

Take a look at post #16 at:

for a little discussion of scope.

I see. So to make the Timezone object properties and methods available everywhere, which is what I need, it would have to be instantiated before setup() where it will be global. Then I would have to add a method function to allow updating the dst and std data to the already instantiated, global object. Once that is done, it should work. Is that correct?

I believe I found a good solution - I added the function, 'updateRules' to the library. That way the object can be created globally in the initialization section, so library functions are available everywhere.

Initialize:
TimeChangeRule myDST = {"DST", 0, 0, 0, 0, 0};
TimeChangeRule mySTD = {"STD", 0, 0, 0, 0, 0};
Timezone1 myTZ(myDST, mySTD);

This goes anywhere rules need to be updated:
TimeChangeRule myDST = {"EDT", 2, 1, 3,2, -240}; //Daylight time = UTC - 4 hours
TimeChangeRule mySTD = {"EST", 1, 1, 11,2, -300}; //Standard time = UTC - 5 hours
myTZ.updateRules(myDST,mySTD);

If there is a better way to do this, let me know. Thanks again for the help.

If there is a better way to do this, let me know.

Let's first consider whether, while the Arduino is running, the conversion rules will change. How often is that likely to happen?

There is a better way. The TimeChangeRule class should have a no-argument constructor. It should also have a begin() method. You would instantiate two (empty) rules, and then call the begin() methods to give them values.

Instead of updateRules(), you'd just call begin() again, for the rule instance(s). if the rule(s) changes.

Right now, it appears that the Timezone1 class copies data from the TimeChangeRule instances, instead of storing the TimeChangeRule instances. The data should be obtained from the TimeChangeRule instances, when the Timezone1 instance's methods are called.

That way, you could change the TimeChangeRule instance, and the Timezone1 instance would KNOW.

Thanks for the help!

The rules will probably never change, unfortunately, but they are accessible in menus so I do want to keep the ability to change them if necessary.

TimeChangeRule is just a struct. It is not defined as a class and it doesn't appear in Timezone.cpp. It appears to only store values set to myDST and mySTD.

So if this will work to initialize myDST and mSTD, so they can be set later:
TimeChangeRule myDST = {};
TimeChangeRule mySTD = {};

And this anywhere:
TimeChangeRule myDST = {"EDT", 2, 1, 3,2, -240}; //Daylight time = UTC - 4 hours
TimeChangeRule mySTD = {"EST", 1, 1, 11,2, -300}; //Standard time = UTC - 5 hours
myTZ.updateRules(myDST,mySTD);

Is that accomplishing what you describe, but in a less elegant way? I'm at the limit of what I understand about objects, now. I will check other libraries that have a begin() method, to see how it's done.

So if this will work to initialize myDST and mSTD, so they can be set later:
TimeChangeRule myDST = {};
TimeChangeRule mySTD = {};

Why? You can declare an instance of a struct without providing initializers.

TimeChangeRule myDST;
TimeChangeRule mySTD
TimeChangeRule myDST = {"EDT", 2, 1, 3,2,  -240};    //Daylight time = UTC - 4 hours
TimeChangeRule mySTD = {"EST", 1, 1, 11,2,   -300};     //Standard time = UTC - 5 hours
myTZ.updateRules(myDST,mySTD);

That works, but the convention is to call the mandatory function begin(). Your mandatory function, before the class is usable is called updateRules() which implies, to me at least, that it is an optional function, to be used when the rules change (not are set).

I made the changes and it works perfectly. Thanks for the help.