file creation date and time in sd card ?

Hello all,
My first arduino project is to make a data logger for analogue input.
It consist of Mega, RTC, SD reader.
This system make CSV files for excel. No problem.
But, when I check the CSV files with the windows explorer, the file creation date and time has something wrong.
See this screen captured one.

DATA_000.CSV 2000-01-01 AM 1:00 Microsoft Office Excel
DATA_001.CSV 2000-01-01 AM 1:00 Microsoft Office Excel
DATA_002.CSV 2000-01-01 AM 1:00 Microsoft Office Excel

All files has 2000-01-01 AM 1:00.
This is not the present date and time.

I asked this solution to somebody, but anyone doesn’t explain clearly.
One said I must revise ‘callback function’ in the SD library.
So, I searched and studied the callback function’ in the SD.h and SPI.h.
But I failed.
Is there anybody to explain more details?
Thank you in advance.

Install the SdFat library - there is an example called Timestamp.ino describing in detail how to do it…

// after your rtc is set up and working you code just needs:

void dateTime(uint16_t* date, uint16_t* time) {
  DateTime now = rtc.now();

  // return date using FAT_DATE macro to format fields
  *date = FAT_DATE(now.year(), now.month(), now.day());

  // return time using FAT_TIME macro to format fields
  *time = FAT_TIME(now.hour(), now.minute(), now.second());
}

//put that outside of any functions, before your 'setup'

//Then inside your 'loop' or 'setup'

void loop(void)
{

  //Other code that does stuff

  //put this next line *Right Before* any file open line:
  SdFile::dateTimeCallback(dateTime);
  dataFile = SD.open(datafilename, FILE_WRITE);

  //other code that does stuff

}
2 Likes

God only knows what a callback function is, but I bet you don't need to. The simplest solution is to name the file by date, or time, or both.

An example of that is at

http://homepages.ihug.com.au/~npyner/Arduino/Bluetooth_graphic_5110_with_file_retrieve_DY.ino

Essentially, the clock is checked every loop cycle. If it is midnight, a new file is created, named by date. The vital subroutine for that is:

void getFileName(){
sprintf(filename, "%02d%02d%02d.csv", year, month, day);
}

It really is that simple.

It isn't that simple because that's not what the OP asked for - and God isn't the only one who knows what a callback function is.
The response from @BillHo is precisely what is required. I've just used it in a program of mine, after a bit of modification to use the information from a tm_elements structure instead of using rtc.now(). It does indeed update the file's datetime stamp so that it shows in Windows explorer.
I also used SdFile::dateTimeCallbackCancel(). In my code, I create a new file at the beginning of each UTC day but I open/write/close the file every minute to log the data. If I don't cancel the callback, the date/time stamp will be updated every time I open the file. Cancelling it after the file has been created ensures that the date stamp on the file will be when it was created, not when it was last written. That's the theory anyway, I'll have to wait until after 00:00:00Z before I can check that the file's date/time is correct.

Pete

@donald0000 wants the Date Modified field to show an actual time stamp when you look at the files present on the card using Windows Explorer. As Billy Ho says, the callback function is the way to do it. You can indeed use this function with SD.h if you don't want to convert to SDFat. Here is an example of the function in a sketch. Notice the timing of when the date modified time stamp is written, it is when file.close() writes the actual data to the card.

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>

File file;  // test file
const uint8_t SD_CS = 10; // SD chip select
RTC_DS1307 RTC;  // define the Real Time Clock object

 char timestamp[30];

//------------------------------------------------------------------------------
// call back for file timestamps
void dateTime(uint16_t* date, uint16_t* time) {
 DateTime now = RTC.now();
 sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n", now.hour(),now.minute(),now.second(),now.month(),now.day(),now.year()-2000);
 Serial.println("yy");
 Serial.println(timestamp);
 // return date using FAT_DATE macro to format fields
 *date = FAT_DATE(now.year(), now.month(), now.day());

 // return time using FAT_TIME macro to format fields
 *time = FAT_TIME(now.hour(), now.minute(), now.second());
}
//------------------------------------------------------------------------------
void setup() {
 
 Serial.begin(9600);
 Wire.begin();
 if (!RTC.begin()) {
   Serial.println("RTC failed");
   while(1);
 };
 // set date time callback function
 SdFile::dateTimeCallback(dateTime);
 
  DateTime now = RTC.now();
  sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n", now.hour(),now.minute(),now.second(),now.month(),now.day(),now.year()-2000);
  Serial.println("xx");
  Serial.println(timestamp);
 
 
 if (!SD.begin(SD_CS)) {
   Serial.println("SD.begin failed");
   while(1);
 }
 file = SD.open("TEST_SD.TXT", FILE_WRITE);
 file.println("Testing 1,2,3...");
 
 delay(5000);
 file.close();
 Serial.println("Done");
}
//------------------------------------------------------------------------------
void loop() {}
2 Likes

