RTC DS3231 reseting time

I need some help here, i’ve a project with a RTC DS3231. But everytime i set time, then shut down the power my rtc reset the time. Looks like it isn’t saving the time set by code.

#include <Servo.h> 
#include <DS3231.h>
DS3231  rtc(SDA, SCL);
Servo servo;
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,2,1,0,4,5,6,7,3, POSITIVE);
int estadoBotao = 0; 
int Chave=3; //Pino a ser ligado na chave esquerda
//int ChaveCentral=4;  //Pino a ser ligado na chave central
//int ChaveDireita=5;  //Pino a ser ligado na chave direita

void setup() 
{ 
  // Setup Serial connection
  Serial.begin(9600);
  // Initialize the rtc object
  rtc.begin();
  lcd.begin (16,2);
  //rtc.setDOW(MONDAY);     // Set Day-of-Week to SUNDAY
  //rtc.setTime(17, 58, 19);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(28, 12, 2016);   // Set the date to January 1st, 2014
  
  // Pino de dados do servo conectado ao pino 9 do Arduino
  servo.attach(9);   
  //Define o pino como entrada
  pinMode(Chave, INPUT);      
  //Aciona o resistor pull-up interno
  digitalWrite(Chave, HIGH);  
  //pinMode(ChaveCentral, INPUT);
  //digitalWrite(ChaveCentral, HIGH);
  //pinMode(ChaveDireita, INPUT);
  //digitalWrite(ChaveDireita, HIGH);
} 

void loop() 
{ 
 //Le o valor da Chave Esquerda (On/Off)
  estadoBotao=digitalRead(Chave);  
  //Caso a chave seja pressionada, movimenta o servo
  lcd.setBacklight(HIGH);
  lcd.setCursor(0,0);
  lcd.print(rtc.getTemp());
  lcd.print(" C");
  lcd.setCursor(0,1);
  lcd.print(rtc.getTimeStr());    

  //Blink   
  delay(3000);     
  lcd.display();   
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.clear();

  lcd.print("Data: "); 
  lcd.print(rtc.getDateStr()); 
  
  //Blink 
  delay(3000);   
  lcd.clear();
  
  // Fim do LCD
  
  
  //Inicio Servo

  if(estadoBotao == LOW) 
    {
      delay(200);
      servo.write(180); delay(4000); //espera 4 segundos
      servo.write(0); delay(500);
   }    
   
  //Fim Servo
  
  
  //lcd.noDisplay();   
  
  //Serial.print(rtc.getDOWStr()); Dia da senaba
 // Serial.print(" ");  
  
}

Does your RTC have a battery installed? Is the battery still good?

As John asked, check the battery to make sure it has proper voltage and inserted correctly. (i.e. not inserted backwards/upsidedown)

Is the time really being reset or does it just stop?

What is the OSF bit? Bit 7 in the status register (0xf)
You may have to manually read/write this bit as many libraries don't handle it correctly.

If it is set, then the oscillator stopped at some point.

What module are you using? and what type of battery?
Can you post a photo?
Many of them (most that I've seen) require a h/w modification to work correctly in that they have a broken charging circuit. Even worse, many them ship with a regular 2032 which is not a rechargeable battery.

--- bill

bperrybap:
a h/w modification

Please spell out words in full.
Remember, English is not the first language of everyone on this forum.

@Flambo

#include <Servo.h> 

#include <DS3231.h>
DS3231  rtc(SDA, SCL);
Servo servo;
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,2,1,0,4,5,6,7,3, POSITIVE);

I see that you are using four libraries (Servo, DS3231, Wire, and LiquidCrystal_I2C). Where exactly did you get these libraries? I’m guessing that Servo and Wire came with the Arduino software, but where did the other two libraries come from?

Also, I notice that you are trying to do more than just show the time. You are also trying to run a servo. What happens if you remove the “servo” part of your project and try again? (By this I mean: Disconnect the servo from the Arduino. Shorten your sketch by removing all mention of the servo. Upload the shortened sketch to your Arduino, and see what happens.)

johnwasser:
Does your RTC have a battery installed? Is the battery still good?

Yes, it does. It came with the RTC, im pretty sure its fine. I can try with a new one. Next weekend i will buy a new one, but i guess mine is ok.

As John asked, check the battery to make sure it has proper voltage and inserted correctly. (i.e. not inserted backwards/upsidedown)

Is the time really being reset or does it just stop?

What is the OSF bit? Bit 7 in the status register (0xf)
You may have to manually read/write this bit as many libraries don’t handle it correctly.

