Setting Arduino's date and time?

This could go in the networking forum as it involves the WiFi shield or the storage forum as it involves the SD card... but I thought the fact that it should set the info on the actual Arduino puts it here.

I have the WiFi shield with the built-in SD card unit. Whenever I create a file on the SD card, through the Arduino and the WiFi shield, the date and time of the file creation is set to the standard January 1, 2000 00:00. I have found how to connect to an NTP server and read the current date and time. But how can I set the current date and time on the Arduino for it to use in it's other operations such as file I/O?

Thanks.

Since the SD class doesn't care about the date and time, you have a much bigger job ahead of you than you think. The first thing that you need to do is to make it care.

and the Arduino doesn't have a time or date to set ..........

Mark

http://playground.arduino.cc/Code/Time

If you want the time and date survive a reset, you have to put in a DS1307 RTC (there's a dozen different breakout boards available in usual arduino-friendly online stores)

The Arduino documentation for the SD library covers access to the directory and file content, but not to attributes such as the creation/modification times. As far as I can see, these are supported by the underlying SdFat library so could be read at the SD library interface, but there's no obvious way to set them. I see some code in SdBaseFile.cpp which suggests that the creation and modification times default to 1 Jan 2000 but could be modified if a user-defined function was implemented to look up the local date/time:

    // set timestamps
    if (dateTime_) {
      // call user date/time function
      dateTime_(&p->creationDate, &p->creationTime);
    } else {
      // use default date/time
      p->creationDate = FAT_DEFAULT_DATE;
      p->creationTime = FAT_DEFAULT_TIME;
    }
void (*SdBaseFile::dateTime_)(uint16_t* date, uint16_t* time) = 0;

I haven't noticed any documentation describing how to use this (but then, I haven't looked very hard) but I would guess that if you implement a function with the correct signature and then update dateTime_ to point to that function, it would be invoked when you created/updated a file. This leaves you with the problem of how to find the current date/time, and I expect the usual responses would point you towards an RTC or a network interface and (S)NTP.

DerekErb:
Whenever I create a file on the SD card, through the Arduino and the WiFi shield, the date and time of the file creation is set to the standard January 1, 2000 00:00. I have found how to connect to an NTP server and read the current date and time. But how can I set the current date and time on the Arduino for it to use in it's other operations such as file I/O?

I think the simplest approach is to do your own stamping using a DS1307 clock module. You can use it to name the file and/or include date/time in the data. In my case, the clock is used to create a new file at midnight - 20130102,csv - and thus only the time need be recorded therein.

in preamble:

File myFile;
char filename[] = "00000000.CSV";

in Setup

getFileName();

the condition in the loop:

  if (hour == 0 && minute == 0 && second <2)
  {
    getFileName();
  }

the subroutine:

void getFileName(){

  DateTime now = RTC.now();

  filename[0] = (now.year()/1000)%10 + '0'; //To get 1st digit from year()
  filename[1] = (now.year()/100)%10 + '0'; //To get 2nd digit from year()
  filename[2] = (now.year()/10)%10 + '0'; //To get 3rd digit from year()
  filename[3] = now.year()%10 + '0'; //To get 4th digit from year()
  filename[4] = now.month()/10 + '0'; //To get 1st digit from month()
  filename[5] = now.month()%10 + '0'; //To get 2nd digit from month()
  filename[6] = now.day()/10 + '0'; //To get 1st digit from day()
  filename[7] = now.day()%10 + '0'; //To get 2nd digit from day()

  myFile = SD.open(filename, FILE_WRITE);
  myFile.close();
}

Maybe you could get the same result with your NTP server.

For most of my uses I'm not worried about the date/time surviving a board reset as each of my current and foreseen boards is either Ethernet or WiFi based. I will get the current time, via NTP, in setup() every time the board is reset.

