Time and date from GPS

I have a question on how to dea/thinkl when dealing with time and date with regards to GPS applications. Below is a simple program I put together that displays the exact time and date every 5 seconds using the TinyGPS++ library. It works fine from what I can tell.

My question is do I need this if-statement:

if (gps.date.isValid())

What would/could happen if I don't use it? I think the interesting thing happens with times around midnight. Could there be a situations where I get the exact time and the date is not valid as it was from previous day, and thus not displayed? If anyone could help understand this that would be great. Thank you!

#include "TinyGPS++.h"
#include "SoftwareSerial.h"

SoftwareSerial serial_connection(10, 11); //TX=pin 10, RX=pin 11
TinyGPSPlus gps;//This is the GPS object that will pretty much do all the grunt work with the NMEA data

void setup()
{
  Serial.begin(9600);//This opens up communications to the Serial monitor in the Arduino IDE
  serial_connection.begin(9600);//This opens up communications to the GPS
}

void loop()
{
  while(serial_connection.available())//While there are characters to come from the GPS
  {
    gps.encode(serial_connection.read());//This feeds the serial NMEA data into the library one char at a time
  }
  
  if(gps.time.isUpdated()) 
  {
    Serial.println("Time has been updated");
    Serial.print("Satellites: ");
    Serial.println(gps.satellites.value());
    Serial.print("Time now [GMT]:  ");
    Serial.print(gps.time.hour());
    Serial.print(":");
    Serial.print(gps.time.minute());
    Serial.print(":");
    Serial.print(gps.time.second());

    if (gps.date.isValid())
    {
      Serial.print("  Date:  ");
      Serial.print(gps.date.year());
      Serial.print("/");
      Serial.print(gps.date.month());
      Serial.print("/");
      Serial.println(gps.date.day());
    }
    delay(5000); // This delay gives us exact time every 5s seconds
  }
}

What would/could happen if I don't use it?

A wild guess. The GPS data may not be valid

Why would you want to use invalid data ?

Yea I can give you a pretty precise answer to that, since I was at the same spot as you. As bob already said, you might get Data, before “valid” is true. But, there is no guarantee, that this data is correct and/or full. A very common thing happened to me was, getting time while Lat/Long was still loading. Also you sometimes nearly correct coordinates and connectedSatelites were still 0. Just non-viable Data or no data at all.

I for myself hoped for “faster” usage of product, since GPS Module can take up to 15 Minutes (in most extreme cases) until he establised a proper connection. The result was not satisfying. Therefore: Like Bob already said: I can’t imagine any use case for not waiting for valid data, though. Would you like to give more Information, maybe?

Edit:
I even doublecheck my GPS Data, since it is possible, that your GPS Data is “valid” but you have less than 3 satelites and therefore you get not proper positions.

    if (gps.encode(Serial1.read())) {
      valid = gps.location.isValid();
      foundSatellites = gps.satellites.value();
      ...
    }

    int isGpsSignalValid() {
      if (valid == 1 && foundSatellites < 3) {
        valid = 0;
      }
      return valid;
    }

Good points. Yes, let me explain more. I understand that you have to “feed” the data non-stop to the class. But if time is updated, wouldn’t date be too? To me they are linked. That is what I am trying to better understand.

What I want is this: a command that gives me time AND date at all times. It seems to me that there is a tiny battery (and clock I would assume) on my module (Neo6m) and that it gives me time and date even if no satellites are available yet (before it has had time to lock to them).

Also, does anyone know if there are issues with having to check the GPS module non-stop AND checking a 433MHz receiver non-stop in the same loop? In my case, I don’t want to miss a single 433MHz signal (very in-frequent messages) so I don’t know if the constant checking of the GPS module is going to cause problem in that respect. Why check both? I want to have an accurate time-stamp when I receive my 433MHz signal. That is the core of my application. I do have an RTC module in there now. It works but the time is off by 1-2 seconds per week or so, which is within spec. With the GPS I was hoping to get accurate time stamps all the time. :slight_smile:

Thanks again!

Or, rather than asking the GPS module what the time and date is directly, should I use the GPS time/date info to update the system clock on a regular basis and then get time and date from the system clock when needed? Would that be a better approach? Thanks again!

Wait, you are using the GPS Module only for time? There are dedicated modules dir arduino, which keeps track of time. Name is RealTimeClock ds3231.

Dont Understand the Part with 433mhz part. GPS Module (i own) sends Data roughly once a second. So there ist that. If you require millisecond precise calculations, I suggest you to Check for rtc Modules or self calculations via GPS Date time + millis()

PS: now I Understand with you already having an rtc. And why you use GPS.

I See No Problem in Reading 433 MHz Signal ans GPS at the Same Loop, as Long as your Loop between two GPS readings dont Take longer than roughly 1 second.

Did you tried to Set init timestamp and then using millis()? This should bei totally fine. Please consider: millis() overflows after roughly 50 days

dr-o: I See No Problem in Reading 433 MHz Signal ans GPS at the Same Loop, as Long as your Loop between two GPS readings dont Take longer than roughly 1 second.

Did you tried to Set init timestamp and then using millis()? This should bei totally fine. Please consider: millis() overflows after roughly 50 days

Great! Yes, I use millis() quite often instead of delay() where I need non-stop monitoring of someting. The 50 day overflow is a non-issue for me as I never measure times that long and if you measure time difference it does not matter if it overflows between start and stop which is perfect for me. Thanks again!

Do remember that from a cold start, whilst a good GPS with a decent antenna with a good view of the sky will get a time and position lock within 40 seconds or so, that time can be 1 or 2 seconds out. It can take 12.5 minutes for the time to be the same as UTC, longer if its a poor GPS, has a poor antenna or is in a poor position.

This 1 or 2 second error might not be important, but it can be if your trying to sync seperate devices to the same second.

amaruk: Great! Yes, I use millis() quite often instead of delay() where I need non-stop monitoring of someting. The 50 day overflow is a non-issue for me as I never measure times that long and if you measure time difference it does not matter if it overflows between start and stop which is perfect for me. Thanks again!

This ist good, thus, i meant following: In the initialization Phase, save DateTime in a variable, pref from RTC Module but If you want to, Sure, Go ahead an read it from gps module. Also save millis(), where you saved DateTime in a seperate variable. (Millis() gives you milliseconds since arduino start) Then you can always get pretty precise Date time by

DateTimeVariable + millis() - millisAtInit()

There is some conversion Work to do though. Maybe this is a solution? And If you require perfect Timings, you should definitly Check for valid!

The 50 day overflow is a non-issue for me as I never measure times that long

Times that always start at boot time? Because, even a measurement of a few milliseconds can be affected by millis() rollover.

amaruk: Or, rather than asking the GPS module what the time and date is directly, should I use the GPS time/date info to update the system clock on a regular basis and then get time and date from the system clock when needed? Would that be a better approach? Thanks again!

What I did, is attach the PPS output from the GPS module, to an interrupt pin. The ISR recorded the millis() value at the time it is called, so at any given time, you just subtract millis() from that value, and you get a very accurate sub-seconds timer.

aarg:
Times that always start at boot time? Because, even a measurement of a few milliseconds can be affected by millis() rollover.

I am glad that you brought this up. I think this is a very common misconception in this forum. Been there done that myselff… I agree that it is very important to know that there will be an overflow after 50 days. However, the only implication of that is just that you can’t measure times that are longer than that as your timer will zero itself. But, and this is important, you can indeed measure times that are shorter than that at any time just fine, even if your timer overflows during the timing process. Just take two readings of the millis() timer and subtract them. Here is a simple C++ code to show what I mean. I have used an online C++ playground rather than Arduino for simplicity. While the max values etc are different, the principle is the same. Below the code I provided a link to the playground I used along with the output from the code. As you can see in my calculations, the overflow does not impact the result as we get what we would expect even if we did not know about the max/overflow value.

