Building a time-stamp string

I am trying to create a character variable that contains the time-stamp as a string. I have not succeeded.

I have tried two methods to build the string but it does not work.

Code:

#include <Time.h>  
#include <Wire.h>  
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t

char timestamp[20]; // declare a character variable that contains timestamp
char timestamp1[20];

void setup()
{
  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");
}

void loop()
{
  //this method does not work
  timestamp[0]= (char) year();
  timestamp[4]='-';
  timestamp[5]= (char) month();
  timestamp[7]='-';
  timestamp[8]= (char) day();
  timestamp[10]=' ';
  timestamp[11]= (char) hour();
  timestamp[13]=':';
  timestamp[14]= (char) minute();
  timestamp[16]=':';
  timestamp[17]= (char) second();
 
  //this method also does not work.
 char timestamp2[20]= { (char) year(),'-',(char) month(),'-',(char) day(),' ',(char) hour(),':',(char) minute(),':',(char) second() };
  
  
  
  Serial.print("My timestamps:  ");
  Serial.print(timestamp);  
  Serial.print("    ");
  Serial.print(timestamp2);
  Serial.print("    ");
  Serial.print("timestamp should look like this!!! ");
  Serial.print(year());
  Serial.print("-");
  printDigits(month());
  Serial.print("-");
  printDigits(day());
  Serial.print(" ");
  printDigits(hour());
  Serial.print(":");
  printDigits(minute());
  Serial.print(":");
  printDigits(second());
  Serial.println();
  delay(1000);
 

}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Serial monitor shows this:

RTC has set the system time
My timestamps: Ð Ð-- ::% timestamp should look like this!!! 2000-01-19 22:15:37
My timestamps: Ð Ð-- ::& timestamp should look like this!!! 2000-01-19 22:15:38
My timestamps: Ð Ð-- ::’ timestamp should look like this!!! 2000-01-19 22:15:39
My timestamps: Ð Ð-- ::( timestamp should look like this!!! 2000-01-19 22:15:40
My timestamps: Ð Ð-- ::) timestamp should look like this!!! 2000-01-19 22:15:41
My timestamps: Ð Ð-- ::* timestamp should look like this!!! 2000-01-19 22:15:42
My timestamps: Ð Ð-- ::+ timestamp should look like this!!! 2000-01-19 22:15:43
My timestamps: Ð Ð-- ::, timestamp should look like this!!! 2000-01-19 22:15:44
My timestamps: Ð Ð-- ::- timestamp should look like this!!! 2000-01-19 22:15:45
My timestamps: Ð Ð-- ::. timestamp should look like this!!! 2000-01-19 22:15:46
My timestamps: Ð Ð-- ::/ timestamp should look like this!!! 2000-01-19 22:15:47
My timestamps: Ð Ð-- ::0 timestamp should look like this!!! 2000-01-19 22:15:48
My timestamps: Ð Ð-- ::1 timestamp should look like this!!! 2000-01-19 22:15:49
My timestamps: Ð Ð-- ::2 timestamp should look like this!!! 2000-01-19 22:15:50
My timestamps: Ð Ð-- ::3 timestamp should look like this!!! 2000-01-19 22:15:51
My timestamps: Ð Ð-- ::4 timestamp should look like this!!! 2000-01-19 22:15:52
My timestamps: Ð Ð-- ::5 timestamp should look like this!!! 2000-01-19 22:15:53
My timestamps: Ð Ð-- ::6 timestamp should look like this!!! 2000-01-19 22:15:54
My timestamps: Ð Ð-- ::7 timestamp should look like this!!! 2000-01-19 22:15:55
My timestamps: Ð Ð-- ::8 timestamp should look like this!!! 2000-01-19 22:15:56
My timestamps: Ð Ð-- ::9 timestamp should look like this!!! 2000-01-19 22:15:57
My timestamps: Ð Ð-- ::: timestamp should look like this!!! 2000-01-19 22:15:58
My timestamps: Ð Ð-- ::; timestamp should look like this!!! 2000-01-19 22:15:59
My timestamps: Ð Ð-- :: timestamp should look like this!!! 2000-01-19 22:16:00
My timestamps: Ð Ð-- :: timestamp should look like this!!! 2000-01-19 22:16:01
My timestamps: Ð Ð-- :: timestamp should look like this!!! 2000-01-19 22:16:02
My timestamps: Ð Ð-- :: timestamp should look like this!!! 2000-01-19 22:16:03
My timestamps: Ð Ð-- :: timestamp should look like this!!! 2000-01-19 22:16:04
My timestamps: Ð Ð-- :: timestamp should look like this!!! 2000-01-19 22:16:05
My timestamps: Ð Ð-- :: timestamp should look like this!!! 2000-01-19 22:16:06
My timestamps: Ð Ð-- ::a timestamp should look like this!!! 2000-01-19 22:16:07
My timestamps: Ð Ð-- :: timestamp should look like this!!! 2000-01-19 22:16:08
My timestamps: Ð Ð-- :: timestamp should look like this!!! 2000-01-19 22:16:09
My timestamps: Ð Ð-- ::
timestamp should look like this!!! 2000-01-19 22:16:11
My timestamps: Ð Ð-- :: timestamp should look like this!!! 2000-01-19 22:16:12
My timestamps: Ð Ð-- ::
timestamp should look like this!!! 2000-01-19 22:16:13
My timestamps: Ð Ð-- :: timestamp should look like this!!! 2000-01-19 22:16:14

