PaulStoffregen / Time

Time library for Arduino
http://playground.arduino.cc/code/time
1.24k stars 665 forks source link

Wrong values for year and month when converting unix timestamp to human readable time. #109

Open joje47 opened 5 years ago

joje47 commented 5 years ago

Description

Describe your problem. Wrong values for month and year when converting unix timestamp to human readable time.

NTP time is 1546258674 Get: 2018-6-117 12:17:54 Want: 2018-12-31 12:17:54

Steps To Reproduce Problem

Please give detailed instructions needed for anyone to attempt to reproduce the problem.

I get the timestamp correctly from NTP-server (verified using online epoch to human time converter) But when using time_t t = now(); Serial.println(t); Serial.print(year(t)); Serial.print("-"); Serial.print(month(t)); Serial.print("-"); Serial.print(day(t)); Serial.print(" "); Serial.print(hour(t)); printDigits(minute(t)); printDigits(second(t)); Serial.println(); the human readable time gets screwed up. Used the time functions without t variable to, same result.

Hardware & Software

Board Arduino Uno and pro mini (tested both, same result)

Shields / modules used ds3231 rtc esp8266 (esp-01)

Arduino IDE version 1.8.8

Version info & package name (from Tools > Boards > Board Manager) BN: Arduino/Genuino Uno VID: 2341 PID: 0043 SN: 75736303336351310210

Operating system & version Windows 10 latest update Any other software or hardware? No

Arduino Sketch


// Change the code below by your sketch (please try to give the smallest code which demonstrates the problem)
/*
   Koppla in klocka till sda/sdl samt wifi-kort TXD till a6, RXD till a7. Wifi ska drivas på 3.3v, samt CHPD ska vara strömsatt.
*/
#include <RtcDS3231.h>
#include <SoftwareSerial.h> // Since we want to use hw-serial for debugging
#include <Wire.h>
#include <WiFiEsp.h>
#include <WifiEspUdp.h>
#include <TimeLib.h>

const char ssid[] = "myssid";  //  your network SSID (name)
const char pass[] = "mypass";       // your network password

// NTP settings
char timeServer[] = "se.pool.ntp.org";
unsigned int localPort = 2390;  // local port to listen for UDP packets
const int NTP_PACKET_SIZE = 48;  // NTP timestamp is in the first 48 bytes of the message
const int UDP_TIMEOUT = 2000;    // timeout in miliseconds to wait for an UDP packet to arrive
byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets
const int timeZone = 1;     // Central European Time

// RTC module object
RtcDS3231<TwoWire> rtcModule(Wire);

// Wifi client object
WiFiEspClient client;

// SoftwareSerial object for Wifi module on pin 6 (RX) and 7 (TX).
// Wifi card needs to be preset to 9600b I.E. SoftwareSerials speed limit.
SoftwareSerial Serial1(6, 7);

// Set radio status
int status = WL_IDLE_STATUS;

// A UDP instance to let us send and receive packets over UDP (for NTP)
WiFiEspUDP Udp;

// Set up timelib
tmElements_t tm;
int Year, Month, Day, Hour, Minute, Second;

void setup()
{
  Serial.println();
  Serial.println("TimeNTP Lab");

  // Enable IC2 communication
  Wire.begin();

  Serial.begin(115200);

  // Start rtc module
  rtcModule.Begin();

  // Initialise serial for ESP module
  Serial1.begin(9600);
  WiFi.init(&Serial1);

  // Check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");

    // Dont continue
    while (true);
  }

  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.print("IP number assigned by DHCP is ");
  Serial.println(WiFi.localIP());
  Serial.println("Starting UDP");
  Udp.begin(localPort);

  Serial.println("waiting for sync");
  setSyncProvider(getNTPTime);
  setSyncInterval(300); // 300 sec = 5 min

  // Set clock to compile time to have a starting point
  RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
  rtcModule.SetDateTime(compiled);

  setRTCTime();
}

time_t prevDisplay = 0; // when the digital clock was displayed