If it is set, then the oscillator stopped at some point.

What module are you using? and what type of battery?
Can you post a photo?
Many of them (most that I’ve seen) require a h/w modification to work correctly in that they have a broken charging circuit. Even worse, many them ship with a regular 2032 which is not a rechargeable battery.

Here is some pictures i took right know, as you can see my LCD isn’t showing the correct time, it shows 00:00:00.
If i set the time again in the code, it works fine but several minutes(like 2) after being shutdown it returns displaying 00:00:00.

The last one is my fault, hehe, i took the picture while my lcd was blinking to the next text but as you can see it was displaying the time that i set 11:04:12, but then i shutdown the power for like 2 min and it resetted to 00:00:00.

I see that you are using four libraries (Servo, DS3231, Wire, and LiquidCrystal_I2C). Where exactly did you get these libraries? I’m guessing that Servo and Wire came with the Arduino software, but where did the other two libraries come from?

Also, I notice that you are trying to do more than just show the time. You are also trying to run a servo. What happens if you remove the “servo” part of your project and try again? (By this I mean: Disconnect the servo from the Arduino. Shorten your sketch by removing all mention of the servo. Upload the shortened sketch to your Arduino, and see what happens.)

I got LCD+I2C from here, and the DS3231 one from here.

Yes, im trying more than a simple RTC plus LCD. This is supposed to be a system for a fishtank(my first project using arduino), so i gotta have the right time being set cause Servo is activated at some time set by the code, like every 8 hours, do you know what i mean ?

Ok, i will remove the servo part and upload the results here but as i said the its an important piece of the whole project.

Maybe it’s an important information for you guys to help me, but i’ve got another problem with this code because my pushbutton isnt working properly. I’ve already posted in the portuguese section of this forum and they are helpinh me, seems like i gotta learn something about debounce. I think this doesnt affect the problem with RTC, but i gotta be clear with whats going on with my project, hehe.

I’m wondering about that RTC library.

I have a little experiment I would like you to try.
Please run this sketch, and tell me what you see on the LCD.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,2,1,0,4,5,6,7,3, POSITIVE);

// variables for storing the time
//   second  minute  hour    weekday  date    month   year
byte ss=0,   mi=0,   hh=0,   wd=6,    dd=1,   mo=1,   yy=0;
 
void setup()
{
  delay(20); // maybe I don't really need this line
  
  Wire.begin();
 
  // clear /EOSC bit
  // Sometimes necessary to ensure that the clock
  // keeps running on just battery power. Once set,
  // it shouldn't need to be reset but it's a good
  // idea to make sure.
//  Wire.beginTransmission(0x68); // address DS3231
//  Wire.write(0x0E); // select register
//  Wire.write(0b00011100); // write register bitmap, bit 7 is /EOSC
//  Wire.endTransmission();

  delay(20); // maybe I don't really need this line either
  
  lcd.setBacklight(HIGH);
  lcd.clear();
  
  delay(20); // or this line, for that matter
}
 
void loop()
{
  // read the time from the RTC, if we can
  boolean gotTheTime = grabTime();
  
  if (gotTheTime) {
    // if we are here, then the time has been successfully read
    // and stored in global variables (ss, mi, hh, wd, dd, mo, yy)
    printTime();  
  }
  else {
    // if we are here, then we tried to read the time but couldn't
    lcd.setCursor(0,0);
    lcd.print("Unable to read  ");
    lcd.setCursor(0,1);
    lcd.print("time from RTC.  ");
    //         01234567890123456
  }
  
  delay(100);
}


boolean grabTime() {
  // get time from the RTC and put it in global variables

  // send request to receive data starting at register 0
  Wire.beginTransmission(0x68); // 0x68 is DS3231 device address
  Wire.write((byte)0); // start at register 0
  Wire.endTransmission();
  Wire.requestFrom(0x68, 7); // request seven bytes (ss, mi, hh, wd, dd, mo, yy)
  // check for a reply from the RTC, and use it if we can
  if (Wire.available() >= 7) {
    // if we're here, we got a reply and it is long enough
    // so now we read the time
    ss = bcd2bin(Wire.read()); // get seconds
    mi = bcd2bin(Wire.read()); // get minutes
    hh = bcd2bin(Wire.read()); // get hours
    wd = bcd2bin(Wire.read()); // get day of week
    dd = bcd2bin(Wire.read()); // get day of month
    mo = bcd2bin(Wire.read()); // get month
    yy = bcd2bin(Wire.read()); // get year (two digits)
    // indicate that we successfully got the time
    return true;
  }
  else {
    // indicate that we were unable to read the time
    return false;
  }
}


