Setting DS3231 from GPS

First of all, my apologies for posting this despite various existing attempts.

I realized that most of the methods already conceived, prioritize precision control of time synchronization, and that certainly has it's appeal. But the way they work are above my understanding, and I admit that outright. I was looking at the sample code of RTCLib and stumbeled upon this line:

rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));

What if, we pass data to the DateTime function in the format it expects. Would it synchronize the time? Accuracy isn't important to me. The GPS can simply be used to set the DS3231 in case the RTC is reset or the battery runs flat. So, with whatever I know, I attempted to do that (and I can see the seasoned veterans cringing at the very act). It didn't work. Here's the code:

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

RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
bool syncOnce = true;

SoftwareSerial SerialGPS = SoftwareSerial(4, 3);
TinyGPSPlus tinyGPS;
const int offset = 19800;  //  hours (in seconds)
time_t prevDisplay = 0;
void setup() {
  Serial.begin(9600);
  while (!Serial)
    ;
  SerialGPS.begin(9600);
  rtc.begin();
}

void loop() {

  while (SerialGPS.available())
    tinyGPS.encode(SerialGPS.read());  // Send it to the encode function
  // tinyGPS.encode(char) continues to "load" the tinGPS object with new
  // data coming in from the GPS module. As full NMEA strings begin to come in
  // the tinyGPS library will be able to start parsing them for pertinent info
  int Year = tinyGPS.date.year();
  int Month = tinyGPS.date.month();
  int Day = tinyGPS.date.day();
  int Hour = tinyGPS.time.hour();
  int Minute = tinyGPS.time.minute();
  int Second = tinyGPS.time.second();
  setTime(Hour, Minute, Second, Day, Month, Year);
  adjustTime(offset);
  if (timeStatus() != timeNotSet) {
    if (now() != prevDisplay) {  //update the display only if the time has changed
      prevDisplay = now();
      //GPSprintformat();
      sync();
      rtcPrint();
    }
  }
}

void GPSprintformat() {
  char buf[40];
  sprintf(buf, "%4d,%2d,%2d %2d,%2d,%2d", year(), month(), day(), hour(), minute(), second());
  Serial.println(buf);
}
void rtcPrint() {
  DateTime now = rtc.now();

  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(' ');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();
}

void sync() {
  if (syncOnce) {
  String TIMES = String(year()) + "," + String(month()) + "," + String(day()) + "," + String(hour()) + "," + String(minute()) + "," + String(second());
  const char *STRINGS = TIMES.c_str();
  rtc.adjust(DateTime(*STRINGS));
  syncOnce = false;
  }
}

The output is a random time value like "2106/2/6 6:29:5".

Please let me know your thoughts.

Not sure what You try to tell. Why use an RTC if You get that data from the GPS?

One way could be collecting Date/Time from the GPS at the start up of the controller and set the RTC.

It tells nothing useful.

When you are not experienced enough, look at the examples provided with each library.
Is GPS used for anything else, is WiFi available?

Backup, and also to save power as this will be run off solar energy. The GPS will be fired if RTC time is lost and also, there's no need to set time manually or through programming.

That's why the question. The "Serial.print(*STRINGS); command prints exactly in the same format the library expects the time to be set:

rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));

So, the idea was:

rtc.adjust(DateTime(*STRINGS)); 

should be able to set the time. But it doesn't. I do not know why, hence asking the experts here as this will be a simple way of integrating GPS and RTC together.

Always post all the code along with any error messages or results. Snippets are not useful.
Also identify the exact model Arduino board you are using.

You should avoid using String objects with Arduino. They cause crashes or undefined behavior due to poor memory management, and are never necessary.

This is the best approach for creating a C-string (zero terminated character array) that can be used to set the RTC, but fix the formatting to include the required commas:

  char buf[40];
  sprintf(buf, "%4d,%2d,%2d %2d,%2d,%2d", year(), month(), day(), hour(), minute(), second());
  Serial.println(buf);

I have a handful of the DS3231. I set the time in the house, and it runs for close to 8 years with incredible accuracy. I use the internet NTP time service to set the time; it's a couple of wires and takes 2 minutes. I never touch it again for 5 years. When I connect a couple of wires and replace the battery (maybe 3 years early), I can make a time adjustment at that time, but I almost never need to.

