Problème de formatage de date

Bonjour à toutes et à tous,

Dans une application autour d'un ESP32, j'utilise la librairie time.h pour en extraire la date et l'heure.

Dans un exemple, il y a les instructions suivantes :

  struct tm timeinfo;
  getLocalTime(&timeinfo);
  Serial.println(&timeinfo, "%d/%m/%Y %H:%M:%S");

Ce qui me donne : 21/12/2024 20:18:16 --> correct

J'essaie un autre formatage pour obtenir une chaîne :

Serial.printf("%02u/%02u/%04u %02u:%02u:%02u", timeinfo.tm_mday, timeinfo.tm_mon, &timeinfo.tm_year, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);

et là, j'obtiens : 21/11/124 20:18:16 --> mois et année incorrects.

sachant que dans la structure timeinfo, ses composantes sont des entiers :

struct tm
{
  int	tm_sec;
  int	tm_min;
  int	tm_hour;
  int	tm_mday;
  int	tm_mon;
  int	tm_year;
  int	tm_wday;
  int	tm_yday;
  int	tm_isdst;
#ifdef __TM_GMTOFF
  long	__TM_GMTOFF;
#endif
#ifdef __TM_ZONE
  const char *__TM_ZONE;
#endif
};

et que si je les affiche un par un, j'obtiens 11 pour le mois et 124 pour l'année.

J'en conclus donc Serial.println() possède des formateurs spécifiques pour cette strructure car, si j'emploie ces formateurs dans un sprintf ou printf, j'obtiens les mauvaises valeurs.

Comment récupérer une chaîne représentant la date et l'heure avec le bon format ? Y a-t-il une instruction qui permette d'obtenir le formatage donné par println() ?

Cordialement.

Pierre.

Oui print() est surchargée pour différents types de données dont la struct tm sur ESP32

Ça utilise strftime()

Pourquoi avoir effacer ce post ?

Je me doutais bien qu'il y avait cette histoire de 1900. Mais ce qui ne m'a pas paru cohérent est que le mois commence à zéro mais pas le jour.

Cordialement.

Pierre.

Merci J-M-L pour cette info.

Effectivement, je pourrais utiliser strftime, mais en fait, je voudrais ne faire qu'une seule écriture dans une carte SD qui inclut la date/heure et d'autres informations que j'ai sous forme de flottant. Ce que je fais donc de cette manière (ajout de 1 au mois et de 1900 à l'année) :

struct tm timeinfo;
char message[48];
...
getLocalTime(&timeinfo);
sprintf(message, "%02u/%02u/%04u %02u:%02u:%02u %.1f %.1f, %.1f\n", timeinfo.tm_mday, 1+timeinfo.tm_mon, 1900+timeinfo.tm_year, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec,
                 pActif, vRMS, iRMS);

Mais peut-être y a-t-il plus sioux !

NOTA : le 1900 me pose aussi question car le départ du temps UNIX est 1970 et le Temps Universel ne possède pas de date départ.

Cordialement.

Pierre.

vous pouvez effectivement faire comme cela ou vous pourriez créer un petit buffer local pour appeler strftime() comme ils le font dans la fonction surchargée et injecter cette chaîne temporaire ensuite avec un %s dans votre sprintf()


Mais pour ce qui est de

En pratique construire le buffer avant de l'écrire dans la carte SD ne sert à rien. Le plus efficace niveau mémoire reste d'écrire sur la carte SD directement chaque champ séparément puisque de toutes façons vous écrivez dans un buffer déjà et que c'est la bibliothèque SD qui se charge de vider ce buffer de temps en temps dans la carte SD.

Merci J-M-L pour ces suggestions.

Pour autant, dans mon cas, ce qui m'intéresse n'est pas tellement un problème de mémoire, mais un problème de temps. Faire un écriture pour chaque variable accroit légèrement le temps d'inscription dans la carte SD. Toutefois, c'est l'ouverture et la fermeture qui prennent le plus de temps. Je pense que je vais en rester à la situation suivante :

char message1[24]; // Chaîne de caractères transmise à la carte SD pour l'écriture de la date-heure
char message2[24]; // Chaîne de caractères transmise à la carte SD pour l'écriture des données
...
  getLocalTime(&timeinfo);
  strftime( message1, 24, "%d/%m/%Y %H:%M:%S,", &timeinfo);
  sprintf(message2, "%.1f,%.1f,%.1f\n", pActif, vRMS, iRMS);
  appendFile2(SD, "/Valeurs.txt", message1, message2);

avec :

uint8_t appendFile2(fs::FS &fs, const char * path, const char * message1, const char * message2){
  File file = fs.open(path, FILE_APPEND);
  if(!file){
    return 1;
  } else {
    file.print(message1);
    file.print(message2);
    file.close();
    return 0;
  }
}

Cordialement.

Pierre.

Je demande à voir : entre la création d'un buffer que l'on remplit avec sprintf() qui est une fonction couteuse (analyse du format) et un seul print, versus une série de print() ciblés (puisque le type est figé à la compilation, pas d'analyse de format à faire) — je ne suis pas sûr que ce soit plus lent puisque les écritures se font en mémoire RAM (ça construit un buffer comme vous le faites)

N'oubliez pas que de toutes façons, avec un print ou 10 prints, rien n'est écrit dans la carte SD de toutes façons avant que le buffer de 512 octets soit plein ou que vous fassiez un close() sur le fichier ou que vous appeliez flush().

La fermeture prend du temps parce que c'est généralement là que tout le buffer est transféré sur la carte elle même.

Cela dit, si vous n'avez pas de souci de place mémoire, votre approche est simple et lisible.