byte bcd2bin(byte x) {
  // converts from binary-coded decimal to a "regular" binary number
  return ((((x >> 4) & 0xF) * 10) + (x & 0xF)) ;
}


void printTime() {
  // just like the name says  
  char buf[35]; // this is more than we really need, but so what?
  lcd.setCursor(0,0);
  //            0 12 3 45 6 78 9 0 1 23456
  sprintf(buf,"\'%02d.%02d.%02d(%c%c%c)  ",yy,mo,dd,
   "BMTWTFSS"[(wd<7)?wd:0],"aouehrau"[(wd<7)?wd:0],"dneduitn"[(wd<7)?wd:0]);
  lcd.print(buf);
  lcd.setCursor(0,1);
  //            01 2 34 5 67 890123456
  sprintf(buf,"%02d:%02d:%02d        ",hh,mi,ss);
  lcd.print(buf);   
}

That RTC module has the charging circuit issue. You need to modify it to protect the 2032 battery.
As is it tries to feed voltage/current into the 2032 which is not a rechargeable battery.
You need to cut the trace that runs between the battery and the diode.
Just use a small knife (I use an exacto knife) to cut the trace.
It doesn’t take much just as long as trace is cut.
See the photo for which trace.

You should also use a volt meter to measure the voltage of the battery to see if is ok or if it needs to be replaced.
It should read slightly above or very close to 3v.

— bill

Or remove a component in the charging path? Is there a diode or something that could be removed?

CrossRoads:
Or remove a component in the charging path? Is there a diode or something that could be removed?

Yes, you could remove the diode or simply rip it apart with pliers or remove the resistor but cutting the trace going to the diode does the same thing and I think is simpler & not as ugly as breaking the diode.
Just a few cuts with an exacto knife.

--- bill

bperrybap:
That RTC module has the charging circuit issue. You need to modify it to protect the 2032 battery.
As is it tries to feed voltage/current into the 2032 which is not a rechargeable battery.
You need to cut the trace that runs between the battery and the diode.
Just use a small knife (I use an exacto knife) to cut the trace.
It doesn’t take much just as long as trace is cut.
See the photo for which trace.

You should also use a volt meter to measure the voltage of the battery to see if is ok or if it needs to be replaced.
It should read slightly above or very close to 3v.

— bill

This?

odometer:

I’m wondering about that RTC library.

I have a little experiment I would like you to try.
Please run this sketch, and tell me what you see on the LCD.

#include <Wire.h>

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,2,1,0,4,5,6,7,3, POSITIVE);

// variables for storing the time
//  second  minute  hour    weekday  date    month  year
byte ss=0,  mi=0,  hh=0,  wd=6,    dd=1,  mo=1,  yy=0;

void setup()
{
  delay(20); // maybe I don’t really need this line
 
  Wire.begin();

// clear /EOSC bit
  // Sometimes necessary to ensure that the clock
  // keeps running on just battery power. Once set,
  // it shouldn’t need to be reset but it’s a good
  // idea to make sure.
//  Wire.beginTransmission(0x68); // address DS3231
//  Wire.write(0x0E); // select register
//  Wire.write(0b00011100); // write register bitmap, bit 7 is /EOSC
//  Wire.endTransmission();

delay(20); // maybe I don’t really need this line either
 
  lcd.setBacklight(HIGH);
  lcd.clear();
 
  delay(20); // or this line, for that matter
}

void loop()
{
  // read the time from the RTC, if we can
  boolean gotTheTime = grabTime();
 
  if (gotTheTime) {
    // if we are here, then the time has been successfully read
    // and stored in global variables (ss, mi, hh, wd, dd, mo, yy)
    printTime(); 
  }
  else {
    // if we are here, then we tried to read the time but couldn’t
    lcd.setCursor(0,0);
    lcd.print("Unable to read  ");
    lcd.setCursor(0,1);
    lcd.print("time from RTC.  ");
    //        01234567890123456
  }
 
  delay(100);
}

