An Array of Time Zones

I've got several, general problems I'm trying to solve before I try to start tackling the details. I was hoping for some suggestions before I commit to a bad solution, early.

I am using jchristensen's TimeZone library.

The user will need to be able to select their local time zone from a list that will scroll on a 16x2 LCD using up down keys.

My first attempt was to create an array of timezones, but that wouldn't compile.

#include <Timezone.h>    //https://github.com/JChristensen/Timezone

//Australia Eastern Time Zone (Sydney, Melbourne)
TimeChangeRule aEDT = {"AEDT", First, Sun, Oct, 2, 660};    //UTC + 11 hours
TimeChangeRule aEST = {"AEST", First, Sun, Apr, 3, 600};    //UTC + 10 hours
Timezone ausQLD(aEST, aEST);
Timezone ausNSW(aEDT, aEST);

//Australia Central Time Zone (Darwin)
TimeChangeRule aCDT = {"ACDT", First, Sun, Oct, 2, 630};    //UTC + 10.5 hours
TimeChangeRule aCST = {"ACST", First, Sun, Apr, 3, 570};    //UTC +  9.5 hours
Timezone ausNT(aCST, aCST);
Timezone ausSA(aCDT, aCST);

//Australia Western Time Zone (Perth)
TimeChangeRule aWST = {"AWST", First, Sun, Apr, 3, 480};    //UTC + 8 hours
Timezone ausWA(aWST, aWST);

#define NUMBER_OF_TIME_ZONES 5
Timezone timeZones_arr[NUMBER_OF_TIME_ZONES] = {
  ausQLD(aEST, aEST),
  ausNSW(aEDT, aEST),
  ausNT(aCST, aCST),
  ausSA(aCDT, aCST),
  ausWA(aWST, aWST)
}

My second approach is to define an array of strings that will hold user friendly names of the timezones. The index of the array will be somehow tied to the list of timezones. But, now that I think of it, would a does it make more sense to create a typedef with a string and timezone? My problem is being able to know what timezone is selected by the user and reference that in code later.

Can anyone give me an idea a good way to do this within the scope of the timezone library?

Thanks,

John

... off to experiment with the typedef option.

Did you try this method of creating the array, as an array of pointers to time zones?:-

#include <Timezone.h>    //https://github.com/JChristensen/Timezone

//Australia Eastern Time Zone (Sydney, Melbourne)
TimeChangeRule aEDT = {"AEDT", First, Sun, Oct, 2, 660};    //UTC + 11 hours
TimeChangeRule aEST = {"AEST", First, Sun, Apr, 3, 600};    //UTC + 10 hours
Timezone ausQLD(aEST, aEST);
Timezone ausNSW(aEDT, aEST);

//Australia Central Time Zone (Darwin)
TimeChangeRule aCDT = {"ACDT", First, Sun, Oct, 2, 630};    //UTC + 10.5 hours
TimeChangeRule aCST = {"ACST", First, Sun, Apr, 3, 570};    //UTC +  9.5 hours
Timezone ausNT(aCST, aCST);
Timezone ausSA(aCDT, aCST);

//Australia Western Time Zone (Perth)
TimeChangeRule aWST = {"AWST", First, Sun, Apr, 3, 480};    //UTC + 8 hours
Timezone ausWA(aWST, aWST);

#define NUMBER_OF_TIME_ZONES 5
Timezone* timeZones_arr[NUMBER_OF_TIME_ZONES] =
{
    &ausQLD,
    &ausNSW,
    &ausNT,
    &ausSA,
    &ausWA
};

OldSteve:
Did you try this method of creating the array, as an array of pointers to time zones?:-

No, that wouldn't have ever occurred to me. I will give that a shot.

Is there a way to get the timezone names to populate a list? The ausNT, ausSA, etc. Or will I still need to make another array of strings and have the indexes of the two arrays (timezones and strings) matched?

Thanks for the help and ideas.

jecottrell:
No, that wouldn't have ever occurred to me. I will give that a shot.

Is there a way to get the timezone names to populate a list? The ausNT, ausSA, etc. Or will I still need to make another array of strings and have the indexes of the two arrays (timezones and strings) matched?