How to do it correctly?

  //this method does not work
  timestamp[0]= (char) year();

year () returns what? An "int"? Let's say it returns 2015 (0x7DF) , cast that to a char and what do you get? 0xdf, which is what, in ASCII?

Use sprintf - it's simpler.

Use sprintf - it's simpler.

It has an added benefit in that it actually works.

AWOL:

  //this method does not work

timestamp[0]= (char) year();



year () returns what? An "int"?
Let's say it returns 2015 (0x7DF) , cast that to a char and what do you get? 0xdf, which is what, in ASCII?

Use sprintf - it's simpler.

But how do I use sprintf() to insert characters to specific index locations of the array?

if I use after the variable eg: sprintf(timestamp[5], "%d", month());

Then I get error: invalid conversion from ‘char’ to ‘char*’

If I do not specify index location then it just overwrites the variable every time.

sprintf (appropriatelySizedBuffer, "%02d/%02d/%4d", day(), month(), year());

AWOL:

sprintf (appropriatelySizedBuffer, "%02d/%02d/%4d", day(), month(), year());

Thanks! This sprintf() seems like a really powerful tool.

My working time-stamp code:

#include <Time.h>  
#include <Wire.h>  
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t

char timestamp[20]; // declare a character variable that contains time-stamp


void setup()
{
  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");
}

void loop()
{

  sprintf (timestamp, "%4d-%02d-%02d %02d:%02d:%02d", year(), month(),day(), hour(), minute(), second());
  Serial.println(timestamp);
  delay(1000);
 

}

your issue is you do not understand ascii encoding.

for ezample if your date is 20, you need to write '2' '0' which are two ascii characters.

you could hack like this:

20/10 =2 -> timestamp[0]= '0' +2; 20%10 =0 ->timestamp[1]='0' +0;

this works because the ascii values of numbers are sequential, aka '1' == '0'+1.

The value of '0' is 48...

http://www.asciitable.com/index/asciifull.gif

most characters you've tried to print are non printable ones so they look funky...

use snprintf, it’ll avoid you corrupting your memory if the buffer is too small. use sizeof(timestamp) for the size parameter…

naftaliin: But how do I use sprintf() to insert characters to specific index locations of the array?

if I use [] after the variable eg:

sprintf(timestamp[5], "%d", month());

Then I get error: invalid conversion from 'char' to 'char*'

If I do not specify index location then it just overwrites the variable every time.

You need a pointer to char, timestamp+5 rather than a char timestamp[5] Anyway that sticks in null terminator, its easier to sprintf the whole string in one call - just like you would with printf. Examples all over the internet.

sonyhome: use snprintf, it'll avoid you corrupting your memory if the buffer is too small. use sizeof(timestamp) for the size parameter...

Better still, use snprintf_P . . .

Thanks for ideas for other approaches. May need some of them if memory usage becomes a problem.

sprintf() seems to use a lot of memory and the whole sketch is 7,848 bytes! Some of it is for serial communication but the libraries alone use a lot as well.

Are really all 3 libraries needed to produce my time-stamp like in the "Time" library example or would it be possible to get time from my DS3231 clock module reasonably simply some other way? Like some minimum code? These libraries probably have all sort of other functions that I do not use.

you can generate the ASCII yourself because your string format is very easy, only numbers, positions and number of digits are fixed.

define a blank string with all zeros in the date elements, and write out each character as I showed you and that will take a few hundred bytes, no C library, and maybe 30 cycles.

sprintf() seems to use a lot of memory

No, it uses code space, not memory.

PaulS: No, it uses code space, not memory.

Which I believe is stored in flash memory?

Are you running short of flash?

AWOL:
Are you running short of flash?

