time() function

I am writing some library (class) where some methods may calls standard time() function.
How "heavy" is this function? If my methods will be called often, multiple times per second, should I do caching of time() function, or it is already cashed internally?

time()?

Is this an RTC library function or ... ?

No, it is core function, not a library function. Does not require any include.
Actually, it is NTP related function, see example below, first line in the loop().

//minimal sketch providing NTP time sync with automatically switching between summer-winter time (DST)

#include <ESP8266WiFi.h>

//put your WiFi credentials here
const char* ssid = "********";
const char* password = "************";

#define MYTZ "EST5EDT,M3.2.0,M11.1.0"  //for New York, automatically consider DST change
//more codes here: https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("\nConnecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  configTime(MYTZ, "pool.ntp.org", "time.nist.gov");
}

void loop() {
  time_t now = time(nullptr);  // <----------- here!
  Serial.println(ctime(&now));
  delay(1000);
}

Ah, okay. An NTP request makes sense.

SergeS:
I am writing some library (class) where some methods may calls standard time() function.
How "heavy" is this function? If my methods will be called often, multiple times per second, should I do caching of time() function, or it is already cashed internally?

"standard time() function".
Well it depends on what you mean by that.
I'm assuming you mean the unix time() function which is one of the unix time functions, like asctime, strftime, ctime, gmtime, localtime, mktime, asctime_r, ctime_r, gmtime_r, localtime_r that are provided by the GNU tools that came with the compiler tools.
Many Arduino platforms now come with them, but most Arduino users are unware of them much less know how to use them.

If the time library is properly implemented, a call to time() should be very very light as it simply returns the time_t integer, which is the the UTC based time_t epoch seconds value.
There is nothing to do in the time() function but grab the integer and return it.
The heavy portion is the conversion from a time_t value to a local time broken down into human elements by calling something like strftime(), asctime() or localtime()
How often that needs to be done varies depending on the application.

Alas, many arduino based time libraries screw it up so it really depends on which library functions are you using.

Another thing to be aware of is the Y2k38 issue.

as that is now just a bit over 17 years away.
Y2K38 is MUCH bigger issue than Y2K ever was.

The AVR time library functions in newer AVR libc versions went beyond just switching to an unsigned 32 bit value to get around the 2038 issue.
They also changed the epoch to Jan 1, 2000. This is a big mistake IMO, but that gets them 30 years beyond 2106.

The esp8266, and esp32 both currently will break in 2038.
The only platform that I know that uses 64 bit time_t values is STM platform.

The only platform that I know of that supports the full time library functions which includes the ability to set a POSIX TZ string for local time DST conversions is the esp8266 platform.
It is trivial to set up NTP and the TZ string to get background timekeeping going and have proper local time conversions when you need them - including with DST adjustments.

While several other platforms may have some of the unix time functions, I've not seen any other platform that works properly for local time adjustments. esp32 is close but still has a few issues vs the esp8266 platform.

--- bill

Ok, thank you for good information.
But what about my question? Should I cache it in my class, or do not bother, it is already cashed?

p.s. Ok, read your explanation more carefully, seems like time() should be very light. thank you, will not cache it.

  configTime(MYTZ, "pool.ntp.org", "time.nist.gov");

cool.
I had only seen the older version of configTime() that was:

configTime(int timezone_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3)

and it never worked. It totally broke the conversions.
I had been manually setting the TZ variable using setenv() but the new configTime() makes it even easier to use TZ strings.

--- bill

bperrybap:

  configTime(MYTZ, "pool.ntp.org", "time.nist.gov");

cool.
I had only seen the older version of configTime() that was:

configTime(int timezone_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3)

and it never worked. It totally broke the conversions.
I had been manually setting the TZ variable using setenv() but the new configTime() makes it even easier to use TZ strings.

--- bill

bperrybap:

  configTime(MYTZ, "pool.ntp.org", "time.nist.gov");

cool.
I had only seen the older version of configTime() that was:

configTime(int timezone_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3)

