Sommerzeit/ Winterzeit automatisch umstellen

Hallo,

Da das Thema bald ansteht hab ich mich mal damit etwas beschäftigt.
Zum Thema selbst habe ich hier im Forum folgenden Code gefunden.

boolean summertime_EU(int year, byte month, byte day, byte hour, byte tzHours)
// European Daylight Savings Time calculation by "jurs" for German Arduino Forum
// input parameters: "normal time" for year, month, day, hour and tzHours (0=UTC, 1=MEZ)
// return value: returns true during Daylight Saving Time, false otherwise
{
  if (month < 3 || month > 10) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
  if (month > 3 && month < 10) return true; // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
  if (month == 3 && (hour + 24 * day) >= (1 + tzHours + 24 * (31 - (5 * year / 4 + 4) % 7)) || month == 10 && (hour + 24 * day) < (1 + tzHours + 24 * (31 - (5 * year / 4 + 1) % 7)))
    return true;
  else
    return false;
}

beim upload gibt es eine Warnung.

C:\Users\Heinz\Documents\Arduino\D1mini\displayNTP\displayNTP.ino:150:18: warning: suggest parentheses around '&&' within '||' [-Wparentheses]

   if (month == 3 && (hour + 24 * day) >= (1 + tzHours + 24 * (31 - (5 * year / 4 + 4) % 7)) || month == 10 && (hour + 24 * day) < (1 + tzHours + 24 * (31 - (5 * year / 4 + 1) % 7)))

                  ^

ich denke mal man sollte noch für das oder je zwei Klammer machen. siehe code unten dann ist das weg.

aber bei der Analyse der Zeile ist mir was anderes aufgefallen.

hour und day sind als byte deklariet, die Berchnung hour+24*day kann grösser sein als 255 . Geht das dennoch weil intern auch in dem Fall mit integer gerechnet wird?

für die ESP Famile gibt es ja die neue Funktion configTime() die ja recht einfach zu händeln ist.
zur Einstellung der Sommer und Winterzeit gibts einen Parameter den man aber nicht wirklich für die automatische Umstellung nutzen kann denke ich. Wenn man nun die obige Funktion summertime_EU verwendet erhält man ja eine bool Variable zurück, abhängig davon kann man dann z.B. dst 0 oder 3600 setzen Alledings würde dann die Zeitumstellung tatsächlich erst beim nächsten Sync aktive werden, oder ??

configTime(3600, dst , “pool.ntp.org”, “time.nist.gov”);

ich hab jetzt abhängig von Sommerzeit bei hour eine Stunde zu addiert, gefällt mir aber eigendlich nicht so gut. Eigendlich ist es ja fast egal , ist ja eh mitten in der Nacht, aber dennoch hat noch einer eine gute Idee ? Man müste nach einem Sync einmalig die Funktion aufrufen und dann

time_t now = time(nullptr)+3600*sommerzeit

hier mein Versuchscode.

// Hardware ESP  D1 


#include <ESP8266WiFi.h>
#include <time.h>

const char* ssid = "xxxx";
const char* password = "xxxx";
int timezone = 1;
int dst = 3600;
bool sommerzeit = 0;

int year;
byte month, day, hour, minute, second;

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("\nConnecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }
  configTime(timezone * 3600, dst * 0, "pool.ntp.org", "time.nist.gov");
  Serial.println("\nWaiting for time");
  while (!time(nullptr)) {
    Serial.print(".");
    delay(1000);
  }
  Serial.println("");
}

void loop() {

  readtime();
  Serial.printf("%02u-%02u-%4u\n", day, month, year);
  Serial.printf("%02u:%02u:%02u\n", hour, minute, second);
  delay(1000);
}
// Datum und zeit auslesen
void readtime() {
  time_t now = time(nullptr);
  struct tm*timeinfo;
  time(&now);
  timeinfo = localtime(&now);
  year = 1900 + timeinfo->tm_year;
  month = 1 + timeinfo->tm_mon;
  day = timeinfo->tm_mday;
  hour = timeinfo->tm_hour + sommerzeit;
  minute = timeinfo->tm_min;
  second = timeinfo->tm_sec;
  sommerzeit = summertime_EU(year, month, day, hour, 0);
  
}