boolean grabTime() {
  // get time from the RTC and put it in global variables

// send request to receive data starting at register 0
  Wire.beginTransmission(0x68); // 0x68 is DS3231 device address
  Wire.write((byte)0); // start at register 0
  Wire.endTransmission();
  Wire.requestFrom(0x68, 7); // request seven bytes (ss, mi, hh, wd, dd, mo, yy)
  // check for a reply from the RTC, and use it if we can
  if (Wire.available() >= 7) {
    // if we’re here, we got a reply and it is long enough
    // so now we read the time
    ss = bcd2bin(Wire.read()); // get seconds
    mi = bcd2bin(Wire.read()); // get minutes
    hh = bcd2bin(Wire.read()); // get hours
    wd = bcd2bin(Wire.read()); // get day of week
    dd = bcd2bin(Wire.read()); // get day of month
    mo = bcd2bin(Wire.read()); // get month
    yy = bcd2bin(Wire.read()); // get year (two digits)
    // indicate that we successfully got the time
    return true;
  }
  else {
    // indicate that we were unable to read the time
    return false;
  }
}

byte bcd2bin(byte x) {
  // converts from binary-coded decimal to a “regular” binary number
  return ((((x >> 4) & 0xF) * 10) + (x & 0xF)) ;
}

void printTime() {
  // just like the name says 
  char buf[35]; // this is more than we really need, but so what?
  lcd.setCursor(0,0);
  //            0 12 3 45 6 78 9 0 1 23456
  sprintf(buf,"’%02d.%02d.%02d(%c%c%c)  “,yy,mo,dd,
  “BMTWTFSS”[(wd<7)?wd:0],“aouehrau”[(wd<7)?wd:0],“dneduitn”[(wd<7)?wd:0]);
  lcd.print(buf);
  lcd.setCursor(0,1);
  //            01 2 34 5 67 890123456
  sprintf(buf,”%02d:%02d:%02d        ",hh,mi,ss);
  lcd.print(buf); 
}

UPDATE: I’ve done what bperrybap said and now my time isn’t reseting to 00:00 anymore, but now it isnt counting while the power is off. For example: i’ve set the time as 19:25, while the power is on everytime seems fine but when i turn it off the time counting freezes and only returns when the power is on again.

#include <Servo.h> 
#include <DS3231.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,2,1,0,4,5,6,7,3, POSITIVE);
DS3231  rtc(SDA, SCL);
Servo servo;
int estadoBotao = 0; 
int Chave=3;
int counter = 0;
int lastCount = 0;
void setup() 
{ 
  Serial.begin(9600);
  rtc.begin();
  lcd.begin (16,2);
  //rtc.setDOW(MONDAY);     // Set Day-of-Week to SUNDAY
  //rtc.setTime(19, 20, 00);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(29, 12, 2016);   // Set the date to January 1st, 2014
  servo.attach(9);   
  //Define o pino como entrada
  pinMode(Chave, INPUT);      // INPUT -> LOW É LIGADO
  //Aciona o resistor pull-up interno
  digitalWrite(Chave, HIGH);  
} 

void loop() 
{ 
  botao_1();
  lcd_f();
}

void lcd_f() 
{
  lcd.setBacklight(HIGH);
  lcd.setCursor(0,0);
  lcd.print(rtc.getTemp());
  lcd.print(" C");
  lcd.setCursor(0,1);
  lcd.print(rtc.getTimeStr());    

  //Blink   
  delay(3000);     
  lcd.display();   
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.clear();

  lcd.print("D: "); 
  lcd.print(rtc.getDateStr()); 
  
  //Blink 
  delay(3000);   
  lcd.clear();
  
  // Fim do LCD
  
}
void botao_1() 
{
  
  //Inicio Servo

  estadoBotao=digitalRead(Chave);  //Caso a chave seja pressionada, movimenta o servo
  if(estadoBotao == LOW) 
    {
      counter++;
      delay(250);
      //delay(200);
      //servo.write(180); delay(4000); //espera 4 segundos
      //servo.write(0); delay(500)
    
   } 
  if(counter == 2) { lcd.setBacklight(HIGH);  lcd.setCursor(0,0);  lcd.print("Pressionado "); lcd.print(counter);  lcd.print("vzs"); }
  if(counter > 4) { lcd.setBacklight(HIGH); lcd.setCursor(0,0); lcd.print(counter); }
  //Fim Servo
  
  
}

bperrybap:
Even worse, many them ship with a regular 2032 which is not a rechargeable battery.

--- bill

That's perfectly normal, lithium button cells have a ten year shelf life, RTC's take a microamp or so to run.

MarkT:
That's perfectly normal, lithium button cells have a ten year shelf life, RTC's take a microamp or so to run.

I think you have misunderstood the issue. The issue isn't using a CR2032. The issue is that there is a crappy charging circuit on the board attempting to charge a battery that is not intended to be recharged.
i.e. LIR2032 is a rechargeable battery the CR2032 is not.

--- bill

flambo,
Did you measure the voltage of the battery?
Also, if you did that cut with the battery in, you may have shorted it out and drained it down a bit (or a lot).
What is the battery voltage now?

I also wonder about that rtc library.
It does its own i2c protocol. If the pins used match the h/w pins then it uses the h/w else it does it in s/w.
In this case it will use h/w but.... It doesn't use the Wire library and instead writes to the 2wire registers directly so I wonder if it has any issues or if it can peacefully exist with the Arduino Wire library which is used by the lcd library.
There is even a comment about this on the referenced page:

The library has not been tested in combination with the Wire library and I have no idea if they can share pins. Do not send me any questions about this. If you experience problems with pin-sharing you can move the DS3231/DS3232 SDA and SCL pins to any available pins on your development board. This library will in this case fall back to a software-based, TWI-/I2C-like protocol which will require exclusive access to the pins used.

If it were me, I'd use a different RTC library.

--- bill

bperrybap:
flambo,
Did you measure the voltage of the battery?
Also, if you did that cut with the battery in, you may have shorted it out and drained it down a bit (or a lot).
What is the battery voltage now?

I also wonder about that rtc library.
It does its own i2c protocol. If the pins used match the h/w pins then it uses the h/w else it does it in s/w.
In this case it will use h/w but.... It doesn't use the Wire library and instead writes to the 2wire registers directly so I wonder if it has any issues or if it can peacefully exist with the Arduino Wire library which is used by the lcd library.
There is even a comment about this on the referenced page:
If it were me, I'd use a different RTC library.

--- bill

I cant measure the voltage cause i downt have a multimeter. Which library could i use ? Every tutorial i've seen on internet about RTC DS3231 uses this library.

bperrybap:
flambo,
Did you measure the voltage of the battery?
Also, if you did that cut with the battery in, you may have shorted it out and drained it down a bit (or a lot).
What is the battery voltage now?

I also wonder about that rtc library.
It does its own i2c protocol. If the pins used match the h/w pins then it uses the h/w else it does it in s/w.
In this case it will use h/w but… It doesn’t use the Wire library and instead writes to the 2wire registers directly so I wonder if it has any issues or if it can peacefully exist with the Arduino Wire library which is used by the lcd library.
There is even a comment about this on the referenced page:
If it were me, I’d use a different RTC library.

— bill

Alright bill, i’ve been thinking about your words so i changed my code and library. Seems like my new code works fine, the only problem i’ve seen is the time is wrong for like ~2hours and i dunno how to change. Take a look.

#include "Wire.h"
#define DS1307_ADDRESS 0x68

void setup(){
  Wire.begin();
  Serial.begin(9600);
}

void loop(){
  printDate();
  delay(1000);
}

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

void printDate(){

  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());
  //print the date EG   3/1/11 23:59:59
  Serial.print(month);
  Serial.print("/");
  Serial.print(monthDay);
  Serial.print("/");
  Serial.print(year);
  Serial.print(" ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.println(second);

}

After a few changes, my new code is here. Seems like everyIthing is going fine, im not sure if the temperature on display is correct but this isn’t a huge issue. I will post here soon if everythings keeps working fine. Seems like the problem was with the library as billy said.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "Wire.h"
#define DS1307_ADDRESS 0x68
#define DS3231_I2C_ADDR             0x68
#define DS3231_TEMPERATURE_MSB      0x11
#define DS3231_TEMPERATURE_LSB      0x12
LiquidCrystal_I2C lcd(0x3F,2,1,0,4,5,6,7,3, POSITIVE);
void setup() 
{ 
  Wire.begin();
  Serial.begin(9600);
  lcd.begin (16,2);
} 
void loop() 
{ 
  temp();
  printDate();
  delay(1000);
}
byte temp_msb;
byte temp_lsb;
byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}
byte DS3231_get_MSB(){
  Wire.beginTransmission(DS3231_I2C_ADDR);
  Wire.write(DS3231_TEMPERATURE_MSB);
  Wire.endTransmission();

  Wire.requestFrom(DS3231_I2C_ADDR, 1);
  temp_msb = Wire.read();

}
byte DS3231_get_LSB(){
  Wire.beginTransmission(DS3231_I2C_ADDR);
  Wire.write(DS3231_TEMPERATURE_LSB);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDR, 1);
  temp_lsb = Wire.read() >> 6;
}
void temp()
{
  temp_msb = DS3231_get_MSB();
  temp_lsb = DS3231_get_LSB();
  Serial.print(temp_msb);
  switch(temp_lsb){
  case 0:
    Serial.println(".00");
    break;
  case 1 :
    Serial.println(".25");
    break;
  case 2:
    Serial.println(".50");
    break;
  case 3:
    Serial.println(".75");
    break;
  }
  delay(2000);  
}
void printDate(){
  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 7);
  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());
  //print the date EG   3/1/11 23:59:59
  Serial.print(month);
  Serial.print("/");
  Serial.print(monthDay);
  Serial.print("/");
  Serial.print(year);
  Serial.print(" ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.println(second);

}

