GPS NEO6M Time is Correct but Date Is Wrong

Hello Again All,

I thought I was home free with this project but I guess not. I built a GPS tracking device which works great! It uses SMS to send GPS data to a user who sends an SMS to the unit with a specific line (GETLOC) then the unit responds with GPS data. However, I started adding information to the SMS and everything is working fine except for the date. I managed to get the timezone adjusted correctly but the date is still a date ahead. Please look through my code and help me. I checked the data and it's all good, no errors and the stream is steady. I added a screenshot of the general idea. The correct date should be 4/10/2024. Once I get this resolved I can move onto daylight savings time (oh joy.) Thanks in advance.

PHOTO OF TEXT MESSAGE

CODE

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
SoftwareSerial GSM(11, 10);
SoftwareSerial neo(8, 9);
String textMessage;
String lampState;
String lati = "";
String longi = "";
String speed = "";
String direction = "";
String rawmonth = "";
String rawday = "";
String rawyear = "";
String rawhour = "";
String rawminute = "";
String rawsecond = "";
String weekday = "";
String num_sat = "";
String elevation = "";
#define redLed    3
#define greenLed  5
#define blueLed   6
const int relay = 12;
TinyGPSPlus gps;
const int timezone_hours = -4;
const int timezone_minutes = 0;

void setup() {

  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  pinMode(blueLed, OUTPUT);
  pinMode(relay, OUTPUT);
  digitalWrite(redLed, HIGH);
  delay(200);
  digitalWrite(redLed, LOW);
  digitalWrite(greenLed, HIGH);
  delay(200);
  digitalWrite(greenLed, LOW);
  digitalWrite(blueLed, HIGH);
  delay(200);
  digitalWrite(blueLed, LOW);
  digitalWrite(relay, HIGH);
  Serial.begin(115200);
  GSM.begin(9600);
  neo.begin(9600);
  GSM.listen();
  delay(5000);
  digitalWrite(greenLed, HIGH);
  Serial.print("GSM ready...\r\n");
  GSM.print("AT+CMGF=1\r\n");
  delay(1000);
  GSM.print("AT+CNMI=2,2,0,0,0\r\n");
  delay(1000);
  digitalWrite(greenLed, LOW);

}


