Calcul éphéméride précis : lever et coucher de soleil

Oui :smiling_imp:

Voici un programme exemple, bricolé vite fait à partir de ma lib simpleRTC, qui contient les fonctions de base nécessaires aux calculs.

void setup()
{
  Serial.begin(115200);
  delay(500);

  demo(0);

  demoUnix(1608316975UL); // le 18/12/2020 à 18:42:55 UTC (heure hiver)
  demoUnix(1600454575UL); // le 18/09/2020 à 18:42:55 UTC (heure été)
}

void loop()
{
}

//timestamp contient le nombre de secondes écoulées depuis le 01/01/2000 00:00:00 UTC
void demo(uint32_t timestamp)
{
  Serial.print("\ntimestamp=");
  Serial.println(timestamp);

  uint8_t annee, mois, jour, heure, minute, seconde;
  decomposer(timestamp, &annee, &mois, &jour, &heure, &minute, &seconde);

  afficher(annee, mois, jour, heure, minute, seconde);
  Serial.println(" UTC");

  if (heureEte(annee, mois, jour, heure))
  {
    timestamp += 7200;
  }
  else
  {
    timestamp += 3600;
  }
  decomposer(timestamp, &annee, &mois, &jour, &heure, &minute, &seconde);

  afficher(annee, mois, jour, heure, minute, seconde);
  Serial.println(" local");
}

//un timestamp unix contient le nombre de secondes écoulées depuis le 01/01/1970 00:00:00 UTC
void demoUnix(uint32_t timestampUnix)
{
  const uint32_t SECONDES_ENTRE_1970_ET_2000 = 946684800UL;
  demo(timestampUnix - SECONDES_ENTRE_1970_ET_2000);
}

//calcul du nombre de jours d'un mois
uint8_t nbJoursMois(uint8_t annee, uint8_t mois)
{
  return (mois==4 || mois==6 || mois==9 || mois==11) ? 30 : (mois==2 ? ((annee&3) ? 28 : 29) : 31);
}

//décomposition d'un timestamp en année/mois/jour/heure/minute/seconde
void decomposer(uint32_t timestamp, uint8_t *annee, uint8_t *mois, uint8_t *jour, uint8_t *heure, uint8_t *minute, uint8_t *seconde)
{
  //Partie facile
  *seconde = timestamp % 60;
  timestamp /= 60;
  *minute = timestamp % 60;
  timestamp /= 60;
  *heure = timestamp % 24;

  //Partie amusante
  uint16_t jours = timestamp / 24;

  const uint16_t JOURS_PAR_ANNEE = 365;
  const uint16_t JOURS_PAR_4_ANNEES = 1 + 4 * JOURS_PAR_ANNEE;
  const uint16_t QUANTIEME_29_FEVRIER_2000 = 31 + 29;

  uint8_t nb_29_fevrier_echus = (jours + (JOURS_PAR_4_ANNEES - QUANTIEME_29_FEVRIER_2000)) / JOURS_PAR_4_ANNEES;
  *annee = (jours - nb_29_fevrier_echus) / JOURS_PAR_ANNEE;

  jours -= ((uint16_t) *annee) * JOURS_PAR_ANNEE + ((*annee + 3) >> 2) - 1;

  *mois = 1;
  uint8_t duree_mois = nbJoursMois(*annee, *mois);
  while (jours > duree_mois)
  {
    jours -= duree_mois;
    *mois = *mois + 1;
    duree_mois = nbJoursMois(*annee, *mois);
  }

  *jour = jours;
}

//détermination de l'heure été ou hiver
bool heureEte(uint8_t anneeUTC, uint8_t moisUTC, uint8_t jourUTC, uint8_t heureUTC)
{
  //En France métropolitaine :
  //Passage de l'heure d'hiver à l'heure d'été le dernier dimanche de mars à 1h00 UTC (à 2h00 locales il est 3h00)
  //Passage de l'heure d'été à l'heure d'hiver le dernier dimanche d'octobre à 1h00 UTC (à 3h00 locales il est 2h00)

  const uint8_t MARS = 3;
  const uint8_t OCTOBRE = 10;

  if (moisUTC == MARS)
  {
    uint8_t dernierDimancheMars = 31 - ((5 + anneeUTC + (anneeUTC >> 2)) % 7); //Pas évidente à trouver celle-là
    return jourUTC > dernierDimancheMars || (jourUTC == dernierDimancheMars && heureUTC != 0);
  }

  if (moisUTC == OCTOBRE)
  {
    uint8_t dernierDimancheOctobre = 31 - ((2 + anneeUTC + (anneeUTC >> 2)) % 7);
    return jourUTC < dernierDimancheOctobre || (jourUTC == dernierDimancheOctobre && heureUTC == 0);
  }

  return MARS < moisUTC && moisUTC < OCTOBRE;
}

//Calcul du jour de la semaine : 0 Dimanche, 1 Lundi, etc.
uint8_t calculerJoursem(uint8_t annee, uint8_t mois, uint8_t jour)
{
  //Formule maison, économe en calculs fin d'épargner les petits processeurs 8 bits
  uint8_t somme = annee + (annee >> 2) + jour;
  switch (mois)
  {
  case  2 :
  case  3 :
  case 11 : somme++;    break;
  case  6 : somme += 2; break;
  case  9 :
  case 12 : somme += 3; break;
  case  4 :
  case  7 : somme += 4; break;
  case  1 :
  case 10 : somme += 5; break;
  case  5 : somme += 6;
  }
  if (mois > 2 || (annee & 3)) somme++;
  return somme % 7;
}

void afficher(uint8_t annee, uint8_t mois, uint8_t jour, uint8_t heure, uint8_t minute, uint8_t seconde)
{
  uint8_t joursem = calculerJoursem(annee, mois, jour);

  switch (joursem)
  {
    case 0 : Serial.print("dim "); break;
    case 1 : Serial.print("lun "); break;
    case 2 : Serial.print("mar "); break;
    case 3 : Serial.print("mer "); break;
    case 4 : Serial.print("jeu "); break;
    case 5 : Serial.print("ven "); break;
    case 6 : Serial.print("sam "); break;
  }  

  Serial.print("20");
  Serial2print(annee);
  Serial.print('/');
  Serial2print(mois);
  Serial.print('/');
  Serial2print(jour);
  Serial.print(' ');
  Serial2print(heure);
  Serial.print(':');
  Serial2print(minute);
  Serial.print(':');
  Serial2print(seconde);
}

void Serial2print(uint8_t nombre)
{
  if (nombre < 10) Serial.print('0');
  Serial.print(nombre);
}
1 Like

Merci.
Je me demande si ce n'est pas plus simple de récupérer l'information depuis un module dcf77, d'autant plus que le changement d'heure est censé disparaître en europe bientôt...