My favorite libraries for dealing with time and a ds3231 RTC are Time and DS3232.
They work together.
You can find Time in the IDE library manger and DS3232 (which works on DS3231 modules) is available here:

The summary is that is it uses unix epoch to track time. The Time library tracks the time and you get the time using Time library API calls. You set up a time synchronization routine that Time will periodically call to set the time - default is like five every minutes. You can tell Time to use an API function in the ds3232 library.
That ds3232 function will read the RTC and convert the time to a unix epoch to return to Time. In between synchronizations, Time keeps updating the time on its own using millis()

In terms of getting the local time, you simply make API calls into Time. It can give you hour, min, sec, etc...
as well as many other things time and date related.

If you want/need to do automatic DST/summer-time adjustments you can add on the Timezone library:

There lots of examples in all 3 libraries that show how to use the API functions in each.

--- bill

bperrybap:
The summary is that is it uses unix epoch to track time. The Time library tracks the time and you get the time using Time library API calls. You set up a time synchronization routine that Time will periodically call to set the time - default is like five every minutes. You can tell Time to use an API function in the ds3232 library.
That ds3232 function will read the RTC and convert the time to a unix epoch to return to Time. In between synchronizations, Time keeps updating the time on its own using millis()

“Five every minutes”? Don’t you mean “once every five minutes”?
Once every five minutes is a bug waiting to happen, and I have seen it happen on these forums. If there is a problem, you want it to fail fast: having to babysit a clock for five minutes is nothing but a hindrance.
In my opinion, it is overkill to use a library to read from and write to an RTC. Here is an old sketch of mine, which demonstrates why. (Note: this sketch uses the Serial monitor.)