and it never worked. It totally broke the conversions.
I had been manually setting the TZ variable using setenv() but the new configTime() makes it even easier to use TZ strings.

--- bill

Yep, I had been also recently surprised.

SergeS:
Ok, thank you for good information.
But what about my question? Should I cache it in my class, or do not bother, it is already cashed?

p.s. Ok, read your explanation more carefully, seems like time() should be very light. thank you, will not cache it.

I wouldn't. Caching variables from system libraries is only need when dealing with crappy implementations.
The esp8266 stuff is pretty good.

I just went to look at the actual code.
Here is the actual code from the esp8266 core library:

time_t time(time_t * t)
{
    time_t currentTime_s = (micros64() + timeshift64) / 1000000ULL;
    if (t)
    {
        *t = currentTime_s;
    }
    return currentTime_s;
}

Not quite as light as what I was thinking, but it is still fairly light.

In the old unix days there was an ISR that bumped an integer to keep track of the time_t
the time() function just returned that counter.
And in fact in the REALLY old days, the resolution of time_t was not fixed in seconds.
You had use the symbol HZ to determine the actual tick resolution.
In the early days the AC line was used to generate a 60hz interrupt clock so the HZ was originally 60.

--- bill

Hi,
It took me a lot of time to get timing running properly.
That’s why I’m adding my code to save you time handling time.
It’s heavily documented.
The main difference between using NTPclient.h library and this code is that NTPclient.h relies on a 60 seconds WiFi call which in fact isn’t needed.
The time functions inside ESP8266 do handle time connections all by itself as soon as WiFi connection is there.
You can leave your ESP8266 disconnected from WiFi for a year and end up with just a bit of time difference.
Does that matter? We don’t launch missiles don’t we.

Here’s the code.

/*
https://github.com/avaldebe/UxTClib/issues/4

This first Serial Monitor dump is to show the output when connection to a time server fails.
The second attempt connects.

15:10:19.819 -> 
15:10:19.819 -> Connecting to YOUR_SSID
15:10:20.382 -> ........
15:10:24.701 -> WiFi connected.
15:10:24.701 -> IP Address : 
15:10:24.701 -> 192.168.x.x
15:10:24.701 -> 1 - Current local time and date: Thu Jan  1 01:00:04 1970
15:10:24.701 -> 
15:10:24.701 -> Restart..
15:10:30.822 -> 
15:10:30.822 ->  ets Jan  8 2013,rst cause:2, boot mode:(3,6)
15:10:30.822 -> 
15:10:30.822 -> load 0x4010f000, len 3584, room 16 
15:10:30.822 -> tail 0
15:10:30.822 -> chksum 0xb0
15:10:30.822 -> csum 0xb0
15:10:30.822 -> v2843a5ac
15:10:30.822 -> ~ld
15:10:30.891 -> 
15:10:30.891 -> 
15:10:30.891 -> Connecting to YOUR_SSID
15:10:31.423 -> ........
15:10:35.738 -> WiFi connected.
15:10:35.738 -> IP Address : 
15:10:35.738 -> 192.168.x.x
15:10:35.738 -> 1 - Current local time and date: Wed Dec 16 15:10:35 2020
15:10:35.738 -> 
15:10:41.715 -> Disconnect WiFi
15:10:41.762 -> 
15:10:42.850 -> WiFi disconnetecd

*/

#include <ESP8266WiFi.h>
#include <time.h>


// login to WiFi network
const char* ssid       = "YOUR_SSID";
const char* password   = "your_password";

// timeframe setup
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 3600;
const int   daylightOffset_sec = 3600;

// ESP's own clock sync setting
// showing howto create your own 'cron'
int day_of_month = 1;
int hour = 1;
int minute = 1;

// buffer needed to store time data
char buffer[60];