Yes I want to use this time-stamp code in my temperature control chamber code and flash storage is getting full.

I have smaller time reading code that uses only the Wire library:

#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}
void setup()
{
  Wire.begin();
  Serial.begin(9600);
  // set the initial time here:
  // DS3231 seconds, minutes, hours, day, date, month, year
  // setDS3231time(30,42,21,4,26,11,14);
}

void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *day,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *day = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}
void displayTime()
{
  byte second, minute, hour, day, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &day, &month,
  &year);
  // send it to the serial monitor
  Serial.print(hour, DEC);
  // convert the byte variable to a decimal number when displayed
  Serial.print(":");
  if (minute<10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second<10)
  {
    Serial.print("0");
  }
  Serial.print(second, DEC);
  Serial.print(" ");
  Serial.print(day, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.println(year, DEC);

  
}
void loop()
{
  displayTime(); // display the real-time clock data on the Serial Monitor,
  delay(1000); // every second
}

But it has some problems.
There are two issues

  1. In the serial monitor some numbers are missing.

This is what it prints:

1:05:41 6/20/1
1:05:42 6/20/1
1:05:43 6/20/1
1:05:44 6/20/1
1:05:45 6/20/1
1:05:46 6/20/1
1:05:47 6/20/1
1:05:48 6/20/1

Looks like the hour is too short and year too. Year cant be 4 digit because it is byte value but it should be 2 digit at least. Decade would be enough anyway.

I do not know why it is not displaying the hour and year correctly.

  1. The displayTime() function should be replaced or modified to produce a character string time-stamp value using preferably some sort of ASCII generation method as mentioned by sonyhome as it would take less space.

Maybe somehow directly convert the BCD bytes that come from the DS3231 to ASCII characters and write them to a string? Then there would be no need to convert to decimal first and split decimal numbers.

BCD digits are easy to convert to ASCII - just add '0'

AWOL:
BCD digits are easy to convert to ASCII - just add ‘0’

Tried adding 0.

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

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

}

void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = Wire.read() & 0x7f +'0';
  *minute = Wire.read() +'0';
  *hour = Wire.read() & 0x3f +'0';
  *dayOfWeek = Wire.read() +'0';
  *dayOfMonth = Wire.read() +'0';
  *month = Wire.read() +'0';
  *year = Wire.read() +'0';
}
void displayTime()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  // send it to the serial monitor
  Serial.print(hour);
  // convert the byte variable to a decimal number when displayed
  Serial.print(":");
  if (minute<10)
  {
    Serial.print("0");
  }
  Serial.print(minute);
  Serial.print(":");
  if (second<10)
  {
    Serial.print("0");
  }
  Serial.print(second);
  Serial.print(" ");
  Serial.print(dayOfWeek);
  Serial.print("  ");
  Serial.print(dayOfMonth);
  Serial.print("/");
  Serial.print(month);
  Serial.print("/");
  Serial.println(year);

  
}
void loop()
{
  displayTime(); // display the real-time clock data on the Serial Monitor,
  delay(1000); // every second
}

Does not work properly.

3:68:08 54 80/49/48
3:68:09 54 80/49/48
3:68:00 54 80/49/48
3:68:01 54 80/49/48
3:68:02 54 80/49/48
3:68:03 54 80/49/48
3:68:04 54 80/49/48
3:68:05 54 80/49/48
3:68:06 54 80/49/48
3:68:07 54 80/49/48
3:68:08 54 80/49/48
3:68:09 54 80/49/48
3:69:00 54 80/49/48
3:69:01 54 80/49/48
3:69:02 54 80/49/48
3:69:03 54 80/49/48
3:69:04 54 80/49/48
3:69:05 54 80/49/48
3:69:06 54 80/49/48
3:69:07 54 80/49/48
3:69:08 54 80/49/48
3:69:09 54 80/49/48
3:69:00 54 80/49/48
3:69:01 54 80/49/48
3:69:02 54 80/49/48
3:69:03 54 80/49/48
3:69:04 54 80/49/48
3:69:05 54 80/49/48
3:69:06 54 80/49/48
3:69:07 54 80/49/48
3:69:08 54 80/49/48
3:69:09 54 80/49/48
3:69:32 54 80/49/48
3:69:33 54 80/49/48
3:69:34 54 80/49/48
3:69:35 54 80/49/48
3:69:36 54 80/49/48
3:69:37 54 80/49/48
3:69:38 54 80/49/48

Probably because the bytes read by the Wire.read() function are not single digits?

Probably because the bytes read by the Wire.read() function are not single digits?

Correct. But BCD digits are really, really easy to split out of a byte.