uint32_t getDaysSinceEpoch(const struct tm& timeInfo) {
int year = timeInfo.tm_year + 1900;
int month = timeInfo.tm_mon + 1;
int day = timeInfo.tm_mday;
// Calculate number of days since January 1st, 0 AD
int a = (14 - month) / 12;
int y = year + 4800 - a;
int m = month + 12 * a - 3;
uint32_t days = day + (153ul * m + 2) / 5 + 365ul * y + y / 4ul - y / 100ul + y / 400ul - 32045ul;
return days;
}
uint32_t getSecondsSinceMidnight(const struct tm& timeInfo) {
int hour = timeInfo.tm_hour;
int minute = timeInfo.tm_min;
int second = timeInfo.tm_sec;
uint32_t seconds = hour * 3600ul + minute * 60ul + second;
return seconds;
}
(see this post to get the time from an NTP server)
The calendar that's in use in most of the world doesn't have a year zero, not AD or BC. That's because it was established when Roman numerals were the way people counted, and they had no zero but always started a count with 1.
If you have a look at e.g. a thermometer then you find a point of zero degrees, but the range around that point extends to either +1 or -1 degrees. Likewise a year at the calendar origin will extend to +1 or -1, the first year after or before Christ. See AD = p.C.n in wikipedia.
But the science and astronomy knowledge / maths behind the Gregorian calendars is fascinating.
It was a bold move to decide to get 10 days forward in one night (The Julian calendar day Thursday, 4 October 1582 was followed by the first day of the Gregorian calendar, Friday, 15 October 1582) a decision that was applied over the globe at different moment due to the religious connotation of the decision.
Integral time values in computer programs and/or RTC chips traditionally started at a random date, like 1900 or 1970. Unsigned numbers prevent handling of dates before that starting point. Consequently dates are exchangable across programs/systems only in verbose y/m/d form, not in day numbers.
struct tm timeInfo;
int year = timeInfo.tm_year + 1900;
int month = timeInfo.tm_mon + 1;
int day = timeInfo.tm_mday;
// Calculate number of days since January 1st, 0 AD
int a = (14 - month) / 12;
int y = year + 4800 - a;
int m = month + 12 * a - 3;
uint32_t days = day + (153 * m + 2) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 32045;
log_i("%d/%d/%d", day, month, year);
log_i("Days %d\n", days);
In chronology and periodization, an epoch or reference epoch is an instant in time chosen as the origin of a particular calendar era. The "epoch" serves as a reference point from which time is measured.
The formula I provided is used to calculate the Julian Day Number (JDN) for a given date in the Gregorian calendar. The JDN represents the number of days since noon on January 1, 4713 BCE (start of the Julian date calendar).
âžś This formula can be used to convert a date to the JDN format
if you want the number of days since January 1st, 0001 you need to subtract from the JDN you calculate for the chosen date the JDN for 1/1/1 which is a constant since both dates are known = 1 721 426
the formula would be then
unsigned long days = day + ((153ul * m + 2) / 5) + (365ul * y) + (y / 4ul) - (y / 100ul) + y / 400ul - 32045ul - 1721426ul;
here is a code example for ESP32 that will give you 738714
#include <WiFi.h>
#include "time.h"
const char * ssid = "xxx";
const char * wifipw = "xxx";
void setTimezone(const char * timezone) {
Serial.print("Setting Timezone to ");
Serial.println(timezone);
setenv("TZ", timezone, 1);
tzset();
}
void initTime(const char * timezone) {
struct tm timeinfo;
Serial.println("Getting time from NTP server");
configTime(0, 0, "pool.ntp.org"); // First connect to NTP server, use 0 TZ offset
if (!getLocalTime(&timeinfo)) {
Serial.println(" Failed to obtain time");
return;
}
Serial.println("OK, Got the time from NTP");
setTimezone(timezone); // then set your timezone
}
void printLocalTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("printLocalTime: Failed to obtain time");
return;
}
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S zone %Z %z ");
}
// Calculate number of days since January 1st, 1 AD
unsigned long getDaysSinceFirstDay(const struct tm& timeInfo) {
unsigned long year = timeInfo.tm_year + 1900;
unsigned short month = timeInfo.tm_mon + 1;
unsigned short day = timeInfo.tm_mday;
unsigned short a = (14 - month) / 12;
unsigned short y = year + 4800 - a;
unsigned short m = month + 12 * a - 3;
unsigned long days = day + ((153ul * m + 2) / 5) + (365ul * y) + (y / 4ul) - (y / 100ul) + y / 400ul - 32045ul - 1721426ul; return days;
}
unsigned long getSecondsSinceMidnight(const struct tm& timeInfo) {
unsigned short hour = timeInfo.tm_hour;
unsigned short minute = timeInfo.tm_min;
unsigned short second = timeInfo.tm_sec;
unsigned long seconds = hour * 3600ul + minute * 60ul + second;
return seconds;
}
void printSetVerificationTimeInfo() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("printSetVerificationTimeInfo: Failed to obtain time");
return;
}
Serial.print("Now : "); printLocalTime();
unsigned long daysSinceFirstDay = getDaysSinceFirstDay(timeinfo);
unsigned long secondsSinceMidnight = getSecondsSinceMidnight(timeinfo);
Serial.print("Days since Jan 1, 0001: "); Serial.println(daysSinceFirstDay);
Serial.print("Seconds since midnight: "); Serial.println(secondsSinceMidnight);
}
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
WiFi.begin(ssid, wifipw);
Serial.println("Connecting Wifi");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("\nWifi OK");
// find your TZ string in https://sites.google.com/a/usapiens.com/opnode/time-zones
initTime("CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00"); // France
}
void loop() {
printSetVerificationTimeInfo();
Serial.println();
delay(5000);
}
say we are Wednesday - how many days ago was Monday?
easy enough : Monday - Tuesday - Wednesday
some people will say it was 2 days ago but from a time elapsed perspective at the end of Wednesday you are three days (3 x 24h) away from the start of Monday
âžś it depends if you count the current day or not