#include <Wire.h>

// variables for storing the time
//   second  minute  hour    weekday  date    month   year
byte ss=0,   mi=0,   hh=0,   wd=6,    dd=1,   mo=1,   yy=0;
 
void setup()
{
  Wire.begin();
  Serial.begin(9600); // or whatever baud rate you wish to use
 
  // clear /EOSC bit
  // Sometimes necessary to ensure that the clock
  // keeps running on just battery power. Once set,
  // it shouldn't need to be reset but it's a good
  // idea to make sure.
//  Wire.beginTransmission(0x68); // address DS3231
//  Wire.write(0x0E); // select register
//  Wire.write(0b00011100); // write register bitmap, bit 7 is /EOSC
//  Wire.endTransmission();
}
 
void loop()
{
  // read the time from the RTC, if we can
  boolean gotTheTime = grabTime();
  
  if (gotTheTime) {
    // if we are here, then the time has been successfully read
    // and stored in global variables (ss, mi, hh, wd, dd, mo, yy)
    Serial.print("Got the time: ");
    printTime();  
  }
  else {
    // if we are here, then we tried to read the time but couldn't
    Serial.println("Unable to read time from RTC");
  }
  
  delay(500);
}


boolean grabTime() {
  // get time from the RTC and put it in global variables

  // send request to receive data starting at register 0
  Wire.beginTransmission(0x68); // 0x68 is DS3231 device address
  Wire.write((byte)0); // start at register 0
  Wire.endTransmission();
  Wire.requestFrom(0x68, 7); // request seven bytes (ss, mi, hh, wd, dd, mo, yy)
  // check for a reply from the RTC, and use it if we can
  if (Wire.available() >= 7) {
    // if we're here, we got a reply and it is long enough
    // so now we read the time
    ss = bcd2bin(Wire.read()); // get seconds
    mi = bcd2bin(Wire.read()); // get minutes
    hh = bcd2bin(Wire.read()); // get hours
    wd = bcd2bin(Wire.read()); // get day of week
    dd = bcd2bin(Wire.read()); // get day of month
    mo = bcd2bin(Wire.read()); // get month
    yy = bcd2bin(Wire.read()); // get year (two digits)
    // indicate that we successfully got the time
    return true;
  }
  else {
    // indicate that we were unable to read the time
    return false;
  }
}