Thanks for the help and ideas.

If you want to use the names for another purpose, you'd need to make a separate list.
For example:-

char zoneList[NUMBER_OF_TIME_ZONES][7] =
{
    "ausQLD",
    "ausNSW",
    "ausNT",
    "ausSA",
    "ausWA"
};

And by the way, to access an element of the array of pointers to time zones, you'd do this:-
(This will set the time of one TimeZone in 'setup()')setTime(timeZones_arr[0]->toUTC(compileTime()));
N.B. The 'compileTime()' function is in the "WorldClock" example that came with the "TimeZone" library.

This compiles fine for me:-

#include <Timezone.h>    //https://github.com/JChristensen/Timezone

//Australia Eastern Time Zone (Sydney, Melbourne)
TimeChangeRule aEDT = {"AEDT", First, Sun, Oct, 2, 660};    //UTC + 11 hours
TimeChangeRule aEST = {"AEST", First, Sun, Apr, 3, 600};    //UTC + 10 hours
Timezone ausQLD(aEST, aEST);
Timezone ausNSW(aEDT, aEST);

//Australia Central Time Zone (Darwin)
TimeChangeRule aCDT = {"ACDT", First, Sun, Oct, 2, 630};    //UTC + 10.5 hours
TimeChangeRule aCST = {"ACST", First, Sun, Apr, 3, 570};    //UTC +  9.5 hours
Timezone ausNT(aCST, aCST);
Timezone ausSA(aCDT, aCST);

//Australia Western Time Zone (Perth)
TimeChangeRule aWST = {"AWST", First, Sun, Apr, 3, 480};    //UTC + 8 hours
Timezone ausWA(aWST, aWST);

#define NUMBER_OF_TIME_ZONES 5
Timezone* timeZones_arr[NUMBER_OF_TIME_ZONES] =
{
    &ausQLD,
    &ausNSW,
    &ausNT,
    &ausSA,
    &ausWA
};

char zoneList[NUMBER_OF_TIME_ZONES][7] =
{
    "ausQLD",
    "ausNSW",
    "ausNT",
    "ausSA",
    "ausWA"
};

void setup()
{
    Serial.begin(115200);
    setTime(timeZones_arr[0]->toUTC(compileTime()));
    Serial.println(zoneList[0]);
}

void loop()
{

}

//Function to return the compile date and time as a time_t value
time_t compileTime(void)
{
#define FUDGE 25        //fudge factor to allow for compile time (seconds, YMMV)

    char *compDate = __DATE__, *compTime = __TIME__, *months = "JanFebMarAprMayJunJulAugSepOctNovDec";
    char chMon[3], *m;
    int d, y;
    tmElements_t tm;
    time_t t;

    strncpy(chMon, compDate, 3);
    chMon[3] = '\0';
    m = strstr(months, chMon);
    tm.Month = ((m - months) / 3 + 1);

    tm.Day = atoi(compDate + 4);
    tm.Year = atoi(compDate + 7) - 1970;
    tm.Hour = atoi(compTime);
    tm.Minute = atoi(compTime + 3);
    tm.Second = atoi(compTime + 6);
    t = makeTime(tm);
    return t + FUDGE;        //add fudge factor to allow for compile time
}

And if I upload and run it, it prints "ausQLD" to the serial monitor.

Fantastic! Thanks for the spoon feeding, it is much appreciated.

What would I Google to read about why this:

setTime(timeZones_arr[0]->toUTC(compileTime()));

And not this:

setTime(timeZones_arr[0].toUTC(compileTime()));

Try "C++ pointer dereference operator".
Maybe that's not such a good search term.
This might help:- Class member access operator (->) overloading in C++

And here's a better example. It prints "00:42:28 Sun 04 Sep 2016 ausNSW"
(My time zone - must be bedtime. :slight_smile: )

#include <Timezone.h>    //https://github.com/JChristensen/Timezone

