RTC mit Sommerzeit

Hi!

Habe das Netz schon auf den Kopf gestellt, aber leider nicht das richtige gefunden, oder einfach nach dem Falschen gesucht.

Also - ich suche einen Code, den ich in meinen Sketch einfügen kann, damit ich die Uhrzeit vom DS1307 RTC-Modul auch bei Sommer/Winterzeit korrekt angezeigt bekomme.

Im Moment klappt das mit der Sommerzeit nicht.
Habe die Uhrzeit mit dem Pc gestellt. Obwohl mein Pc gerade 20:24 anzeigt, zeigt das Display vom Arduino 19:26 an?

Gestellt habe ich hiermit:

/*
 * TimeRTCSet.pde
 * example code illustrating Time library with Real Time Clock.
 *
 * RTC clock is set in response to serial port time message 
 * A Processing example sketch to set the time is inclided in the download
 */

#include <Time.h>  
#include <Wire.h>  
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t


void setup()  {
  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");      
}

void loop()
{
  if(Serial.available())
  {
     time_t t = processSyncMessage();
     if(t >0)
     {
        RTC.set(t);   // set the RTC and the system time to the received value
        setTime(t);          
     }
  }
   digitalClockDisplay();  
   delay(1000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

/*  code to process time sync messages from the serial port   */
#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message

time_t processSyncMessage() {
  // return the time if a valid sync message is received on the serial port.
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    Serial.print(c);  
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();          
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }   
      return pctime; 
    }  
  }
  return 0;
}

Kann da jemand helfen?

Gruß
Morris

Das mit der Sommerzeit ist recht aufwändig zu berechnen, aber es gibt eine Lib "DS1307new.h", die das unterstützt.
Sie stellt (neben den üblichen anderen Funktionen) auch die Funktion isMEZSummerTime() zur Verfügung.

guntherb:
Das mit der Sommerzeit ist recht aufwändig zu berechnen, aber es gibt eine Lib "DS1307new.h", die das unterstützt.

Ich mache die Feststellung der Sommerzeit mit gerade mal sechs Zeilen Code im Codeblock, davon eine längere if-Abfrage.

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;
}

Zu übergeben an die Funktion ist eine "Zonenzeit", also die Zeit auf der man die Echtzeituhr am besten dauernd laufen läßt:

  • Jahr
  • Monat
  • Tag
  • Stunde
  • Zeitzone (UTC=0, MEZ=1)
    und Rückgabewert ist true oder false, je nachdem ob man für Sommerzeit eine Stunde draufschlagen muss oder nicht.

Im Fall der Time-Library, die mit Unix-Time "Sekunden seit 01.01.1970" arbeitet, würde man also bei Sommerzeit 3600 Sekunden auf die Zonenzeit UTC+1 draufschlagen.

Habe es mit der DS1307new (1.24) versucht.

Ergebnis vom Test:

DS1307 Testsketch
Format is "hh:mm:ss dd-mm-yyyy DDD"
MEZ=0, MESZ=1 : 1

19:40:14 15-06-2013 SAT seconds since 1.1.2000:424640414 MEZ=0, MESZ=1 : 1 - Address in NV-RAM is: 0 - Clock was set!
19:40:15 15-06-2013 SAT seconds since 1.1.2000:424640415 MEZ=0, MESZ=1 : 1 - Address in NV-RAM is: 1 - Clock was set!
19:40:16 15-06-2013 SAT seconds since 1.1.2000:424640416 MEZ=0, MESZ=1 : 1 - Address in NV-RAM is: 2 - Clock was set!

Es ist jedoch laut meinem Rechner 20:38. Also 1ne Stunde und 2 Minuten falsch

EDIT:
Ok, habe das Problem gelöst.
Habe einfach die aktuelle 1.0.5 installiert, die neue Time und DS1307 library installiert und die Zeit gestellt.
Nun ist die Uhrzeit korrekt!

Der thread ist einige Jahre alt, aber für mich ist das Sommerzeitthema immer noch aktuell.
jurs - schreibt

" Ich mache die Feststellung der Sommerzeit mit gerade mal sechs Zeilen Code im Codeblock, davon eine längere if-Abfrage."

Ich habe deine if - Abfrage übernommen und einen kleinen Testsketch geschieben.

Als Ergebnis bekommen ich nicht das richtige Datum für die Sommerzeit.

Sommerzeitbeginn "Ermittelter Sommerzeitbeginn"
31.03.2013 25.03.2013
30.03.2014 31.03.2014
29.03.2015 30.03.2015
27.03.2016 28.03.2016
26.03.2017 27.03.2017
25.03.2018 26.03.2018
31.03.2019 25.03.2019
29.03.2020 30.03.2020
28.03.2021 29.03.2021
27.03.2022 28.03.2022
26.03.2023 27.03.2023
31.03.2024 25.03.2024
30.03.2025 31.03.2025
29.03.2026 30.03.2026
28.03.2027 29.03.2027
26.03.2028 27.03.2028