The date and time of the file creation, and modification, are not primordial for me. I just wanted to know where and how to be able to control that for future operations and, most importantly, if it is possible. The date and time recordings I need will be in fields inside my files, mostly CSVs, and that's not a problem as I control that inside the files. But when transferring those files from the SD card to my computers I would prefer it is the last modification date and time were correct.

My next project, as soon as I get some more time, is to start working on moving my SD routines from the SD library to the SdFat library as I already need that to correctly return the amount of space available on the SD card. At that time I'll look in to how to possibly set both the file creation date/time and the file modification date/time ... if it's possible.

Thanks all.

hi there can i ask a question,the DS1307 RTC have battery backup so it doesnt lose the time...but what about hour change?(when clock turn fwd and bckwd) do i have to change the arduino values allways?or is there any way to do it buy it self..thankyou

juycce:
hi there can i ask a question,the DS1307 RTC have battery backup so it doesnt lose the time...but what about hour change?(when clock turn fwd and bckwd) do i have to change the arduino values allways?or is there any way to do it buy it self..thankyou

For my network (NTP) version I always use a timer which reverifies and resets the time. Once every 24 hours, for example, it gets the time from the NTP server and sets the internal clock. The frequency of your timer reset would be based on how much, or little, overhead you want to add to your loop()

For a version which isn't using the network you would have to build-in DST calculations, with additional location-based and timezone-based modifications, in to your code...

juycce:
what about hour change?(when clock turn fwd and bckwd) do i have to change the arduino values allways?

DST is usually only relevant when the time value is rendered for display, and if you're going to support DST you need to provide a way to choose which timezone you're going to render the time for (perhaps hard-coded) and to apply the DST adjustments applicable to that TZ. This is not changing the value of the underlying timestamp (nor the clock that it came from) but just how the date/time value is displayed.

I usually set the RTC to UTC then use this library:
http://arduino.cc/forum/index.php/topic,96891.0.html

github has changed their download process slightly, I'll update the instructions shortly, but it's simple enough, click the ZIP button, then after downloading and un-zipping, rename the folder to just "Timezone".

I've come back here as it seems logical to continue this discussion rather than starting a new thread as I think my current problem is related.

As you can see below I got everything to work as I wanted with my Ethernet Shield and then with my Ethernet Arduino.

Now I'm trying to apply the same principles to a much simpler project: a WiFi smoke detector and thermometer.

Where I am blocking is setting the time for the Arduino. It appears as though my original approach, which worked via Ethernet and Ethernet UDP, isn't going to work with WiFi. I am hoping that someone here is going to tell me that the following thread is dated and this (somehow) works now:

Before anyone asks, and in case it's just a matter of programming, here is an example of the code I am working on:

/*
  WiFi Time Server Test
*/

// Libraries
#include <SPI.h>
#include <WiFi.h>
#include <EthernetUdp.h>
#include <Time.h>

// NTP time stamp from first 48 bytes of the message
const int iNTP_PACKET_SIZE = 48;

// Buffer to hold incoming / outgoing packets
byte byPacketBuffer[iNTP_PACKET_SIZE];

// Previous hour and minute counters
byte byPrevHr = 0;
byte byPrevMin = 0;

// UDP instance
EthernetUDP Udp;

////////////////////////////////////////////////////////
//
// GetNTPTime
//
// Get the time via NTP, adjust for Time Zone and return for synchronisation
//
unsigned long GetNTPTime() {
  // Time Zone (Difference from GMT in seconds)
  const long lTZ = 3600;

  // Time Server fixed IP address (nist1-ny.ustiming.org)
  IPAddress ipTimeServer(64, 90, 182, 55);

  // Set an NTP packet to the NTP time server
  sendNTPpacket(ipTimeServer);
  delay(1000);

  if (Udp.parsePacket()) {  
    // We've received a packet, read the data from it
    Udp.read(byPacketBuffer, iNTP_PACKET_SIZE);

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, extract the two words:
    unsigned long highWord = word(byPacketBuffer[40], byPacketBuffer[41]);
    unsigned long lowWord = word(byPacketBuffer[42], byPacketBuffer[43]);  
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;  

    // now convert NTP time into everyday time:
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL; 
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;
   
    // Adjust for local time zone
    epoch += lTZ;
    
    // Return local time
    return(epoch);
  }
}
  
