Algunos países cambian la hora según Verano o invierno. En España por ejemplo, El horario de verano empieza a las 02:00 Am del ultimo domingo de Marzo y finaliza a las 03:00 horas del ultimo domingo del mes de octubre. Eso significa, que el ultimo domingo de octubre a las 03:00 tenemos que restar una hora al reloj, mientras que el ultimo domingo de Marzo a las 02:00 tenemos que sumarla.
He querido implementar una función que sea capaz de hacer esto con un rtc y la quiero compartir por si a alguien le interesa, aparte de para mejorarla si alguien ve mejores formas "y las habrá" de hacer determinadas cosas. El código está comentado. Utilizo un rtc DS1307. Es necesario utilizar el byte del registro día de la semana del rtc y ajustarlo cuando se ajusta la fecha y la hora ya que el rtc no calcula automáticamente el día de la semana (Lunes---Domingo) a partir de la fecha, que también se podría hacer.
Lo que hago fundamentalmente es grabar una bandera en la eeprom interna (también se podría grabar en una posición de ram de uso libre del rtc) , la bandera la llamo "Sunset", si vale 1 es por que estamos en horario de verano. Si vale cero, es horario invierno.
Al arrancar el programa se lee esta bandera y se pasa por la función que lo que hará será preguntar primero si estamos en los meses (Noviembre, diciembre, enero o febrero), en tal caso es fácil, si estamos en esos meses y la bandera SUNSET está a 1, tenemos que cambiar la hora. La cambiamos y grabamos la bandera sunset a cero.
Si Sunset estaba a cero pues no pasará nada.
La complicación viene en los meses de Octubre y Marzo. Son dos operaciones:
Si es octubre, primero pregunto si estamos en la ultima semana del mes, de ser así, pregunto si es domingo, de ser así pregunto si son mas de las 03:00 am y de ser así activo horario de invierno, resto la hora, la ajusto en el rtc, pongo SUNSET a cero y lo grabo en eeprom interna.
Si lo anterior no se cumple, por ejemplo, por que el domingo ya ha pasado, vuelvo a preguntar lo mismo, si es octubre, si estamos en la ultima semana del mes y determino mediante una diferencia y una suma si a lo largo de esa semana ha transcurrido el domingo. De ser así pues lo mismo, activo horario invierno.
Luego para Marzo se hace exactamente lo mismo, con la diferencia de que hay que preguntar cuando sean las 02:00 para sumarle la hora.
Un folloncete en verdad. Ahí os dejo el código..
void sunsett() {
int i = 0;
// sunset (cambio automático horario de verano e invierno)
// ( desde ultimo domingo de marzo a ultimo domingo de octubre es horario de verano sunset = 1)
// para determinar si estamos en horario de verano o invierno, inicialmente creamos variable local "localsunset" y la inicializo con el valor de sunset que está grabado en la eeprom interna.
int8 localsunset = sunset; // cargamos el horario actual.
if ((mes == 1) || (mes == 2) || (mes == 11) || (mes == 12)) localsunset = 0; // si estamos en algunos de estos meses, marcamos horario de invierno. (localsunset = 0)
if ((mes == 10) && ((dia>=25) && (dia <=31))) { // si es octubre y además estamos en la ultima semana del mismo mes
if ((weekday == 6) && (horas >= 3)) localsunset = 0; // si es domingo y son mas de las 3 de la mañana ponemos horario de invierno.
// si no es domingo tenemos que averiguar si ya lo ha sido
else {
int8 dif = 31 - dia; // hallamos los dias que restan hasta final de mes.
int8 suma = dif + weekday; // sumo el valor del dia de la semana a los dias que restan hasta fin de mes
// el domingo en weekday sería el 6.
if (suma <=6) localsunset = 0; // si da 6 o menos de 6 es por que ya ha sido domingo, por lo que activamos horario de invierno.
}
}
if ((mes == 3) && ((dia>=25) && (dia <=31))) { // si es Marzo y además estamos en la ultima semana del mismo mes
localsunset = 0; // en Marzo continuamos en horario de invierno salvo.....
if ((weekday == 6) && (horas >= 2)) localsunset = 1; // si es domingo y son mas de las 3 de la mañana ponemos horario de verano.
// si no es domingo tenemos que averiguar si ya lo ha sido
else {
int8 dif = 31 - dia; // hallamos los dias que restan hasta final de mes.
int8 suma = dif + weekday; // sumo el valor del dia de la semana a los dias que restan hasta fin de mes
// el domingo en weekday sería el 6.
if (suma <=6) localsunset = 1; // si da 6 o menos de 6 es por que ya ha sido domingo, por lo que activamos horario de verano
}
}
// activamos y grabamos la bandera sunset que corresponda
posi (40,40);
printf("TT Ls:%u \r\n ss:%u \r\n ",localsunset
,sunset
); delay_ms(500);
if (sunset != localsunset) { // si localsunset no coincide con sunset es por que ha cambiado....
if (sunset == 1) { // si estabamos en horario de verano
horas = horas - 1; // restamos una hora al reloj
setrtc(); // grabamos en el rtc
sunset = 0; // indicamos que estamos ahora en horario de invierno.
write_eeprom(25,sunset); // grabamos en la eeprom interna.
}
else { // si estabamos en horario de invierno
horas = horas + 1; // sumamos una hora al reloj
setrtc(); // grabamos en el rtc
sunset = 1; // activamos horario de verano.
write_eeprom(25,sunset); // grabamos en la eeprom interna.
}
}