#include <iostream>
using namespace std;
 
   int main()
   {
   
      const unsigned int UINT_MAX = 4294967295;

      const unsigned int X1 = UINT_MAX - 2;
      const unsigned int X2 = UINT_MAX + 3;
      unsigned int X3 = X2 - X1;

  
      cout << "UINT_MAX = " << UINT_MAX << endl;
      cout << "UINT_MAX + 1 = "<< UINT_MAX+1 << endl;
      cout << "0 - UINT_MAX = "<< 0 - UINT_MAX << endl;
      cout << "X1 = UINT_MAX - 2 = " << X1 << endl;
      cout << "X2 = UINT_MAX + 3 = " << X2 << endl;
      cout << "X3 = X2 - X1 = " << X3 << endl;

    return 0;
    }

/* Output:

UINT_MAX = 4294967295
UINT_MAX + 1 = 0
0 - UINT_MAX = 1
X1 = UINT_MAX - 2 = 4294967293
X2 = UINT_MAX + 3 = 2
X3 = X2 - X1 = 5

// C++ playground: https://code.sololearn.com/c39N9RN6b4Md/#cpp
*/

Yes, also if you want to measure times longer than ~50 days, you can use millis() to just increment a counter. For example, a seconds counter will then count 50,000 days.

Thanks for all inputs!

An update for those of you who are interested:

I decided to use the GPS to set the system clock with a valid time and date and then read the time from the system clock when needed. I also have a boolean that tells me if the system clock has been set yet (global). That way I avoid reading time when the system clock has not yet been set. Here is simple demo example of what I am doing. In this example I display the time and date every time there is a new number of satellites tracked. I used this satellite counter to avoid filling the serial monitor too quickly during tests as it still shows the main principle of how I use the GPS and system clock together. I also use TimeLib.h to be able to easy adjust for the time zone. Thanks again!

#include "TinyGPS++.h"
#include "SoftwareSerial.h"
#include <TimeLib.h>

int satelliteCounter = 0;
int currentCount;
bool clockHasBeenSet = false;
const int OFFSET_HRS = -5; // (Negative number for moving time backwards (e.g. from GMT to ET)

SoftwareSerial serial_connection(10, 11); //TX=pin 10, RX=pin 11
TinyGPSPlus gps;//This is the GPS object that will pretty much do all the grunt work with the NMEA data

void setSystemClock()
{
  if (gps.time.isValid() && gps.date.isValid())
  {
      // setTime(hr,min,sec,day,mnth,yr);
      setTime(gps.time.hour(),gps.time.minute(),gps.time.second(),gps.date.day(),gps.date.month(),gps.date.year());
      adjustTime(SECS_PER_HOUR*OFFSET_HRS);
      clockHasBeenSet = true;
  }
}

String getTwoDigitString(const int& x) // 00-99
{
  if (x==0)
  {
    return "00";
  }
  if (x<10)
  {
    return "0" + String(x);
  }
  return String(x);
}

void displayTime()
{
  time_t t;
  t=now();
  Serial.print("Time [ET]: ");
  Serial.print(getTwoDigitString(hour(t)));
  Serial.print(":");
  Serial.print(getTwoDigitString(minute(t)));
  Serial.print(":");
  Serial.print(getTwoDigitString(second(t)));
  Serial.print("   Date: ");
  Serial.print(year(t));
  Serial.print("-");
  Serial.print(getTwoDigitString(month(t)));
  Serial.print("-");
  Serial.print(getTwoDigitString(day(t)));
  Serial.print("   (");
  Serial.print(dayStr(weekday(t)));
  Serial.print("/");
  Serial.print(dayShortStr(weekday(t)));
  Serial.print(",");
  Serial.print(monthStr(month(t)));
  Serial.print("/");
  Serial.print(monthShortStr(month(t)));
  Serial.println(")");
}

