Hi... complete noob here to Arduino and C++... I am having a heck of a time just trying to access the current date in my loop(). Any help is appreciated.
I've pieced together the following code that connects to an NTP and adjusts for my timezone... this (borrowed) code seems to be working just fine. Now, I'd like to access a function in my loop() that returns a String in the format "YYYY-MM-DD" of the current moment in time and I can't seem to get it right.
When the date rolls from one day to the next e.g. 2025-03-17 to 2025-03-18, my strings never change to the next day, whatever the "DD" was on the first run is all I get. Nothing I've tried works, so I've just omitted that part of the code. I have no idea what I'm doing wrong for such a simple task.
Board is an ESP32-WROOM-32D.
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <cstring>
#include <TimeLib.h>
#include <ctime>
/*#include <DS1307RTC.h>*/
WiFiMulti WiFiMulti;
struct tm timeinfo;
void setTimezone(String timezone){
Serial.printf(" Setting Timezone to %s\n",timezone.c_str());
setenv("TZ",timezone.c_str(),1); // Now adjust the TZ. Clock settings are adjusted to show the new local time
tzset();
}
void initTime(String timezone){
Serial.println("Setting up time");
configTime(0, 0, "0.us.pool.ntp.org"); // First connect to NTP server, with 0 TZ offset
Serial.print(F("Waiting for NTP time sync: "));
time_t nowSecs = time(nullptr);
while (nowSecs < 8 * 3600 * 2) {
delay(500);
Serial.print(F("."));
yield();
nowSecs = time(nullptr);
}
Serial.println();
if(!getLocalTime(&timeinfo)){
Serial.println(" Failed to obtain time");
return;
}
Serial.println(" Got the time from NTP");
// Now we can set the real timezone
setTimezone(timezone);
}
void printLocalTime(){
if(!getLocalTime(&timeinfo)){
Serial.println("Failed to obtain time");
return;
}
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S zone %Z %z ");
}
void setup() {
Serial.begin(115200);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
WiFi.mode(WIFI_STA);
WiFiMulti.addAP("SSID", "PASS");
// wait for WiFi connection
Serial.print("Waiting for WiFi to connect...");
while ((WiFiMulti.run() != WL_CONNECTED)) {
Serial.print(".");
}
Serial.println(" connected");
//initTime("EST+5EDT,M3.2.0/2,M11.1.0/2"); // Set for EastCoast
initTime("CST+6CDT,M3.2.0/2,M11.1.0/2"); // Set for Central
printLocalTime();
}
void loop() {
String dateString; // ????
dateString = formatDateForAPI(); // ????
delay(1000*60*60*6); // check again in 6hrs
}
String formatDateForAPI(???) {
????
}
With the help of some AI, this is what I have now...I don't understand the function declaration. It seems to me it should be * if anything, not &. We'll see if this works as intended once the clock rolls tonight.
String formatDateForAPI2(const tm& currentTime) // note pass by reference here
{
/*
int tm_sec seconds [0,61]
int tm_min minutes [0,59]
int tm_hour hour [0,23]
int tm_mday day of month [1,31]
int tm_mon month of year [0,11]
int tm_year years since 1900
int tm_wday day of week [0,6] (Sunday = 0)
int tm_yday day of year [0,365]
int tm_isdst daylight savings flag
*/
String year_str;
String month_str;
String day_str;
year_str = String(currentTime.tm_year + 1900 );
if ( String(currentTime.tm_mon + 1).length() < 2 )
{
month_str = "0" + String(currentTime.tm_mon + 1);
}
else {
month_str = String(currentTime.tm_mon + 1);
}
if ( String(currentTime.tm_mday).length() < 2 )
{
day_str = "0" + String(currentTime.tm_mday);
}
else {
day_str = String(currentTime.tm_mday);
}
Serial.println("-----Final string in the function2:");
Serial.println(year_str + "-" + month_str + "-" + day_str );
Serial.println("--------End Func2---------------");
return (year_str + "-" + month_str + "-" + day_str);
}
void loop(){
String dateString;
dateString = formatDateForAPI2(timeinfo);
}
How do you test what you have? Wait until almost midnight EDT, and if that doesn't work, wait an hour for CDT; then try again the next day? Oh: your second post answered that
As a general note, when you're writing an .ino, you never need #include <Arduino.h> -- it is magically/silently added for you when compiling. It's only needed if you're writing your own "regular" .h or .cpp -- and you're referencing something Arduino-specific, like Serial or String
In C++, & means reference, as opposed to pass-by-value (i.e. making a copy). Behind the scenes, it is likely implemented with a pointer, but it is safer.
The AI-generated code is mediocre. If you already have a struct tm, try this
char date_ymd[] = "YYYY-MM-DD";
char time_hms[] = "HH:MM:SS";
void setup() {
Serial.begin(115200);
}
void loop() {
delay(1000);
// get the current time as both epoch seconds and date/time
time_t now;
time(&now);
tm datetime;
localtime_r(&now, &datetime);
// update date and time strings
strftime(date_ymd, sizeof(date_ymd), "%F", &datetime); // use specifiers
strftime(time_hms, sizeof(time_hms), "%T", &datetime); // added in C++11
// and print them
Serial.print(date_ymd);
Serial.print(' ');
Serial.println(time_hms);
// manually adjust the clock to be around midnight
if (datetime.tm_min == 0 && datetime.tm_sec >= 4) {
now += 86400 - 9;
timeval tv {.tv_sec = now, .tv_usec = 0};
settimeofday(&tv, nullptr); // no timezone
}
}
Your first post had code to set the timezone and get the actual date and time. Which is fine, but not necessary to see if the date rolls over at midnight. It is actually just slightly counterproductive. Once the time is set -- even when initialized to 1970, the start of the Unix epoch -- it will increment automatically.
Thanks for this @kenb4 . Before your example, I didn't realize that a struct tm doesn't actually keep track of the time... whoops... Which was the biggest flaw in my code first posted. The only occurrence of my tm being set was in setup() that's why the date never changed from the first run.
Using your example - time, localtime_r, and strftime have got me what I needed. It seems to be working as intended now.