////////////////////////////////////////////////////////
//
// PrintTime
//
// Serial Print time (DD/MM/YYYY - HH:MM:SS)
//
void PrintTime() {
  char cTime[22];
  
    sprintf(cTime, "%02u/%02u/%4u - %02u:%02u:%02u", day(), month(), year(), hour(), minute(), second());
    Serial.println(cTime);
}

////////////////////////////////////////////////////////
//
// sendNTPpacket
//
// Send an NTP request to the NTP time server at the IP address
//
// 
unsigned long sendNTPpacket(IPAddress& address) {

  // set all bytes in the buffer to 0
  memset(byPacketBuffer, 0, iNTP_PACKET_SIZE); 

  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  byPacketBuffer[0] = 0b11100011;   // LI, Version, Mode
  byPacketBuffer[1] = 0;     // Stratum, or type of clock
  byPacketBuffer[2] = 6;     // Polling Interval
  byPacketBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  byPacketBuffer[12]  = 49; 
  byPacketBuffer[13]  = 0x4E;
  byPacketBuffer[14]  = 49;
  byPacketBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:         
  Udp.beginPacket(address, 123);   //NTP requests are to port 123
  Udp.write(byPacketBuffer, iNTP_PACKET_SIZE);
  Udp.endPacket();
}

//////////////////////////////////////////////////////
//
// WiFiConnect
//
// Establish WiFi connection to network
//
byte WiFiConnect() {
  byte byResult = false;
  // WiFi Network & Password
  char SSID[] = "SSIDHERE";
  char WiFiPass[] = "PASSWORDHERE";
  
  int iWiFiStatus = WL_IDLE_STATUS;     // WiFi radio's status
  byte byAttempt = 0;                   // Attempt counter

  while (iWiFiStatus != WL_CONNECTED) {
    if (byAttempt < 10) {
      byAttempt++;

      // Wait 3 seconds before trying
      delay(3000);

      Serial.print(F("Attempting to connect to WPA network: "));
      Serial.print(SSID);
      Serial.print(F("\nAttempt: "));
      Serial.println(byAttempt);

       // Attempt to connect to WPA network:
      iWiFiStatus = WiFi.begin(SSID, WiFiPass);
  
      if (iWiFiStatus != WL_CONNECTED) {
        byResult = false;

        Serial.println(F("Couldn't establish WiFi connection"));
        
      }
      
      // if connected :
      else {
        byResult = true;
        
        Serial.println(F("WiFi connection established\n"));
      }
    }
    else {
      byResult = 2;    // Too many attempts
    }
  } 
  
  return(byResult);
}


//////////////////////////////////////////////////////
//
// SETUP
//
void setup() {
  // Setup serial monitor
  Serial.begin(9600);
  // Wait 3 seconds
  delay(3000);
  
  Serial.println(F("WiFi Time Test"));
  Serial.println(F("Arduino - Derek Erb\n"));
  
  // Connect to WiFi
  WiFiConnect();

  // Setup time
  Serial.println(F("Waiting for sync...\n"));
  setSyncProvider(GetNTPTime);

  while(timeStatus() == timeNotSet);  // Wait until time set by sync provider

  // Display time
  PrintTime();
  
  // Save current hour and minute as previous hour and minute
  byPrevHr = hour();
  byPrevMin = minute();
}
  
//////////////////////////////////////////////////////
//
// LOOP
//
void loop() {
  
  // Display new time at the start of every minute
  if (byPrevMin != minute()) {
    // Store current minute as new previous minute
    byPrevMin = minute();
    
    // Serial print time
    PrintTime();
  }
}

If not... then how does one go about setting the time (autonomously) in an Arduino with a WiFi shield???

Thanks!