//Australia Eastern Time Zone (Sydney, Melbourne)
TimeChangeRule aEDT = {"AEDT", First, Sun, Oct, 2, 660};    //UTC + 11 hours
TimeChangeRule aEST = {"AEST", First, Sun, Apr, 3, 600};    //UTC + 10 hours
Timezone ausQLD(aEST, aEST);
Timezone ausNSW(aEDT, aEST);

//Australia Central Time Zone (Darwin)
TimeChangeRule aCDT = {"ACDT", First, Sun, Oct, 2, 630};    //UTC + 10.5 hours
TimeChangeRule aCST = {"ACST", First, Sun, Apr, 3, 570};    //UTC +  9.5 hours
Timezone ausNT(aCST, aCST);
Timezone ausSA(aCDT, aCST);

//Australia Western Time Zone (Perth)
TimeChangeRule aWST = {"AWST", First, Sun, Apr, 3, 480};    //UTC + 8 hours
Timezone ausWA(aWST, aWST);

#define NUMBER_OF_TIME_ZONES 5
Timezone* timeZones_arr[NUMBER_OF_TIME_ZONES] =
{
    &ausQLD,
    &ausNSW,
    &ausNT,
    &ausSA,
    &ausWA
};

char zoneList[NUMBER_OF_TIME_ZONES][7] =
{
    "ausQLD",
    "ausNSW",
    "ausNT",
    "ausSA",
    "ausWA"
};

TimeChangeRule *tcr;        //pointer to the time change rule, use to get the TZ abbrev
time_t utc;

void setup()
{
    Serial.begin(115200);
    
    byte zoneIndex = 1;
    utc = now();
    
    setTime(timeZones_arr[zoneIndex]->toUTC(compileTime()));
    printTime(timeZones_arr[zoneIndex]->toLocal(utc, &tcr), tcr -> abbrev, zoneList[zoneIndex]);
}

void loop()
{

}

//Function to return the compile date and time as a time_t value
time_t compileTime(void)
{
#define FUDGE 25        //fudge factor to allow for compile time (seconds, YMMV)

    char *compDate = __DATE__, *compTime = __TIME__, *months = "JanFebMarAprMayJunJulAugSepOctNovDec";
    char chMon[3], *m;
    int d, y;
    tmElements_t tm;
    time_t t;

    strncpy(chMon, compDate, 3);
    chMon[3] = '\0';
    m = strstr(months, chMon);
    tm.Month = ((m - months) / 3 + 1);

    tm.Day = atoi(compDate + 4);
    tm.Year = atoi(compDate + 7) - 1970;
    tm.Hour = atoi(compTime);
    tm.Minute = atoi(compTime + 3);
    tm.Second = atoi(compTime + 6);
    t = makeTime(tm);
    return t + FUDGE;        //add fudge factor to allow for compile time
}

//Function to print time with time zone
void printTime(time_t t, char *tz, char *loc)
{
    sPrintI00(hour(t));
    sPrintDigits(minute(t));
    sPrintDigits(second(t));
    Serial.print(' ');
    Serial.print(dayShortStr(weekday(t)));
    Serial.print(' ');
    sPrintI00(day(t));
    Serial.print(' ');
    Serial.print(monthShortStr(month(t)));
    Serial.print(' ');
    Serial.print(year(t));
    Serial.print(' ');
    Serial.print(tz);
    Serial.print(' ');
    Serial.print(loc);
    Serial.println();
}

//Print an integer in "00" format (with leading zero).
//Input value assumed to be between 0 and 99.
void sPrintI00(int val)
{
    if (val < 10) Serial.print('0');
    Serial.print(val, DEC);
    return;
}

//Print an integer in ":00" format (with leading zero).
//Input value assumed to be between 0 and 99.
void sPrintDigits(int val)
{
    Serial.print(':');
    if(val < 10) Serial.print('0');
    Serial.print(val, DEC);
}

Ahhhhh.

You made an array of pointers to the time zone variables. So, the call would need to dereference it for the method.

Thanks.

jecottrell:
Ahhhhh.

You made an array of pointers to the time zone variables. So, the call would need to dereference it for the method.

Thanks.

Yep. For dereferencing pointers for class member functions.

Having a lot of trouble with forum timeouts right now. Off to bed for me......