void loop() {
  GSM.listen();
  delay(2);
  while (GSM.available() > 0) {
    digitalWrite(blueLed, HIGH);
    textMessage = GSM.readString();
    Serial.print(textMessage);
    delay(10);
    digitalWrite(blueLed, LOW);
  }
  neo.listen();
  if (textMessage.indexOf("ON") >= 0) {
    String array_string[20];
    string_splitting(textMessage,array_string,'\"');
    String NUMBER = array_string[1];
    digitalWrite(relay, LOW);
    lampState = "ON";
    Serial.println("Bike set to ON\r\n");
    textMessage = "";
    GSM.println("AT+CMGS=\"" + NUMBER + "\"\r");
    delay(500);
    GSM.print("Bike set to ON\r");
    GSM.write(0x1a);
    delay(1000);
    GSM.println("AT+CMGD=1,4");
  }
  if (textMessage.indexOf("OFF") >= 0) {
    String array_string[20];
    string_splitting(textMessage,array_string,'\"'); 
    String NUMBER = array_string[1]; 
    digitalWrite(relay, HIGH);
    lampState = "OFF";
    Serial.println("Bike set to OFF\r\n");
    textMessage = "";
    GSM.println("AT+CMGS=\"" + NUMBER + "\"\r");
    delay(500);
    GSM.print("Bike set to OFF\r");
    GSM.write(0x1a);
    delay(1000);
    GSM.println("AT+CMGD=1,4");
  }
    
  if (textMessage.indexOf("GETLOC") >= 0) {
    Serial.println("_____________________________________");
    smartDelay(1000);
    String array_string[20];
    string_splitting(textMessage,array_string,'\"'); // 
    String NUMBER = array_string[1];  
    Serial.println("GPS data Recived\r\n");
    textMessage = "";
    Serial.print("Speed: ");
    Serial.print(gps.speed.mph());
    Serial.println(" Miles Per Hour");
    Serial.print("Number of Sattelites: ");
    Serial.println(num_sat);
    Serial.print("Raw course in degrees = "); 
    Serial.println(gps.course.value());
    Serial.print("Elevation: ");
    Serial.println(elevation);
    Serial.println("_____________________________________");
    GSM.println("AT+CMGS=\"" + NUMBER + "\"\r");
    delay(500);
    String pesan = "https://maps.google.com/?q=" + lati + "," + longi;
    rawmonth = gps.date.month();
    rawday = gps.date.day();
    rawyear = gps.date.year();
    rawhour = gps.time.hour();
    rawminute = gps.time.minute();
    rawsecond = gps.time.second();
    speed = gps.speed.mph();
    direction = gps.course.deg();
    num_sat = gps.satellites.value();
    elevation = gps.altitude.feet();
    GSM.print("Date ");
    GSM.print(rawmonth);
    GSM.print("/");
    GSM.print(rawday);
    GSM.print("/");
    GSM.println(rawyear);
    GSM.print("Time ");
    Get_GPS();
    GSM.print(rawhour);
    GSM.print(":");
    GSM.print(rawminute);
    GSM.print(":");
    GSM.println(rawsecond);
    GSM.print("Speed ");
    GSM.print(speed);
    GSM.println(" MPH");
    GSM.print("Direction ");
    GSM.println(direction);
    GSM.print("Number of Sattelites ");
    GSM.println(num_sat);
    GSM.print("Elevation ");
    GSM.print(elevation);
    GSM.println(" Feet ASL");
    GSM.print(pesan);
    GSM.write(0x1a);
    delay(1000);
    GSM.println("AT+CMGD=1,4");
  }
}
static void smartDelay(unsigned long ms) {
  unsigned long start = millis();
  do {
    neo.listen();
    delay(2);
    while (neo.available())
      gps.encode(neo.read());
  } while (millis() - start < ms);
  lati = String(gps.location.lat(), 8);
  longi = String(gps.location.lng(), 6);
  Serial.println(lati);
  Serial.println(longi);
}

void string_splitting(String splitMsg, String bb[], char delimiter) {
  int counter = 0 ;
  for ( int i = 0 ; i < splitMsg.length() ; i ++ ) {
    if ( splitMsg.charAt(i) == delimiter ) {
      counter++;
    }
    else {
      bb[counter] +=  splitMsg.charAt(i) ;
    }
  }
}

void Get_GPS(){

  if (gps.time.isValid()){
    int hour = gps.time.hour();
    int minute = gps.time.minute();
    rawsecond = gps.time.second();

    abc(hour, minute);
    
    rawhour   = String(hour);
    rawminute = String(minute);
    rawhour = (rawhour.length() == 1) ? "0"+rawhour : rawhour;
    rawminute = (rawminute.length() == 1) ? "0"+rawminute : rawminute;
  }
}

void abc(int &rawhour, int &rawminute){
    Serial.println("UTC =  "+String(rawhour)+":"+String(rawminute)+":"+String(rawsecond));
    rawminute = rawminute + timezone_minutes;
    if(rawminute >= 60){
      rawminute = rawminute - 60;
      rawhour = rawhour + 1;
    }
    if(rawminute < 0){
      rawminute = rawminute + 60;
      rawhour = rawhour - 1;
    }
    rawhour = rawhour + timezone_hours;
    if(rawhour >= 24){
      rawhour = rawhour - 24;
    }
    else if(rawhour < 0){
      rawhour = rawhour + 24;
    }

    Serial.println("Time=  "+String(rawhour)+":"+String(rawminute)+":"+String(rawsecond));
}

If your 4G mormon (Oops, MODEM) is on all the time, use the +CCLK sentence to get the cellular time rather than the GPS time..

GPS time is UTC, and has to be adjusted for timezone, DST etc.
Cellular time is localised to the cell, corrected automatically for the modem / cell location.

Use the Arduino time library <TimeLib.h> to adjust time zones. It correctly handles the date change, starting with a Unix timestamp.

Unless you are using an ESP32, and possibly even then, all those String objects will bring a lot of grief.

Example of time/date adjustment:

//time_make_and_add
#include <TimeLib.h>