Thank you.. so much..
I'm now retrying it, according to your advice..

Hope you to have great day..

Nick_Pyner:
God only knows what a callback function is ...

I also know what a callback function is. Documented at Gammon Forum : Electronics : Microprocessors : Function pointers / function callbacks / function variables

Yes, but everybody knows that you are the Nick who sits at the right hand of God..........

Thanx

Nick... you trying to tell us something ?

"God only knows what a callback function is ..".

What if I don't use an RTC in my project? Can I still change the date and time of the file created to the current date and time?

If you have some other means of getting the date and time, there should be no problem at all.

After reading this thread I successfully implemented timestamps on files written to SD when the clock source is an RTC

But I have a curious bug on another project that uses the (excellent) NeoGPS library for GPS data including GPS time.

When data logging starts the sketch (SCOO8 version r) embeds a current timestamp in the SD filename, for example the file I’ve just created (25th September 2017 at 20:42.33) was correctly named:

SCOO8.r_170925_204233.csv

So the GPS time and the timestamp are working in principle, however the FAT_DATE allocated to the SD file by my code gets the year wrong, showing “25-Sep-65 20:42” in explorer file listing, even though both timestamps use the same year variable (localTime.year) ?

(year variable is uint8_t in NeoGPS and has a range of 0-99, and I’ve separately confirmed it’s value is 17)

Any suggestions ?

here is the “offending” code:

void fatDateTime(uint16_t *date, uint16_t *time) {
  *date = FAT_DATE(localTime.year, localTime.month,  localTime.date);
  *time = FAT_TIME(localTime.hours,localTime.minutes,localTime.seconds);
  }

static void startLogging() {
  if (SD_OK) {
    loggingActive = true;
    strcpy_P( logName, CJ_ID );                           // start filename with sketch name & version identifier
    char timeStamp[15];                                   // "_YYMMDD_HHmmss" + NULL
    sprintf(timeStamp,"_%02d%02d%02d_%02d%02d%02d",
                        localTime.year,
                        localTime.month,
                        localTime.date,
                        localTime.hours,
                        localTime.minutes,
                        localTime.seconds);
    strcat(logName,timeStamp);                            // append time stamp to filename
    strcat(logName,".csv");                               // append .csv to filename
    SdFile::dateTimeCallback(fatDateTime);                // add explorer timestamp when SD file created
    Serial << F("\t\t\t\t\t-->> LOGGING to: <") << logName << F(">\n");
    logfile = SD.open(logName,FILE_WRITE);                // only Open/Close once, not every row
    addLogHeader();
    } 
  else {                                                  // SD not OK
    Serial << F("SD BAD: no logging\n");                  // warn we're not logging
    beep3(); delay(100);                                  // plus many beeps
    beep3(); delay(100);
    beep3();
    }
  } // startLogging

PS: sure it’s redundant having same timestamp appear in filename and explorer file listing, but I have my reasons … :slight_smile:

I think that FAT_DATE takes a 4 digit year. If localTime.year has a value of 17 then try

void fatDateTime(uint16_t *date, uint16_t *time) {
  *date = FAT_DATE((2000 +localTime.year), localTime.month,  localTime.date);
  *time = FAT_TIME(localTime.hours,localTime.minutes,localTime.seconds);
  }

doh ... that works, thanks

but a bit annoying 'cos I thought of 4 digit year before, but somehow got the maths/syntax wrong.

Hello!

I'm trying to log some data using SD.h, but file date is 01.01.2000 01:00. Since I'm using swRTC library, I need to implement my own callback. Following the
example from post #4 it looks like this:

void dateTime(uint16_t* date, uint16_t* time)
{
 // return date using FAT_DATE macro to format fields
 *date = FAT_DATE(rtc.getYear(), rtc.getMonth(), rtc.getDay());
 // return time using FAT_TIME macro to format fields
 *time = FAT_TIME(rtc.getHours(), rtc.getMinutes(), rtc.getSeconds());
}

