Timezone library with unixtime to set DS3231 time

I have working code that set DS3231 using GPS time with unixtime. Looking to use Timezone library and do not know how to go about accomplishing the task. Do I have to use Time.h and Timelib.h? Do I need to change RTClib.h (Adafruit) library Will I still be able to use unixtime?

These are the two functions that are the time keeping functions:

void getDate_Time()
{
     DateTime now = rtc.now();

     YEAR = now.year();
     MONTH = now.month();
     DATE = now.day();
     DOW = now.dayOfTheWeek();
     HOUR = now.hour();
     MINUTE = now.minute();
     SECOND = now.second();

     sprintf (message, "%4d/%02d/%02d %02d:%02d:%02d EDT", YEAR, MONTH, DATE, HOUR, MINUTE, SECOND);
     dtStamp = message;

}

void RTC_UPDATE()
{

     struct tm  timeinfo;
     unsigned long int unixtime;

     if((!gps.date.isValid()) || (!gps.time.isValid()))
     {
          getDate_Time();
          Serial.println(dtStamp);
          return;
     }

     Serial.print(F("GPS: "));
     if (gps.date.isValid())
     {

          timeinfo.tm_year =  gps.date.year() - 1900;
          timeinfo.tm_mon = gps.date.month() - 1;
          timeinfo.tm_mday =  gps.date.day();
     }
     else
     {
          Serial.print(F("Date INVALID"));
          exit;
     }

     Serial.print(F(" "));
     if (gps.time.isValid())
     {

          timeinfo.tm_hour =  gps.time.hour();
          timeinfo.tm_min =  gps.time.minute();
          timeinfo.tm_sec = gps.time.second();

          unixtime = mktime(&timeinfo);
          Serial.println("");
          printf("unixtime = %u\n", unixtime);

          rtc.adjust(DateTime(unixtime - SECONDS_OFFSET));  //Correction for local time.

          Serial.println("RTC updated");
          Serial.println("");

     }
     else
     {
          Serial.print(F(" Time INVALID"));
          exit;
     }

     Serial.println();

}

I am using the RTClib library from "Adafruit" with an ESP32 and the "Arduino IDE."

William

     YEAR = now.year();
     MONTH = now.month();
     DATE = now.day();
     DOW = now.dayOfTheWeek();
     HOUR = now.hour();
     MINUTE = now.minute();
     SECOND = now.second();

By convention, all capital letter names are reserved for constants. Constants do NOT appear on the left of an equal sign after they are declared and initialized.

Looking to use Timezone library and do not know how to go about accomplishing the task.

What IS the task? You are getting date and time information from the GPS, in UTC time. You can use the timezone library to convert that date/time to local time, and use the local time to set the RTC.

If you mean this timezone library GitHub - JChristensen/Timezone: Arduino library to facilitate time zone conversions and automatic daylight saving (summer) time adjustments. then it automatically makes the Arduino time library (TimeLib.h) available in your sketch. It includes usage examples.

You can get "unix time" from the Adafruit rtclib like this example. Of course, it makes some assumptions that the RTC has been properly set before hand.

DateTime now = rtc.now();  
Serial.print( now.unixtime() ) ;  // uint32_t

The time_t data type which you will see is a lot of is a uint32_t number representing unix time

Thank you 6v6gt appreciate your response and advise; yes that is the library.

What would the command be to set the DS3231 by passing parameter "unixtime." I was able to do this with the RTClib library. Is it possible to do this with "Time.h" or "Timelib.h" eliminating the RTClib?

Thank you PaulS for your comments.

William

Is it possible to do this with "Time.h" or "Timelib.h" eliminating the RTClib?

No. The TimeLib and Time libraries know nothing about RTCs.

If you have a physical DS3231 then you really need to use the matching RTC library. The alternative is to use the basic wire/I2C commands to poke/read the correct values into/from the RTC registers.

The time library (TimeLib.h) has setTime() and now() for handling unix time, that is a uint32_t representation of seconds since 1.1.1970.

Thank you 6v6gt; I now have timezone feature of the project working!

ESP32 "Weather_View" project web site.

void getDate_Time()
{
  
  time_t utc = now();
  time_t local = myTZ.toLocal(utc, &tcr);
  time_t t = now(); // store the current time in time variable t
  HOUR = hour(t);          // returns the hour for the given time t
  MINUTE = minute(t);        // returns the minute for the given time t
  SECOND = second(t);        // returns the second for the given time t
  DATE = day(t);           // the day for the given time t
  DOW = weekday(t);       // day of the week for the given time t
  MONTH = month(t);         // the month for the given time t
  YEAR = year(t);          // the year for the given time t

  printDateTime(local, tcr -> abbrev);
  
}