boolean summertime_EU(int year, byte month, byte day, byte hour, byte tzHours)
// European Daylight Savings Time calculation by "jurs" for German Arduino Forum
// input parameters: "normal time" for year, month, day, hour and tzHours (0=UTC, 1=MEZ)
// return value: returns true during Daylight Saving Time, false otherwise
{
  if (month < 3 || month > 10) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
  if (month > 3 && month < 10) return true; // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
  if ((month == 3 && (hour + 24 * day) >= (1 + tzHours + 24 * (31 - (5 * year / 4 + 4) % 7))) || ( month == 10 && (hour + 24 * day) < (1 + tzHours + 24 * (31 - (5 * year / 4 + 1) % 7))))
    return true;
  else
    return false;
}

Heinz

Eine verbesserte Version hoffentlich ohne Warnungen.

Rentner:
hour und day sind als byte deklariet, die Berchnung hour+24*day kann grösser sein als 255 . Geht das dennoch weil intern auch in dem Fall mit integer gerechnet wird?

Ich komme auf maximal 167:

byte hour=23, day=6;
void setup()
{
  Serial.begin(9600);

  Serial.print("Ergebnis: ");
  Serial.println(hour+24*day);
}

void loop()
{
}

Wie kommst Du auf mehr?

Rentner:
Geht das dennoch weil intern auch in dem Fall mit integer gerechnet wird?

Grundsätzlich betrachtet ja.

Hallo
Hab ich da falsch gedacht , day kann doch bis 31 gehen. ?
In der structure gibt's noch w_day ? Tag der Woche
Heinz

Ja, da habe ich falsch geschaut, also 767 liegt deutlich außerhalb von 0 bis 255.

Zu beachten: Bei den 32 bittigen µCs hat int einen größeren Zahlenumfang als bei den achtbittigen.

Hi

Um den Code 'µC-sicher' zu bekommen, benutze ich deshalb
byte (8 Bit, vorzeichenlos, 0...255)
uint8_t (8 Bit, vorzeichenlos ... = Byte)
uint16_t, uint32_t, uint64_t (die jeweilige Zahl gibt die Bitbreite an, das U bedeutet unsigned - also Vorzeichenlos, kleinste Wert 0)
int8_t (8 Bit, mit Vorzeichen, -128 ... 127 - sind wieder 256 Zustände. Ähnlich uint8_t, nur, daß hier das oberste Bit das Vorzeichen angibt)
Gleiches für int16_t, int32_t, int64_t

So ist zumindest von vorne herein klar, wie groß die enthaltene Zahl werden kann, egal, wie viele Bit der µC selber intern benutzt.
Ob ein 32-Bit µC bei einem uint8_t trotzdem 4 Byte (entspricht 32 Bit) reserviert - kA - der Sketch hat aber auf dem kleinen AVR, wie auf den deutlich dickeren ARM eine Zahl, Die 8 Bit breit ist - INT wird je nach µC verschieden benutzt.

MfG

Bei uintX_t bei der Variablen/Konstanten-Deklaration stimme ich Dir zu, Heinz geht es aber um die Aktivitäten rechts vom Gleichheitszeichen, die sich nicht vom Typ links davon beeinflussen lassen. Das geschieht erst bei der Wertzuweisung.

Hi

Dazu las ich hier(?), daß die Rechnung mit dem Datentyp des ersten Operator durchgeführt wird - oder des Cast vor der ersten Variable/Zahl.
Deshalb Ergebnisse, Die in float benötigt werden mittels 1.0*..... anfangen, da die 1.0 float vorgibt und der Rest 'in float' berechnet wird.