But still I get "2019.01.26 01:08:37 - 153,155,150" inside the file and same initial date in the file system table.

Also. I can't understand if it's hardware or software bug. If you use SD card and reset Arduino by the button on the board, during next setup() I call SD.begin(4) and it fails until I will physically eject the microSD card, put it again and reset the board. How to avoid this after power fails etc?

According to Serial log, dateTime() is never called by SD library. How to fix it?

1 Like

SD card has its own controller that power off resets.

When the system writing the files just started, does it know the Unix Time to set those files to?

FILE * pFile;

pFile = fopen (“abc.txt” , “r”);

pFile is a FILE object/handle that has a copy of the DOS file info. I downsized my DOS references so sorry I can’t hand you the layout but it’s there including 8.3 filenames.

According to Serial log, dateTime() is never called by SD library. How to fix it?

Can you post an MCVE ("minimal complete verifiable example" of your problem. You have posted a snippet of code and a claim that the callback function is not called by the library. Please give us something more to work with.

Can you run the example in post #4 with RTClib successfully? There is actually a class in RTClib which uses a software RTC and the syntax of the library, and you could test with that and the example code.

Hi all
Ive been experimenting with this bit of code and using cattledog’s first post, I modified it to work with the HCRTC library instead of RTCLib. Here is the code-

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
/* Include the Hobby Components RTC library */
#include <HCRTC.h>

/* The RTC has a fixed address of 0x68 /
#define I2CDS1307Add 0x68
/
DIO pin used to control the SD card CS pin /
//#define SD_CS_DIO 10
File file; // test file
const uint8_t SD_CS = 10; // SD chip select
/
Create an instance of HCRTC library */
HCRTC HCRTC;

char timestamp[30];

//------------------------------------------------------------------------------
// call back for file timestamps
void dateTime(uint16_t* date, uint16_t* time) {
HCRTC.RTCRead(I2CDS1307Add);
sprintf(timestamp, “%02d:%02d:%02d %2d/%2d/%2d \n”, HCRTC.GetHour(),HCRTC.GetMinute(),HCRTC.GetSecond(),HCRTC.GetMonth(),HCRTC.GetDay(),HCRTC.GetYear());
Serial.println(“yy”);
Serial.println(timestamp);
// return date using FAT_DATE macro to format fields
*date = FAT_DATE((HCRTC.GetYear()-48), HCRTC.GetMonth(), HCRTC.GetDay());

// return time using FAT_TIME macro to format fields
*time = FAT_TIME(HCRTC.GetHour(), HCRTC.GetMinute(), HCRTC.GetSecond());
}
//------------------------------------------------------------------------------

void setup() {
// put your setup code here, to run once:

Serial.begin(9600);
Wire.begin();

// set date time callback function
SdFile::dateTimeCallback(dateTime);

HCRTC.RTCRead(I2CDS1307Add);
sprintf(timestamp, “%02d:%02d:%02d %2d/%2d/%2d \n”, HCRTC.GetHour(),HCRTC.GetMinute(),HCRTC.GetSecond(),HCRTC.GetMonth(),HCRTC.GetDay(),HCRTC.GetYear());
Serial.println(“xx”);
Serial.println(timestamp);

if (!SD.begin(SD_CS)) {
Serial.println(“SD.begin failed”);
while(1);
}
SD.remove(“TEST_SD.TXT”);
file = SD.open(“TEST_SD.TXT”, FILE_WRITE);
file.println(“Testing 1,2,3…”);

delay(5000);
file.close();
Serial.println(“Done”);

}

void loop() {
// put your main code here, to run repeatedly:

}


All worked fine except the year on the file stamp was 2068. I’ve no idea why and I fixed it by subtracting 48 from the Macro “*date = FAT_DATE((HCRTC.GetYear()-48), HCRTC.GetMonth(), HCRTC.GetDay());”

Anybody have a clue as to why this happens?

All worked fine except the year on the file stamp was 2068. I've no idea why and I fixed it by subtracting 48 from the Macro "*date = FAT_DATE((HCRTC.GetYear()-48), HCRTC.GetMonth(), HCRTC.GetDay());"

Anybody have a clue as to why this happens?

I think that you are having the same issue as reply#11, with the solution presented in reply #12.

FAT_DATE expects a 4 digit year. Try HCRTC.GetYear() + 2000.

I'm not certain why the correction factor of 48 works, but this is the same offset seen in post #11.