// format and print a time_t value, with a time zone appended.
void printDateTime(time_t t, const char *tz)
{
    char buf[32];
    char m[4];    // temporary storage for month string (DateStrings.cpp uses shared buffer)
    strcpy(m, monthShortStr(month(t)));
    sprintf(buf, "%.2d:%.2d:%.2d %s %.2d %s %d %s",
        hour(t), minute(t), second(t), dayShortStr(weekday(t)), day(t), m, year(t), tz);
    dtStamp = buf;
}

void RTC_UPDATE()
{

     struct tm  timeinfo;
     unsigned long int unixtime;

     if((!gps.date.isValid()) || (!gps.time.isValid()))
     {
          getDate_Time();
          Serial.println(dtStamp);
          return;
     }

     Serial.print(F("GPS: "));
     if (gps.date.isValid())
     {

          timeinfo.tm_year =  gps.date.year() - 1900;
          timeinfo.tm_mon = gps.date.month() - 1;
          timeinfo.tm_mday =  gps.date.day();
     }
     else
     {
          Serial.print(F("Date INVALID"));
          exit;
     }

     Serial.print(F(" "));
     if (gps.time.isValid())
     {

          timeinfo.tm_hour =  gps.time.hour();
          timeinfo.tm_min =  gps.time.minute();
          timeinfo.tm_sec = gps.time.second();

          unixtime = mktime(&timeinfo);
          Serial.println("");
          printf("unixtime = %u\n", unixtime);

          setTime(unixtime);   // the function to get the time from the RTC
          if(timeStatus()!= timeSet)
             Serial.println("Unable to sync with the RTC");
          else
             Serial.println("RTC has set the system time");;
      
             Serial.println("RTC updated");
             Serial.println("");

     }
     else
     {
          Serial.print(F(" Time INVALID"));
          exit;
     }

     Serial.println();

Attached project Serial Monitor output; which shows two GPS time (unixtime) updates with interval set to 15 minutes. Interval is easily set; can be seconds, minutes, or hours.

Appreciate the help!

William

Serial Monitor.txt (10.5 KB)

Event that is coded to happen at 23:58:00 local time is being called at local time 20:58:00 EDT. Believe this is due to 20:00:00 EDT is 24:00:00 in UTC.

What is needed to get the fileStore event to occur at 23:58:00 EDT?

When I use print statement for HOUR is fine unit HOUR = 20; then it goes to HOUR = 0 and the 23:58:0 is called. I believe the DS3231 is using unixtime. I am using JChristensen's Timezone library with he DS3232 library. fileStore only appears in two places; once in loop and and once in void fileStore().

void loop()
{

     ...

     if((HOUR == 23) && (MINUTE == 58) && (SECOND == 0))  //localOffset needed since RTC uses UTC Time.
     {
          fileStore();

          Serial.println("fileStore called");

          Serial.println(dtStamp);
     }

     ...

}

/*  Time keeping functions */


void getDate_Time()
{
  
  time_t utc = now();
  time_t local = myTZ.toLocal(utc, &tcr);
  time_t t = now(); // store the current time in time variable t
  HOUR = hour(t);          // returns the hour for the given time t
  MINUTE = minute(t);        // returns the minute for the given time t
  SECOND = second(t);        // returns the second for the given time t
  DATE = day(t);           // the day for the given time t
  DOW = weekday(t);       // day of the week for the given time t
  MONTH = month(t);         // the month for the given time t
  YEAR = year(t);          // the year for the given time t

  printDateTime(local, tcr -> abbrev);
  
}

// format and print a time_t value, with a time zone appended.
void printDateTime(time_t t, const char *tz)
{
    char buf[32];
    char m[4];    // temporary storage for month string (DateStrings.cpp uses shared buffer)
    strcpy(m, monthShortStr(month(t)));
    sprintf(buf, "%.2d:%.2d:%.2d %s %.2d %s %d %s",
        hour(t), minute(t), second(t), dayShortStr(weekday(t)), day(t), m, year(t), tz);
    dtStamp = buf;
}

void RTC_UPDATE()
{

     struct tm  timeinfo;
     unsigned long int unixtime;

     if((!gps.date.isValid()) || (!gps.time.isValid()))
     {
          getDate_Time();
          Serial.println(dtStamp);
          return;
     }

     Serial.print(F("GPS: "));
     if (gps.date.isValid())
     {

          timeinfo.tm_year =  gps.date.year() - 1900;
          timeinfo.tm_mon = gps.date.month() - 1;
          timeinfo.tm_mday =  gps.date.day();
     }
     else
     {
          Serial.print(F("Date INVALID"));
          exit;
     }

     Serial.print(F(" "));
     if (gps.time.isValid())
     {

          timeinfo.tm_hour =  gps.time.hour();
          timeinfo.tm_min =  gps.time.minute();
          timeinfo.tm_sec = gps.time.second();

          unixtime = mktime(&timeinfo);
          Serial.println("");
          printf("unixtime = %u\n", unixtime);

          setTime(unixtime);   // the function to get the time from the RTC
          if(timeStatus()!= timeSet)
             Serial.println("Unable to sync with the RTC");
          else
             Serial.println("RTC has set the system time");;
      
             Serial.println("RTC updated");
             Serial.println("");

     }
     else
     {
          Serial.print(F(" Time INVALID"));
          exit;
     }

     Serial.println();

}

/*  fileStore function  */

void fileStore()   //If 6th day of week, rename "log.txt" to ("log" + month + day + ".txt") and create new, empty "log.txt"
{


     String logname;
     logname = "/LOG";
     logname += DATE; ////logname += Clock.getMonth(Century);
     logname += MONTH;   ///logname += Clock.getDate();
     logname += YEAR;
     logname += ".TXT";
     // Open file for appended writing
     File log = SPIFFS.open(logname.c_str(), "a");


     if (!log)
     {
          Serial.println("file open failed");
     }
    
}

Prefer to use DS3231 for the HOUR value; since there could be invalid GPS.time causing a logging failure.

William

Here you are hard coding times in your local timezone:

if((HOUR == 23) && (MINUTE == 58) && (SECOND == 0)) //localOffset needed since RTC uses UTC Time.

I'm not sure this is doing what you expect:

  time_t utc = now();
  time_t local = myTZ.toLocal(utc, &tcr);
  time_t t = now(); // store the current time in time variable t
  HOUR = hour(t);          // returns the hour for the given time t

now() is the Arduino "System Time" and has to have been set previously with setTime( time_t myUnixTime )
if you want HOUR to be in local time, you have to say HOUR = hour( local )

You have to post your entire sketch if you need more help.

Project is 2000 lines of code; attached to this post. second attachment is a README.TXT that is features of the project.

"Weather_View_Timezone," ESP32 server

William

Weather_View_Timezone.zip (18.7 KB)

README.TXT (5.82 KB)

It is a big sketch, but I think I see what you are doing.

You appear to want to use GPS time to set the RTC periodically in unix time UTC. However, it is not clear to me if that is what you are actually doing.
This code from void RTC_UPDATE() has misleading comments in it and the indentation in the if/then/else statement does not match the block structure:

          setTime(unixtime);   // the function to get the time from the RTC
             // setTime(unixtime)  does not set the RTC, it sets the Arduino "System Time"
          if(timeStatus()!= timeSet)
             Serial.println("Unable to sync with the RTC");
          else
             Serial.println("RTC has set the system time");;
      
             Serial.println("RTC updated");
             Serial.println("");

You use the RTC to set Arduino "System Time" ) and that is also in unix time UTC. So, for example, now() returns UTC.