MfG

PS: Korrekturen/Links erbeten

Ja, das ist richtig. Auswertung von links nach rechts zur Laufzeit. Bei Konstanten zur Compilezeit habe ich es auch schon andersrum erlebt.

Also das ging:

const uint32_t zeit = 10 * 60 *1000UL; // 10 Minuten

Gruß Tommy

Hallo,

danke für die regen Beteiligung. Da die Funktion ja bereits etwas älter ist war ich eigendlich schon davon ausgegangen das sie funktioniert, tut sie ja auch.

Dennoch habe ich das mal getestet wie sich verhält und warum es zu keinem Überlauf kommt. Ob es zu einem Überlauf kommt scheint also, zumindest bei byte, tatsächlich nur davon abzuhängen welcher Typ links vom = steht.

Eigendlich gings mir aber darum ob noch jemand eine gute Idee hat das Thema Sommerzeit in Verbindung mit configTime anders zu lösen.

Guß Heinz

byte hour, day;
byte erg;
int erg1;

void setup() {
  day = 30;
  hour = 10; 
  Serial.begin(9600);

  erg = hour + 10 * day; // alles Byte
  erg1 = hour + 10 * day;// links vom = Ist interger

  Serial.print(erg); Serial.println(" als Byte falsch war zu erwarten");
  Serial.print(hour + 10 * day); Serial.println(" ausdruck innerhalb print ist richtig");
  Serial.print(erg1); Serial.println(" Ergebnis als Int ist richtig");

  if (hour + 10 * day > 300) {
    Serial.println( "innerhalb von If geht Bedingung ist richtig");
  }
}

void loop() {
  // put your main code here, to run repeatedly:
}

Ich lasse intern alles in UTC laufen und zähle nur für die Anzeige auf die UNIX-Time 3600 oder 7200 drauf (Winter/Sommerzeit). Damit muss ich nicht bei der Umstellung syncen.

Gruß Tommy

Hi

Ganz nebenbei hast Du so eine weltweit gültige Zeit, Die man auch untereinander vergleichen kann.
Für den heimischen Basteltisch vll. nicht sonderlich wichtig, schadet Es aber nicht, wenn man die Daten nur für den Bediener aufbereitet - also nur für die Anzeige die Zeit anwenderfreundlich rechnen.

MfG

Vor allem habe ich in der Datenbank keine Probleme in der Umstellungsnacht.
Key ist UTC, ein Sommezeitflag wird mit abgespeichert.
Damit kann ich auch aus der DB problemlos Userfreundlich anzeigen, habe aber keine Probleme mit dem PK.

Gruß Tommy

Edit: Ich ziehe zusätzlich Luftdruckdaten vom Flughafen Nürnberg mit rein, die haben immer UTC+1

PK?

postmaster-ino:
PK?

Pressekonferenz…?!?

themanfrommoon:
Pressekonferenz…?!?