void setup()
{
  Serial.begin(9600);//This opens up communications to the Serial monitor in the Arduino IDE
  serial_connection.begin(9600);//This opens up communications to the GPS
  Serial.println("Starting...");
}

void loop()
{
  while(serial_connection.available())//While there are characters to come from the GPS
  {
    gps.encode(serial_connection.read());//This feeds the serial NMEA data into the library one char at a time
  }
  
  if(gps.time.isUpdated()) 
  {
    currentCount = gps.satellites.value();
    if (currentCount != satelliteCounter)
    {
      setSystemClock();
      if(clockHasBeenSet) // make sure time was updated before displaying anything
      {
        satelliteCounter = currentCount;
        Serial.print("Satellite count: ");
        Serial.print(satelliteCounter);
        Serial.print(", Timer: ");
        Serial.print(millis()/1000);
        Serial.print(" seconds. ");
        displayTime();  
      } // clock set end
    } // new count end
  } // time update end
}

amaruk: In this example I display the time and date every time there is a new number of satellites tracked.

Why did you adopt that approach ?

I dont see how the number of satellites in view has any relation to the date and time reported ?

srnet: I dont see how the number of satellites in view has any relation to the date and time reported ?

Yes, I guess I was not clear on that point. Let me try again... In my project I have a need to get the exact time and date at any point in time (RTC not good enough). It needs to be available at that time with no delays or other unknowns. If I were to depend on taking the time and date from the GPS directly, as this thread talks about, I will be at the mercy of the state of the class at that point in time and wether these parameters are valid etc. I don't want it to be that way. Instead, I update the system clock on a regular basis and when I need the time I take it from the system clock.That way I know I will get the exact time and I don't depend on the status of anything. Back to your question, why satellite count? Well no deep thoughts behind that. I just wanted an example without any delays (I can't have delays in my program as I am constantly listening for 433 MHz signals) and I thought that the number of satellites is a random event and will do in order to test my time/date handling between the system clock and the GPS.

amaruk: In my project I have a need to get the exact time and date at any point in time (RTC not good enough). It needs to be available at that time with no delays or other unknowns.

I dont see how what has been suggested so far will give you the 'exact time' at all.

Even if you have checked that the GPS is using the correct value of leap seconds, the time published in a NMEA sentence can be many mS out, internal delays in the GPS processing, time to print etc.

'exact time' is such a vague concept anyway, what differance between the Arduinos time and actual time is acceptable ?

That’s the value of the PPS pulse. You can capture the PPS edge every second and then associate it with a particular calendar/clock time later, when the serial data arrives. IIRC it can be accurate to about +/- 10us. It’s relatively easy to keep the CPU clock synchronized with that.

Good points. What is exact to me is not very accurate to others etc. In my project I started out with an RTC but I quickly noticed that it drifts with 1-2s per week. All within spec but I did not know that. Over a year it will add up to a few minutes. I wanted to do better so I set my eyes on GPS, simply because it gives time. Other alternatives that crossed my mind was NTP time servers or the radio controlled clock signal WWVB from Colorado (60 KHz). But I quickly decided that GPS was best for me. Why? I don't want want to user Internet for this and to get the 60KHz receiver working can be tricky from what I understand.

The suggestions here that helped me was the obvious, why would I use time/date that is not valid? I didn't fully understand the GPS class but I have a better understanding now. The time and date are updated at different times and as a result, the status of the two can be different. That causes a problem for me as I need both to be accurate at the same time. I don't need millisecond accuracy, but the drift of 1-2s per week is a bit much I think.

I don't need millisecond accuracy, but the drift of 1-2s per week is a bit much I think.

Would a "skew" of 1-2s in a shorter period of time be a problem for you? In other words, is it only long term accuracy that is important for your as of yet unexplained application?