Problem with time Library

Hello

Current time of post at my location 21:31:xx

Im using the following function with the time library. Its reads out the time of the rtc and sets the arduino clock.

void setTimeFromRTC() {

  //This function reads the current time in UTC saved in the RTC Module and sets the arduino time.

  //collect data
  Wire.beginTransmission(RTC_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(RTC_ADDRESS, 6);
  byte rtcSeconds = BcdToDec(Wire.read());
  byte rtcMinutes = BcdToDec(Wire.read());
  byte rtcHours = BcdToDec(Wire.read());
  int rtcYear = BcdToDec(Wire.read());
  byte rtcDay = BcdToDec(Wire.read());
  byte rtcMonth = BcdToDec(Wire.read());

  //set arduino time
  setTime(rtcHours, rtcMinutes, rtcSeconds, rtcDay, rtcMonth, rtcYear);
  //calculate TIMEZONE and possible DST for selected values and a just time (in seconds)
  int adjustValue = DST_calculation(rtcDay, rtcMonth) + TMZ_calculation();
  adjustTime(adjustValue * SECS_PER_HOUR);

 
}

Time is saved in UTC, and i live in UTC+1, so rtcHours is 20 at the moment, and ajust time is 1*3600.
I have validated this, by adding a Serial print in the function, that will print out rtcHours and ajust. It was constantly 20 and 1, so no change in the rtc it self!

The second function is:

void timeService() {



  bool updated = false;
  bool needsCycle = false;
  byte AMPM_value = 0;


  if (oldTimeStamp != now()) {
    oldTimeStamp = now();
    updated = 1;

    if (needsTS == true) {
            DEBUG_PORT.print("need: ");
      DEBUG_PORT.println(needsTS);
      if (exTSvalid == true) {
        exTimeSyncSet();
        setTimeFromRTC();
      }
      else {
        setTimeFromRTC();
      }
      needsTS = false;

    }

if (oldMinute != minute()) {
      needsTS = true;
      byte oldMTT = oldMinute / 10;
      byte currentMTT = minute() / 10;

      if (cycletime == 1 && oldMTT != currentMTT) {
        needsCycle = true;
      }

      if (cycletime == 2) {
        needsCycle = true;
      }
      oldMinute = minute();
      
    }
    if( oldHour != hour()){
      
    if (cycletime == 3 ) {
      needsCycle = true;
    }
    
      oldHour = hour();
    }


    if (isAmPmMode == 2) {
      AMPM_value = 12;
    }
  }



  if (needsCycle == true && display_time_true == 1) {
    cycleHandler();
  }


  if (updated == 1 && display_time_true == 1) {



    bulbHandler();

     DEBUG_PORT.print("ST: ");
      DEBUG_PORT.print(now());
    DEBUG_PORT.print(" H: ");
    DEBUG_PORT.print(hour());
    DEBUG_PORT.print(" M: ");   
    DEBUG_PORT.print(minute());
    DEBUG_PORT.print(" S: ");
    DEBUG_PORT.println(second());     
    formatOutput(hour() - AMPM_value, minute(), second(), bulbOne, bulbTwo);
    setOutputs(register_output_1, register_output_2);

  }

}

Every minute, the clock will snychronize to a GPS reciever. To validate whats happening, i added serial output.

The Problem i have can be seen in the Serial log:
Ignore the cordinates, they're fake.

ST: 948230999 H: 21 M: 29 S: 59
ST: 948231000 H: 21 M: 30 S: 0
need: 1
GPS-:
2017-01-18 20:30:022000-01-01 00:00:10
407411110
-739897220
GPS-END
ST: 948231001 H: 20 M: 30 S: 1
ST: 948231002 H: 21 M: 30 S: 2

at 21:29:59 the time is normal, then the gps kicks in, sending 20:30:02 (UTC)
after that, the hour() weirdly becomes 20 for one second!, as you can see, the timestamp is the same in the hours section, only the second changed.

Any ideas why this is happening?

Please indent the code of your second function properly - can't see what is getting closed where and post full code in one go.

Every minute, the clock will snychronize to a GPS reciever.

The "clock" being the RTC? Or, the Arduino?

Why would an RTC need to sync with the GPS once a minute? If the RTC is that inaccurate, throw it away. The Arduino can keep reasonable time, especially if it is syncing with a reliable source once in a while (once a minute is far more often than needed).

I do not see any code that gets time from a GPS.

PaulS:
The "clock" being the RTC? Or, the Arduino?

The procedure works like this:

1.Arduino Powerup
2.Set time of time libray from the RTC Module
3.Update the "Arduino Time" from the RTC Module each minute
4.If there is a GPS fix there, compare if the RTC-Time differs from the GPS fix, if yes, update the RTC Module.
5.The GPS can't be linked directly to the "Arduino Time" since there cant be a guarentee that there will be a gps installed.

To verify if the GPS even updates the RTC, i installed a debug. The GPS does not influence the time of the RTC in most of my cases, so i don't think the bug is created by the GPS....

If the gps updates the rtc, there would be a print on serial with "UPDATED RTC", which in my case is not present

see an example with updated code, rtc is not updated, but the bug still occurs

ST: 979928699 H: 18 M: 24 S: 59
ST: 979928700 H: 18 M: 25 S: 0
need: 1
2017-01-19 17:25:012000-01-01 00:00:10
407411110
-739897220
ST: 979928701 H: 17 M: 25 S: 1
ST: 979928702 H: 18 M: 25 S: 2
ST: 979928703 H: 18 M: 25 S: 3

Here i added the GPS related code:

Time Setting from GPS (with comparation)

void  exTimeSyncSet() {

  DEBUG_PORT << fix.dateTime << '\n'; // Raw date in "YYYY-MM-DD HH:MM:SS" format
  DEBUG_PORT.println();
  DEBUG_PORT.println(fix.latitudeL());
  DEBUG_PORT.println(fix.longitudeL());

  if (gpsTime > earliestTime) {

    int exYear   = fix.dateTime.full_year();
    int exMonth  = fix.dateTime.month;
    int exDay    = fix.dateTime.date;
    int exHour   = fix.dateTime.hours;
    int exMinute = fix.dateTime.minutes;
    int exSecond = fix.dateTime.seconds;

    if ((second() > exSecond + 2) || (second() < exSecond - 2)) {
      DEBUG_PORT.print("UPDATED RTC!");
      RTCsetTime(exSecond, exMinute, exHour, 0, exDay, exMonth, exYear);
    }
  }
  needsTS = 0;
}

To find out if there is a valid fix:

void exTimeSyncTest() {

  while (gps.available() > 0) {
    fix = gps.read();

    //  Make sure it has been long enough since a reset,
    //      that GPS syncing is enabled, and
    //         that the GPS fix has valid date and time fields.
    if ((millis() > 20000) && (enTimeSync == 1) && fix.valid.date && fix.valid.time) {
      gpsTime = fix.dateTime;

      exTSvalid = true;
    }
    else {
      exTSvalid = false;
    }

  }
}

I think you have two choices:

  1. Take your code to http://snippets-r-us.com
  2. Post ALL of your code.

You need to be very careful when using adjustTime() - My recommendation is don't use it.
I have written about this a few times in the past, but basically, it is not intended to be used as an offset for fudging timezones. Attempting to do so will result in some strange behaviors.
There are issues in the code when it is used that way.
I can't remember what they were off the top of my head as it has been a while, but I believe most of the issues could be resolved to work the way people assumed adjustTime() should work if the code were slightly tweaked.

Since the Time library does not support timezone offsets, the best thing is either run the arduino time at UTC and do an offset on the time_t value just before your print the local time values, (this is what the TimeZone library does) or actually alter the time that arduino tracks such that it no longer represents the proper UTC time and track time incorrectly which allows you to produce the proper local time values from using the time_t value directly.
If you want to do the latter and corrupt the time that Arduino tracks by actually altering the time_t to represent a local time time_t value (which it looks like what you seem to be wanting), you shouldn't use adjustTime() to set/modify/adjust the time, you should be using setTime(time_t) to set the actual time_t to the desired modified/corrupted localtime time_t value.

Just keep in mind that by modifying the actual time_t value tracked by the Arduino you are modifying/corrupting the actual time rather than simply adjusting it to the local time when needed for human consumption. This will mean that the time_t values from the Arduino will no longer be correct since they are no longer based on the same epoch. If this is just for a simple clock display, that can work, but if you are needing actual timestamps, it won't work.

--- bill

Thank you for the information bperrybap!

My application is just display the time.
But i have to store the time in UTC, since the GPS always sends UTC, and the time-zone can be configured so "changing the arduino time" would result in additions and subratctions that can be really complex.

Just add or subtract hours to my own variables is no option, since it could be mess up date.

I read it should be possible to set the time by a timestamp, not by declaring hours.

So i could convert my rtc values to a timestamp and then add or subtract time in seconds.

Maybe this works? I will try it.

I have changed my function, and i have not seen the bug since then. Hopefully it works now :slight_smile:

Thanks!

void setTimeFromRTC() {

  //This function reads the current time in UTC saved in the RTC Module and sets the arduino time.

  //collect data
  Wire.beginTransmission(RTC_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(RTC_ADDRESS, 6);
  byte rtcSeconds = BcdToDec(Wire.read());
  byte rtcMinutes = BcdToDec(Wire.read());
  byte rtcHours = BcdToDec(Wire.read());
  int rtcYear = BcdToDec(Wire.read());
  byte rtcDay = BcdToDec(Wire.read());
  byte rtcMonth = BcdToDec(Wire.read());

  //Fill tm elements 
  
  tm.Second=rtcSeconds;
  tm.Hour=rtcHours;
  tm.Minute=rtcMinutes;
  tm.Day=rtcDay;
  tm.Month=rtcMonth;
  tm.Year=(rtcYear-1970);

  //convert rtc time to timestamp
   uint32_t tempTime=makeTime(tm);

  //calculate adjustment
  long adjustValue =(DST_calculation(rtcDay, rtcMonth) + TMZ_calculation())*3600;
   
  //set arduino time
  setTime(tempTime+adjustValue);

}

Just keep in mind that you are modifying the actual time being tracked by the Arduino,
So any time_t value you get from the Time library will not match the REAL time_t which is based on UTC since the time being tracked by the Time library inside the Arduino has been shifted to an alternate epoch based on the local time offset from UTC.

This is fine for clocks that only need to display a local time, but not for timestamps for things like logging.

--- bill