void loop()
{
  if (timeStatus() != timeNotSet) {
    if (now() != prevDisplay) { //update the display only if time has changed
      prevDisplay = now();
      Serial.print("NTP time is ");
      digitalClockDisplay();

      RtcDateTime localNow = rtcModule.GetDateTime();
      char localTimeString[19];
      sprintf(localTimeString, "%04d-%02d-%02d %02d:%02d:%02d", localNow.Year() , localNow.Month(), localNow.Day(), localNow.Hour(), localNow.Minute(), localNow.Second());
      Serial.print("Local time is ");
      Serial.println(localTimeString);

      Serial.println();
    }
  }
}

void setRTCTime() {
  // Compare local time with NTP time
  // unsigned long currentTime = now(); // unix epoch
  time_t currentTime = now(); // unix epoch
  if (currentTime > 0) {
    Serial.print("NTP Time in unix epoch is ");
    Serial.println(currentTime);
    unsigned long epoch2k = currentTime - 946684800;
    Serial.print("NTP time in epoch2k is ");
    Serial.println(epoch2k);

    RtcDateTime localNow = rtcModule.GetDateTime();
    Serial.print("Local Time in epoch2k is ");
    Serial.println(localNow);

    if (localNow != epoch2k) {
      Serial.println();
      Serial.println("Setting time...");

      Serial.print("NTP time is ");
      digitalClockDisplay();
      char timeString[19];
      //sprintf(timeString, "%02d/%02d/%04d %02d:%02d:%02d", day(), month(), year(), hour(), minute(), second());
      sprintf(timeString, "%04d-%02d-%02d %02d:%02d:%02d", year(), month(), day(), hour(), minute(), second());

      char localTimeString[19];
      sprintf(localTimeString, "%04d-%02d-%02d %02d:%02d:%02d", localNow.Year() , localNow.Month(), localNow.Day(), localNow.Hour(), localNow.Minute(), localNow.Second());
      Serial.print("Local time is ");
      Serial.println(localTimeString);

      Serial.print("Trying to set local time to ");
      Serial.println(timeString);
      createElements(timeString);
      setTime(makeTime(tm));
      Serial.println();

      //setTime(currentTime);
      //setTime(currentTime);
      //rtcModule.SetDateTime(timeString);
    } else {
      Serial.println("Fick inget svar från NTP-tjänsten. Provar senare...");
    }
  }
}

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

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

time_t getNTPTime() {
  sendNTPpacket(timeServer); // send a NTP packet to the time server

  // wait for a reply for UDP_TIMEOUT miliseconds
  unsigned long startMs = millis();
  while (!Udp.available() && (millis() - startMs) < UDP_TIMEOUT) {}

  Serial.println(Udp.parsePacket());
  if (Udp.parsePacket()) {
    Serial.println("packet received");
    // We've received a packet, read the data from it and put it into the buffer
    Udp.read(packetBuffer, NTP_PACKET_SIZE);

    // the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, extract the two words:
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long ntp_timestamp = highWord << 16 | lowWord;

    return ntp_timestamp - 2208988800UL + timeZone * SECS_PER_HOUR;
  }
  return 0; // Failed to get time or parse the packet
}

void sendNTPpacket(char *ntpSrv)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);

  // Initialize values needed to form NTP request
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now send a packet requesting the timestamp:
  Udp.beginPacket(ntpSrv, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

void createElements(const char *str)
{
  sscanf(str, "%d-%d-%d %d:%d:%d", &Year, &Month, &Day, &Hour, &Minute, &Second);
  tm.Year = CalendarYrToTm(Year);
  tm.Month = Month;
  tm.Day = Day;
  tm.Hour = Hour;
  tm.Minute = Minute;
  tm.Second = Second;
}```

### Errors or Incorrect Output

If you see any errors or incorrect output, please show it here.  Please use copy & paste to give an exact copy of the message.  Details matter, so please show (not merely describe) the actual message or error exactly as it appears.

NTP time is 1546258674
Get: 2018-6-117 12:17:54
Want: 2018-12-31 12:17:54
kmio42 commented 4 years ago

I also had problems with day and month. In my case it seems, that the compiler somehow optimize out the const array monthDays in Time.cpp An access to array returns always 0. After adding the attribute volatile to this array, output was correct. (tested for Date: 2019-8-1) I have no clue, why this has happen - maybe dependent on compiler?

untillnesss commented 1 year ago

kmio42

Hi, your suggestion worked, but is it safe to use as usual?