tmElements_t te;  //Time elements structure
time_t unixTime; // a time stamp

void setup() {
  Serial.begin(115200);
   // new internal clock setting.
  // convert a date and time into unix time, offset 1970
  te.Second = 0;
  te.Hour = 23; //11 pm
  te.Minute = 0;
  te.Day = 1;
  te.Month = 1;
  te.Year = 2017-1970; //Y2K, in seconds = 946684800UL
  unixTime =  makeTime(te);
  Serial.print("Example 1/1/2017 23:00 unixTime = ");
  Serial.println(unixTime);
  setTime(unixTime); //set the current time to the above entered
  Serial.print("now() = ");
  Serial.println(now());
  // print as date_time
  print_date_time();
  // add
  unixTime += 7200UL; //add 2 hours
  setTime(unixTime);
  Serial.println("After adding 2 hours");
  Serial.print("now() = ");
  Serial.println(now());
  print_date_time();
}
void print_date_time() { //easy way to print date and time
  char buf[40];
  sprintf(buf, "%02d/%02d/%4d %02d:%02d:%02d", day(), month(), year(), hour(), minute(), second());
  Serial.println(buf);
}

void loop() {}

Thanks for the quick response. Going to work on it now.

That sentence is unintelligible.

You remembered that minutes carry into hours, but forgot that hours carry into days. That is why your date is wrong.

What did you get returned with +CCLK ?
Which part didn’t make sense ?

When calling AT+CCLK? with AT+CTZU=1, the time zone is attached (format:+CCLK: "18/11/11,00:51:07-24).

The unintelligible sentence I was referring to was the one you typed, with the "4G mormon" and the "tomgetntyevcelluoar".

Yep, sorry, corrected now
,
No nerves in my hands leads to mistyping sometimes !

I thought this part covered that?

So if I'm using the Arduino time library, what is the syntax to print the date & time to the text message? I tried the following

GSM.print(now);
GSM.print(print_date_time));

none of that worked.

Of course not. It won't even compile without fatal errors.

There are rules in the programming language. You can't just make stuff up and expect it to run.

1 Like

Well I'm here for help, so can you help? What would the syntax be?

A good place to start is to run the very simple example code I posted above, and work on understanding what it does, and why. Every single line of code has an important purpose.

For example, what do you suppose the following two lines of code do, and what is the result of the operation?

Why is there an empty pair of parentheses following the word "now"?

What is the actual meaning of the numeric value that is printed?

  Serial.print("now() = ");
  Serial.println(now());
1 Like

I did that and it printed a number that didn't make any sense. By the way thanks for the help, I truly appreciate it. At least if I could have gotten it to show the date & time I could have built the rest from there. I really want to use this method but I'm having trouble abandoning the other method only because it seems like most of the work is done (headache :laughing:))

So here's the output I got when I tried to run GSM.print(now());

I'm not sure if that's actually a date and time that just needs to be formatted, or is it just a randomly assigned number.

Side note, I copied your code exactly as it was.

It makes perfect sense, if you will take a moment to look up the definition of Unix timestamp.

Unix time is the key to understanding how the program works. Unix times are used the world over by computers to synchronize operations and record keeping, a fundamental concept central to the inner workings of the internet.

The number represents the seconds elapsed since a particular epoch in time, similar to how millis() keeps track of time since an Arduino has started running.

1 Like

That takes care of the hours if the hours go into the hext day. It does not take care of the day if the hours go into the next day.

Did you write this code, or just copy it from somewhere without understanding how it works?

Both, I copied it from another user but tailored it to my needs. I came up with this and it compiled okay but is it correct?

if(rawhour < 0){
      rawhour = rawhour + 24;
      rawday = rawday + 1;
    }

This is the kind of mess you end up with when you try that sort of thing. As you can see, it doesn't meet your needs.

You are correct, thats why i came here for help. If this forum isn't here for people to get help from then pmease tell me the purpose behind it. I mean this is how people learn, correct? If everybody knows everything, and people who dont know anything should stay away, then the forum should be eliminated, correct?

Im sorry to have bothered you and I hipe you have a wo deeful day. Thanks for all your help so far.