Cálculo del horario de verano e invierno con RTClib

Estoy trabajando en un proyecto que incluye un reloj digital que mantiene la hora local y UTC. Utilizo un Arduino NANO y un RTC DS3132, de los que incluyen memoria y uina batería recargable. La librería que utilizo el RTClib. He probado diferentes librerías que por una u otra razón consigo hacerme con ellas.

Uno de los objetivos que me he propuesto es que el RTC, sin conexión a ethernet o GSP pueda realizar el cambio horario de forma automática con las funciones disponibles en la librería.

El primer paso ha sido detectar si el horario es el de verano que, en España peninsular, va desde las dos horas del último domingo del mes de marzo hasta las dos horas del último domingo del mes de octubre. Principalmente para descontar del tiempo local una hora en el de invierno o dos horas en el de verano para calcular el tiempo UTC desde el horario local o a la inversa si el RTC se programa para que cuente el tiempo desde el UTC que es constante.

He diseñado la función cuyo código acompaño que he probado y parece que funciona, pero como soy nuevo en este lenguaje agradecería cualquier comentario crítico sobre una forma más eficiente de desarrollo.

bool isTimeSummer (DateTime dt) {
  bool its = LOW;
  int dom = dt.day();
  int dow = dt.dayOfTheWeek();

  if (dt.month() == 3) {
    if (dom > 25) {
      if (dow == 0) {
        if (dt.hour() > 2) {
          its = HIGH;  
        } 
      } else {
        if (25-dom + dow <= 0) {
          its = HIGH;
        }
      }
    }
  } else if (dt.month() == 10) {
    if (dom <= 24) {
      its = HIGH;
    } else {
      if (dow == 0) {
        if (dt.hour() < 2) {
          its = HIGH;
        }
      } else {
        if (25 - dom + dow > 0) {
          its = HIGH;
        }
      }
    }
  } else if (dt.month() > 3 && dt.month() < 10) { 
      its = HIGH; 
  }
  return its;
}

Me parece que lo estás haciendo muy bien. No me puse a analizar el código para ver si funciona, pero en general lo veo bastante eficiente, y a simple vista parece que funciona bien.

Seguramente vas a tener que hacer un par de funciones mas, y cumplirás el objetivo. Pienso que la fecha-hora que maneja la librería tiene que ser la fecha-hora UTC, y tienes que hacer las funciones que devuelvan la fecha-hora local. Y lo que ya hiciste creo que es el 90%, te falta muy poquito, solamente dos funciones que convierta la fecha-hora UTC a local, y al revés.

Muchas gracias Ener. Efectivamente, inicio el reloj en tiempo UTC, ya que éste no varía y un par de funciones se encargan de calcular la hora local.

Esta función, cuando se desmarca pone a punto el tiempo del RTC, teniendo en cuenta de que el tiempo de compilación tiene un retraso aproximado de 12 segundos.

void setTimeClock () {
  int initYear = 2019;
  int initMonth = 10;
  int initDay = 9;
  int initHour = 13;
  int initMinute = 37;
  rtc.adjust(DateTime(initYear, initMonth, initDay, initHour, initMinute, 0));
}

Otra función comprueba si período del horario es el de verano o el de invierno y carga la variable utcOffSet con 1 o 2 horas de desviación.

enum Period {IS_WINTER, IS_SUMMER};

int calcUtcOffset (DateTime t) { 
  bool period = isTimeSummer (t);
  if (period = IS_WINTER) {
    return 1;
  } else if (period = IS_SUMMER) {
    return 2;
  }
}

Una tercera función prepara la hora local independiente dela hora UTC y corrige la desviación sobre 24 horas que produce la suma del ajuste de la hora UTC.

String processLocalTime (DateTime t) {
  int utcOffset = calcUtcOffset(t);
  int hourUtc = t.hour() + utcOffset;  

  if (hourUtc > 23) {
    hourUtc -= 24;
  }
  
  char buf_time_local[9];
  snprintf(buf_time_local, sizeof(buf_time_local), "%02d:%02d:%02d",
    hourUtc, t.minute(), t.second());
    
  return buf_time_local;  
}

Mi hijo, que es coder (javascript y otros lenguajes) me dice que es una ñapa y que seguro que hay un bug esperando salir, que la corrección del huso de la hora es algo mucho más complicado y puede que tenga razón, pero para este año, en gran parte de Europa este cálculo puede ser válido (con permiso del bug). Si se trata de otros países o de un cambio de criterios con respecto a los horarios de verano e invierno ya habrá tiempo de corregir el código, digo yo.

Yo he probado tu código hasta octubre de 2022 y ha funcionado, hice un bucle sumando una hora a unixtime hasta octubre 2022.

Para sumarle la hora que te falta es tan sencillo como hacer

DateTime((now.unixtime() + 3600))

sin tener que preocuparte de si son las 23 y cambia de dia, de si es final de mes etc, la libreria se encarga de calcularlo.

¡Excelente idea krnlpanic!, evidentemente la hora local será:

DateTime((now.unixtime() + (3600 * utcOffSet));

Voy a probar.

¡Funciona!

String processLocalTime (DateTime t) {
  int utcOffset = calcUtcOffset(t);

  DateTime dt (t.unixtime() + (utcOffset * 3600));
    
  char buf_time_local[9];
  snprintf(buf_time_local, sizeof(buf_time_local), "%02d:%02d:%02d",
    dt.hour(), t.minute(), t.second());
    
  return buf_time_local;  
}

Saca la hora local sin, como apuntas, preocuparme del formato. La sintaxis está ligeramente corregida.