Remove the "*". In this context it dereferences the pointer and returns the single character pointed to by STRINGS.

Any errors after compilarion ?

How will You detect that? Don’t fight unknown ghosts like that. Be the conductor and prevent “the unknown”, make it not happen.

Thanks for this valuable suggestion! Finally got this to working! Upon further observation it was seen that although the RTCLib example code does not explicitly indicate a leading zero in the date format, it does lead to arbitrary values when the date is set. So, I added a rudimentary way to add leading zeros. I'm sure it could be done more craftily, but this works too. To check if the RTC has lost time, the following code is already in the example sketch:

 if (rtc.lostPower())

or the following if there's an RTC failure:

 if (! rtc.begin())

Here's the working sketch:

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

RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
bool syncOnce = true;
const char TIMESTRING;

SoftwareSerial SerialGPS = SoftwareSerial(4, 3);
TinyGPSPlus tinyGPS;
const int offset = 19800;  //  hours (in seconds)
time_t prevDisplay = 0;
void setup() {
  Serial.begin(9600);
  while (!Serial)
    ;
  SerialGPS.begin(9600);
  rtc.begin();
}

void loop() {

  while (SerialGPS.available())
    tinyGPS.encode(SerialGPS.read());  // Send it to the encode function
  // tinyGPS.encode(char) continues to "load" the tinGPS object with new
  // data coming in from the GPS module. As full NMEA strings begin to come in
  // the tinyGPS library will be able to start parsing them for pertinent info
  int Year = tinyGPS.date.year();
  int Month = tinyGPS.date.month();
  int Day = tinyGPS.date.day();
  int Hour = tinyGPS.time.hour();
  int Minute = tinyGPS.time.minute();
  int Second = tinyGPS.time.second();
  setTime(Hour, Minute, Second, Day, Month, Year);
  adjustTime(offset);
  if (timeStatus() != timeNotSet) {
    if (now() != prevDisplay) {  //update the display only if the time has changed
      prevDisplay = now();
      //GPSprintformat();
      if (tinyGPS.time.isValid()) {
        sync();
      }
      rtcPrint();
    }
  }
}

void GPSprintformat() {
  char buf[40];
  sprintf(buf, "%4d,%2d,%2d %2d,%2d,%2d", year(), month(), day(), hour(), minute(), second());
  Serial.println(buf);
}

void rtcPrint() {
  DateTime now = rtc.now();

  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(' ');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();
}

void sync() {
  if (syncOnce) {
    String Months, Days, Hours, Minutes, Seconds;

    if (month() < 10) {
      Months = ("0" + String(month()));
    } else Months = String(month());
    if (day() < 10) {
      Days = ("0" + String(day()));
    } else Days = String(day());

    if (hour() < 10) {
      Hours = ("0" + String(hour()));
    } else Hours = String(hour());

    if (minute() < 10) {
      Minutes = ("0" + String(minute()));
    } else Minutes = String(minute());

    if (second() < 10) {
      Seconds = ("0" + String(second()));
    } else Seconds = String(second());


    String TIMES = String(year()) + "," + String(Months) + "," + String(Days) + "," + String(Hours) + "," + String(Minutes) + "," + String(Seconds);
    const char *TIMESTRING = TIMES.c_str();
    Serial.println(TIMESTRING);
    rtc.adjust(DateTime(TIMESTRING));
    syncOnce = false;
  }
}

Edit:
As suggested by jRemington,

the sync process can be done with more arduino friendly sprintf function (again 0 padding is important at least for RTCLib.

    char timeBuffer[40];
    sprintf(timeBuffer, "%4d,%02d,%02d %02d,%02d,%02d", year(), month(), day(), hour(), minute(), second());
    Serial.println(timeBuffer);
    rtc.adjust(DateTime(timeBuffer));

A boring comment I would agree, but do be aware that the time a GPS reports can be out by 2 or maybe 3 seconds ………

Yes, and it is certainly important for time critical synchronization functions, however this is just for timekeeping for humans, and inclusion of GPS implies ease of use, independence from internet.