Man sollte keine Zitate zitieren. “Probleme mit dem PK”(#11) schließt aber “Pressekonferenz” aus. Die war nämlich schon vor dem ganzen Gender-Quatsch weiblich.

Da Tommy schon schreibt, dass es sich bei seinem DateTime-Feld um einen "Key" handelt, wird er den Primärschlüssel seiner Datenbank Tabelle meinen.
Macht dann auch Sinn zu verhindern, dass in der Stunde der Zeitumstellung zweimal die selben Uhrzeiten auftreten könnten.

Der Primary Key. Key = Schlüssel. Schlüssel hat Bart. Schlüssel = Männlich. Ist doch klar...

Extrem [OT], aber was ist denn eigentlich mit Jurs unserem Zeitexperten?

mde110:
Extrem [OT], aber was ist denn eigentlich mit Jurs unserem Zeitexperten?

Der ist im Arduino Ruhestand.

Ich bedauere das, weil ich viel von ihm gelernt habe, aber seine letzten Kommentare klangen extrem genervt.

Hallo,

möchte kurz über meinen Misserfolg berichten.
Meine Lösung auf die Variable hour in Abhängigket von der Funktion summertime_EU eine Stunde zu zu addieren war natürlich ein grober Flop. :sob:

Gestern nach Mitternacht hab ich bemerkt das mit der Lösung als Zeit 24:10:15 angezeigt wurde und das Datum nicht aktualisiert war. Und da viel es mir wie Schuppen von den Augen, kar so geht das nicht, hatte ja von Anfang an so ein grummeln im Bauch damit.

So jetzt hab ich mir was neues einfallen lassen mal sehen ob das klappt, komisch es grummelt immer noch. :slight_smile:

Lösungsansatz ist der . Im Setup wird die Funktion configTime(... ) aufgerufen. Wenn die Zeit angekommen ist wird ermittelt ob Sommerzeit ist . Anschliessend wird configTime nochmals aufgerufen mit dst Parameter 0 oder 3600.

Beim starten funkioniert das , das synchronisieren jede Stunde geht auch, bei der Zeitumstellung nächste Woche wird die Umstellung aber sicher maximal eine Stunde zu spät sein, hängt davon ab wann planmässig synchronisiert wird.

Gruß Heinz

Hallo zusammen, habe auch einen kleinen Sketch zur Umstellung auf Sommerzeit geschrieben. Es muss in der Programmierung der Anzeige der von der DS 3231 gelesenen Uhrzeit noch die Variable stundesz initialisiert werden (int stundesz = “”:wink: und in der Einfügung in den String outputLine2 += stunde;" in “stundesz” (s.u.) geändert werden.

void printRTCDateTime()
{
  int dOW = calcDayOfWeek(jahr, monat, tag);
  String wochentagC = daysInWeek[dOW];
  String monatC = monthInYear[monat-1];
    
  wochentag = calcDayOfWeek(jahr, monat, tag);
  stundesz = stunde;
  if (monat > 3 && monat < 10)  // In den Monaten April - September gilt an allen Tagen die Sommerzeit
    {
      stundesz = stunde + 1; // = Sommerzeit
    }

  if (monat == 3 && tag >= 25) //  Es werden nur Tage in der letzten Woche berücksichtigt
    {
      if (wochentag == 0 && stunde >= 02 || tag - wochentag > 25 && wochentag != 0)  // Wenn das Datum auf einen Sonntag (hier werktag = 0 und die MEZ ist gleich oder später als 2:00 Uhr) oder auf einen Wochentag danach fällt, dann ist
        {
          stundesz = stunde + 1;  // Sommerzeit
        }
    }
  
  if (monat == 10 && tag >= 25) //  Es werden nur Tage vor der letzten Woche berücksichtigt
    {
      if (wochentag == 0 && stunde < 02 || tag - wochentag <)  // Wenn das Datum auf einen Sonntag (hier werktag = 0 und die MEZ ist früher als 2:00 Uhr) oder auf einen Wochentag davor fällt, dann ist
        {
          stundesz = stunde + 1;  // Sommerzeit
        }
    }

  outputLine1 = "";
  outputLine1 += wochentagC;
  outputLine1 += ". ";
  if(tag<10) { outputLine1 += "0"; }
  outputLine1 += tag;
  outputLine1 += ".";
  outputLine1 += monatC;
  outputLine1 += ".";  
  outputLine1 += jahr;
 
  outputLine2 = "";

  if(stunde<10) { outputLine2 += "0"; }
  outputLine2 += stundesz;                           Hier muss stunde durch stundesz ersetzt werden
  outputLine2 += ":";
  if(minute<10) { outputLine2 += "0"; }
  outputLine2 += minute;
  outputLine2 += ":";
  if(sekunde<10) { outputLine2 += "0"; }
  outputLine2 += sekunde;
}