void setup(){
  Serial.begin(115200);
  delay(1000);   // delay to wait for serial connection 
  // if delay() is omitted the first lines on the Serial Monitor won't be visible
  Serial.println("");
  Serial.println("Startup sequence visualised");
  Serial.println("");
  
  // Init and get the time. Works like magic
  // We do this BEFORE connecting to WiFi so that the magic will happen
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  setenv("TZ","CET-1CEST-2,M3.5.0,M10.5.0/3,1",1);
  
  // Connect to Wi-Fi
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP Address : ");
  Serial.print(WiFi.localIP());
  Serial.println("");

  // check if current time is fetched from NTP server
  // Year in 'C' language is calculated since 1900
  // Epoch time is calculated since 01/01/1970 00:00:00
  // If no time is obtained from NTP server then time will be set at 01/01/1970 00:00:00
  time_t now = time(nullptr);
  struct tm * timeinfo;
  //time (&now);
  timeinfo = localtime(&now);
  printf ("Current local time and date: %s\n", asctime(timeinfo));
  if(timeinfo->tm_year == 70){     // == number of years since 1900, 70 means no time obtained from NTP server
    Serial.println("Restart..");
    delay(6000);
    ESP.restart();
  }
  
  // delay not needed at all, just for the view on the monitor
  delay(6000);
  
  // Disconnect WiFi as it's no longer needed
  // ESP8266 can managa time without being connected to WiFi
  Serial.println("Disconnecting WiFi");
  Serial.println("");
  delay(1000);
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  Serial.println("WiFi disconnected");
  Serial.println("");
}

void loop(){
  // declare struct tm explained at: https://cpp.hotexamples.com/examples/-/-/localtime_s/cpp-localtime_s-function-examples.html
  time_t now = time(nullptr);
  struct tm * timeinfo;
  // time (&now); // not necessary
  timeinfo = localtime(&now);

  // below several approaches to time are displayed to help you get insight
  // spaces in this code are for ease of maintaining alignment in the monitor output
  printf(                 "1 - Current local time : %s\n", asctime(timeinfo));
  Serial.println((String) "2 - Years since 1900   : "+timeinfo->tm_year); // from the time structure
  // printf prints the data
  // sprintf stores the data in a variable buffer[60] which is declared while initiating this script
  sprintf(buffer,         "3 - The time is        : %02d:%02d:%02d  %04d\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, timeinfo->tm_year+1900);
  Serial.println(buffer);
  Serial.println((String) "4 - ctime(&now)        : "+ctime(&now));
  Serial.println((String) "6 - time(&now)         : "+time(&now)); //The Unix epoch (or Unix time or POSIX time or Unix timestamp) 
  Serial.println("*************************************************");

  // To sync time the device is restarted once a month (in this example)
  // This code can be omitted by simply unplugging the device every now and then 
  // Here's the CRON I promised
  if((timeinfo->tm_mday == day_of_month) && (timeinfo->tm_hour == hour) && (timeinfo->tm_min == minute) && (timeinfo->tm_sec >= 50 )){     // restart to sync time with NTP server
    Serial.println("Restarting..");
    delay(6000);
    ESP.restart();
  }
  // timeinfo->tm_sec >= 50 is introduced together with delay(6000) to prevent another restart within the same minute
  delay(6000);
}

Enjoy!

PS
If you want to make a time trip go strftime - C++ Reference

The AVR Time library implementation can also be made to handle time zone and DST, but IIRC it lacks the TZ implementation. Instead, for DST offset you provide a callback function, or use the USA or EU version provided. Those are very generic, lots of time zones would need a local version to be written. In spite of the slight awkwardness of it, I found that it was simpler than utilizing both the Arduino DateTime library and the TimeZone library together in a sketch.

The ESP8266 version also offers automatic background NTP synchronization, which is a distinct advantage. It makes a versatile, working time sketch in very little code. When you use the DateTime library alone, you don't get any of that. It's up to you to provide the time reference. I wrote a LED clock for ESP32 recently. I have done those for other architectures. The code was at least 5 times smaller than those, and also easier to follow. Mostly display routines.

My point, use AVR time stuff for AVR, and ESP time stuff for ESP.