setSyncProvider(RTC.get);

Which, by default, runs every 5 minutes

So, it is as I said before. If you want this to work in local time, ie 23:58 EDT
if((HOUR == 23) && (MINUTE == 58) && (SECOND == 0)) //localOffset needed since RTC uses UTC Time.
you have to change this:

void getDate_Time()
{
  time_t utc = now();
  time_t local = myTZ.toLocal(utc, &tcr);
  //Serial.println();
  //printDateTime(utc, "UTC");
  
  // time_t t = now(); // store the current time in time variable t -  now() returns UTC in this case !!

  HOUR = hour(local);          // returns the hour for the given time  
  MINUTE = minute(local);        // returns the minute for the given time  
  SECOND = second(local);        // returns the second for the given time  
  DATE = day(local);           // the day for the given time  
  DOW = weekday(local);       // day of the week for the given time  
  MONTH = month(local);         // the month for the given time  
  YEAR = year(local);          // the year for the given time  

  printDateTime(local, tcr -> abbrev);
}

Incidentally, you could break your code down to into smaller .h and .cpp units (separate tabs in the Arduino IDE).

1 Like

Thank you 6v6gt; you are excellent at presenting what needs to be done; much appreciated. I am still learning and developing style. Yes, I am familiar with"tabbed compiling;" I find in the initial stages of a project, it is easier for me to search the entire project. My editor of choice is "Notepad++;" I find this search tool is easier to use than the "Arduino IDE" search tool.

Once I have finished coding project I will use "ASytle" to present a well formatted source code. My apologies for the confusing comments. Thanks for your input.

I have no experience writing .cpp or .h library files; perhaps sometime in the future. This project had its beginnings in the Fall of 2012 when I was given an "Arduino Uno;" project has evolved to the present project code I am completely self-learned in "Arduino C++" programming and continue learning at 70 years old!

Best Regards,
William

1 Like