byte bcd2bin(byte x) {
  // converts from binary-coded decimal to a "regular" binary number
  return ((((x >> 4) & 0xF) * 10) + (x & 0xF)) ;
}


void printTime() {
  // just like it says on the tin
  Serial.print ("\'");
  if (yy<10) Serial.print("0"); Serial.print(yy,DEC); Serial.print("-");
  if (mo<10) Serial.print("0"); Serial.print(mo,DEC); Serial.print("-");
  if (dd<10) Serial.print("0"); Serial.print(dd,DEC); Serial.print("(");
  switch (wd) {
    case 1: Serial.print("Mon"); break;
    case 2: Serial.print("Tue"); break; 
    case 3: Serial.print("Wed"); break; 
    case 4: Serial.print("Thu"); break; 
    case 5: Serial.print("Fri"); break; 
    case 6: Serial.print("Sat"); break; 
    case 7: Serial.print("Sun"); break;
    default: Serial.print("Bad");  
  }
  Serial.print(") ");
  if (hh<10) Serial.print("0"); Serial.print(hh,DEC); Serial.print(":");
  if (mi<10) Serial.print("0"); Serial.print(mi,DEC); Serial.print(":");
  if (ss<10) Serial.print("0"); Serial.print(ss,DEC); Serial.println("");
}

odometer:
Once every five minutes is a bug waiting to happen, and I have seen it happen on these forums. If there is a problem, you want it to fail fast: having to babysit a clock for five minutes is nothing but a hindrance.

Not really. When you initialize the RTC library interface as you set up the Time library synchronizer you immediately know if there is an issue with the RTC and can deal with it appropriately then.

In my opinion, it is overkill to use a library to read from and write to an RTC. Here is an old sketch of mine, which demonstrates why. (Note: this sketch uses the Serial monitor.)

That assumes a very narrow implementation and that only localtime is needed. If you need to track time in a way that allows you to do timestamps (which can work across timezones) or compare different times or things like DST/summertime adjustments, the easiest way to do that is to use epoch time which is the most efficient way to track time as it puts all the information into a single integer that makes lots of things easier to do than when using local time which consists of many individual values.
The RTC is merely one of many possible ways used to initialize the epoch in the Time library and to periodically synchronize it to minimize drift.
By using libraries for tracking time and handling the RTC you can have all this up and running very quickly and have the ability to easy expand or modify the code for future capabilities.

Sure you can easily do all the accesses to/from the RTC yourself without a library but then once you go beyond simple localtime you have to write lots of other code to handle things beyond just simple local time and doing calculations in local time vs an epoch are very messy and subject to errors.

If all you want is localtime and never want to do things like time delta calculations, automatic timezone or DST adjustments or later use other clock sources such as NTP or GPS, using only localtime and directly accessing the RTC is ok, but once you go beyond simple localtime and manually setting the time, things can quickly start to get complicated and messy.
i.e. just try to do something as simple as tell if an hour has passed.
With epoch time you simple subtract the two epoch/time-stamp values and see if the difference is bigger than 3600. With nothing but localtime variables it gets very messy as you have to account for hour/min/day/month/year changes (and don’t forget leap years) to be able to fully calculate the difference.
Same is true for calculating a time in the past or future from now.

The world is rapidly moving to IoT and modules like the ESP8266 allow adding NTP over WiFi for just a few dollars which is not more than the cost of a DS3231 module.
And the ESP modules are powerful enough that they can actually be used for everything to create a super low cost solution. (i.e. move all the arduino code to inside the ESP module and use it for everything)

Using libraries for tracking time offers not only offers an easy way to a short time for implementation but also allows for quick changes to accommodate h/w changes or to add additional features or other clock sources in the future.

— bill

bperrybap:
If you need to track time in a way that allows you to do timestamps (which can work across timezones) or compare different times or things like DST/summertime adjustments, the easiest way to do that is to use epoch time which is the most efficient way to track time as it puts all the information into a single integer that makes lots of things easier to do than when using local time which consists of many individual values.

For everyday practical purposes, not usually.
If I want to ring a bell every hour, on the hour, my job is easier if I don't have to screw around with long division (both in the sense of the childhood torture and in the sense of division of longs.).
If I want to dim a light after such-and-such an hour in the evening, I shouldn't even have to look at seconds.
I see no reason for the components of the current time to not simply be global variables. As far as your Arduino is concerned, time is global: your Arduino inhabits reality, not some weird time-travel sci-fi movie. That way, no getters or setters are needed. No namespace either. Alarms are trivial to implement, and can be turned off simply by setting them to a nonexistent time. You could "toggle" a 7:30 alarm by setting it to 57:30, and then back to 7:30 to turn it on. (I have not actually used this approach, but it sounds like it would make sense.)