Das scheint nicht zu funktieren, oder?

Test_Sommerzeit.ino (740 Bytes)

Hoffmakl:
Das scheint nicht zu funktieren, oder?

Wie kommst du da drauf ?

Ich setze den Sketch seit einigen Jahren ein, bisher immer fehlerfrei.

Ja, Jurs Code rechnet richtig, aber die Jahreszahl muss 4stellig sein. Also nicht 18 sondern 2018, dann wird richtig gerechnet.

Hier nochmal der Code aus #4 mit der 4stelligen Jahreszahl - was dann zu richtigen Ergebnissen führt:

int year = 2013;    // nicht 13 sondern 2013
int month = 3;
int day = 1;
int hour = 2;
int MEZ = 0;
int Jahr;
bool Sommerzeit = false;


void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ;                                   // wait for serial port to connect. Needed for native USB port only
  }
  Serial.print("Jahr: ");
  Serial.println(year);
}


void loop() {
  if (Sommerzeit) {
    year++;
    day = 1;
    Sommerzeit = false;
  }

  if (month == 3 && (hour + 24 * day) >= (1 + MEZ + 24 * (31 - (5 * year / 4 + 4) % 7)))
  {
    Sommerzeit = true;
    Serial.print("Sommerzeit: ");
    Serial.print(day);
    Serial.print(".03.");
    Serial.println(year);
  }

  day++;
  delay(10);

}

Edit: Dass die Jahreszahl 4stellig sein muss wird auch hier erwähnt.

und wenn du mit hour = 2 und tzHours = 0 abfragst,
dann fragst du mit GMT/UTC ab, die Sommerzeit schaltet aber in GMT erst um 3h um.

Das würde mir die vermeintlichen Off-by-One Fehler erklären.

Kaum macht man's richtig und funktioniert.
Vielen Dank, für die schnellen und guten Antworten.
Das die Jahreszahl 4-stellig sein muss, hatte ich überlesen.

Mit der Uhrzeit will ich noch testen.
Benutze NTP und stelle den interne RTC des MKR1000 mit MEZ.

Noch eine Frage zur Wochentagsberechnung:
Ich berechne den Wochentag mit folgenden Zeilen

/* Tag 0 bis 6 (year 2-stellig für Jahr 2000 bis 2099) */
uint8_t KM[] = {23, 7, 8, 20, 0, 12, 20, 4, 16, 24, 8, 16};
WoTag = ((5 * year + KM[(month - 1)]) / 4 + day ) % 7 ;

oder (auch möglich)

/* Tag 0 bis 6 (Jahr 4-stellig 1901 bis 2099) */
WoTag = ((5 * Jahr + KM[(month - 1)]) / 4 + day –1 ) % 7

wie kommt man auf
WoTag = (5 * year /4 + 4) % 7 // (Jahr 4-stellig - Monat März)

würde gern auf (Jahr 2-stellig) umstellen.

stimmt, ist irrelevant. Man kann einfach 2000 addieren.

Hallo zusammen.

Ich weiss der Thread ist schon etwas älter.
Ich habe den original Thread in dem Jurs seine geniale Formel vorstellt nicht mehr gefunden.
Ich habe diese bei mir in eine Bibliothek eingebaut und beim testen gemerkt, dass etwas nicht stimmt.

Hier noch einmal die betreffende Codezeile von Jurs

 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;
}

So lange ich mit MEZ, also tzHours= 1 teste, ist alles ok.
Wenn ich aber mit GMT also tzHours = 0 teste, funktioniert die Umschaltung nicht um 2:00 Uhr sondern um 1:00

Wenn ich die entsprechende Zeile im Code (den ich nur ansatzweise verstehe) :o so ändere, funktioniert alles.

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

Die Detektierung der Umschaltung gilt ja immer für die Ortszeit. bei tzHours = 1 + 1 bin ich bei 2:00 Uhr Ortszeit. Bei tzHours = 0 (GMT) + 1 ist das Resultat aber schon um 1:00 true, also eine Stunde zu früh.

Vermutlich mache ja ich einen Überlegungsfehler. Immer wenn es um Verschiebung von Zeit geht wird mir ganz schummrig. :confused:

Kann das jemand ohne viel Aufwand nachvollziehen?
Umstellung 2018: 25. März 2:00 Ein / 28. Okt. 2:00 Aus

Danke schon jetzt.

Daves_DIY:
Ich habe den original Thread in dem Jurs seine geniale Formel vorstellt nicht mehr gefunden.

http://forum.arduino.cc/index.php?topic=313047.msg2193148#msg2193148

Von mir verbesserte Version im originalen Thema:
http://forum.arduino.cc/index.php?topic=313047.msg3483400#msg3483400

Probiere mal, ob es Dir hilft.