Using a library for such things seems the equivalent of driving (as opposed to walking) 50 meters. Especially in my city, what with all the one-way streets.

You mentioned Daylight Saving Time adjustments. All the more reason not to mess around with epoch times. Just keep track of the "real" time and date, then have a function which tells you whether or not to add 1 to the displayed hour. Of course, the extra hour can spill over into the date, but in that case just tell it to show "tomorrow's" date instead of "today's".

In my experience, the best compromise is either to keep a "long count" of days (really an "unsigned int count": you will die before it overflows), and counts of hours, minutes, and seconds; or just to keep track of all six or seven components separately, like you would on paper. You only need two functions to convert a "long count" of days to a calendar date and vice versa. My table clock, which has been running happily for a few years now, uses the "long count" approach. The "everything separate" approach is perhaps only good if you don't intend to calculate on dates. Daylight Saving Time requires such calculation, which is why it's good that my clock uses the "long count".

Hours, minutes, and seconds can be crammed together into a 32-bit (long) integer with enough room left over for two digits of split-seconds. Good if you want to make a timer or stopwatch.

unsigned long timeAdd (unsigned long x, unsigned long y) {
  // no sanity checking of input
  // format is hhmmssff with ff being decimal fractions of a second
  // "out of range" results are e.g. A0000000 for 100 hours
  unsigned long binsum = x + y;
  unsigned long carry = ((binsum + 0x06A6A666) ^ x ^ y) & 0x11111110;
  return (binsum + ((carry - (carry>>4)) & 0x06A6A666));  
}

unsigned long timeSub (unsigned long x, unsigned long y) {
  // no sanity checking of input
  // format is hhmmssff with ff being decimal fractions of a second
  // "negative" results are e.g. F9595999 for -0.01 second
  unsigned long bindiff = x - y;
  unsigned long borrow = (bindiff ^ x ^ y) & 0x11111110;
  return (bindiff - ((borrow - (borrow>>4)) & 0x06A6A666) );
}

There is, however, at least one extremely palpable exception to everything I have said. The exception is if your day is not 24 standard Earth hours. For example, some scientists literally live by Mars time: their jobs require them to. They, and their families, require a Mars clock (one Mars day is about 24 hours and 40 minutes Earth time). That is just one example. A more down-to-earth example is a tide clock: one "tidal day" is about 24 hours and 50 minutes. In such situations, you might well be better off trying to cram everything into one number, so that you can then multiply or divide that number by a constant to get a number that changes at the exact rate you need it to change. If you do so, though, you must keep in mind the (cramped) limitations of Arduino arithmetic. For example, the Mars clock requires a division by 1.027491252, which is perhaps best implemented as a multiplication by 0.0267557042 followed by a coercion to integer and then a subtraction.

The RTC is merely one of many possible ways used to initialize the epoch in the Time library and to periodically synchronize it to minimize drift.
By using libraries for tracking time and handling the RTC you can have all this up and running very quickly and have the ability to easy expand or modify the code for future capabilities.

Sure you can easily do all the accesses to/from the RTC yourself without a library but then once you go beyond simple localtime you have to write lots of other code to handle things beyond just simple local time and doing calculations in local time vs an epoch are very messy and subject to errors.

If all you want is localtime and never want to do things like time delta calculations, automatic timezone or DST adjustments or later use other clock sources such as NTP or GPS, using only localtime and directly accessing the RTC is ok, but once you go beyond simple localtime and manually setting the time, things can quickly start to get complicated and messy.
i.e. just try to do something as simple as tell if an hour has passed.
With epoch time you simple subtract the two epoch/time-stamp values and see if the difference is bigger than 3600. With nothing but localtime variables it gets very messy as you have to account for hour/min/day/month/year changes (and don't forget leap years) to be able to fully calculate the difference.
Same is true for calculating a time in the past or future from now.

The world is rapidly moving to IoT and modules like the ESP8266 allow adding NTP over WiFi for just a few dollars which is not more than the cost of a DS3231 module.
And the ESP modules are powerful enough that they can actually be used for everything to create a super low cost solution. (i.e. move all the arduino code to inside the ESP module and use it for everything)

Using libraries for tracking time offers not only offers an easy way to a short time for implementation but also allows for quick changes to accommodate h/w changes or to add additional features or other clock sources in the future.

--- bill