time.c - low level time and date functions
Copyright (c) Michael Margolis 2009-2014
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1.0 6 Jan 2010 - initial release
1.1 12 Feb 2010 - fixed leap year calculation error
1.2 1 Nov 2010 - fixed setTime bug (thanks to Korman for this)
1.3 24 Mar 2012 - many edits by Paul Stoffregen: fixed timeStatus() to update
status, updated examples for Arduino 1.0, fixed ARM
compatibility issues, added TimeArduinoDue and TimeTeensy3
examples, add error checking and messages to RTC examples,
add examples to DS1307RTC library.
1.4 5 Sep 2014 - compatibility with Arduino 1.5.7
*/
#ifdef ARDUINO
# if ARDUINO >= 100
# include <Arduino.h>
# else
# include <WProgram.h>
# endif
#else
# include "lvgl/lvgl.h"
# define millis() lv_tick_get()
#endif
#include "Time.h"
static tmElements_t g_tm;
static time_t g_cacheTime;
static uint32_t g_syncInterval = 300;
void refreshCache(time_t t) {
if (t != g_cacheTime) {
breakTime(t, g_tm);
g_cacheTime = t;
}
}
int hour() {
return hour(now());
}
int hour(time_t t) {
refreshCache(t);
return g_tm.Hour;
}
int hourFormat12() {
return hourFormat12(now());
}
int hourFormat12(time_t t) {
refreshCache(t);
if( g_tm.Hour == 0 )
return 12;
else if( g_tm.Hour > 12)
return g_tm.Hour - 12 ;
else
return g_tm.Hour ;
}
uint8_t isAM() {
return !isPM(now());
}
uint8_t isAM(time_t t) {
return !isPM(t);
}
uint8_t isPM() {
return isPM(now());
}
uint8_t isPM(time_t t) {
return (hour(t) >= 12);
}
int minute() {
return minute(now());
}
int minute(time_t t) {
refreshCache(t);
return g_tm.Minute;
}
int second() {
return second(now());
}
int second(time_t t) {
refreshCache(t);
return g_tm.Second;
}
int day(){
return(day(now()));
}
int day(time_t t) {
refreshCache(t);
return g_tm.Day;
}
int weekday() {
return weekday(now());
}
int weekday(time_t t) {
refreshCache(t);
return g_tm.Wday;
}
int month(){
return month(now());
}
int month(time_t t) {
refreshCache(t);
return g_tm.Month;
}
int year() {
return year(now());
}
int year(time_t t) {
refreshCache(t);
return tmYearToCalendar(g_tm.Year);
}
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31};
void breakTime(time_t timeInput, tmElements_t &tm){
uint8_t year;
uint8_t month, monthLength;
uint32_t time;
unsigned long days;
time = (uint32_t)timeInput;
tm.Second = time % 60;
time /= 60;
tm.Minute = time % 60;
time /= 60;
tm.Hour = time % 24;
time /= 24;
tm.Wday = ((time + 4) % 7) + 1;
year = 0;
days = 0;
while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
year++;
}
tm.Year = year;
days -= LEAP_YEAR(year) ? 366 : 365;
time -= days;
days=0;
month=0;
monthLength=0;
for (month=0; month<12; month++) {
if (month==1) {
if (LEAP_YEAR(year)) {
monthLength=29;
} else {
monthLength=28;
}
} else {
monthLength = monthDays[month];
}
if (time >= monthLength) {
time -= monthLength;
} else {
break;
}
}
tm.Month = month + 1;
tm.Day = time + 1;
}
time_t makeTime(tmElements_t &tm){
int i;
uint32_t seconds;
seconds= tm.Year*(SECS_PER_DAY * 365);
for (i = 0; i < tm.Year; i++) {
if (LEAP_YEAR(i)) {
seconds += SECS_PER_DAY;
}
}
for (i = 1; i < tm.Month; i++) {
if ( (i == 2) && LEAP_YEAR(tm.Year)) {
seconds += SECS_PER_DAY * 29;
} else {
seconds += SECS_PER_DAY * monthDays[i-1];
}
}
seconds+= (tm.Day-1) * SECS_PER_DAY;
seconds+= tm.Hour * SECS_PER_HOUR;
seconds+= tm.Minute * SECS_PER_MIN;
seconds+= tm.Second;
return (time_t)seconds;
}
static uint32_t sysTime = 0;
static uint32_t prevMillis = 0;
static uint32_t nextSyncTime = 0;
static timeStatus_t Status = timeNotSet;
getExternalTime getTimePtr;
#ifdef TIME_DRIFT_INFO
time_t sysUnsyncedTime = 0;
#endif
time_t now() {
while (millis() - prevMillis >= 1000) {
sysTime++;
prevMillis += 1000;
#ifdef TIME_DRIFT_INFO
sysUnsyncedTime++;
#endif
}
if (nextSyncTime <= sysTime) {
if (getTimePtr != 0) {
time_t t = getTimePtr();
if (t != 0) {
setTime(t);
} else {
nextSyncTime = sysTime + g_syncInterval;
Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync;
}
}
}
return (time_t)sysTime;
}
void setTime(time_t t) {
#ifdef TIME_DRIFT_INFO
if(sysUnsyncedTime == 0)
sysUnsyncedTime = t;
#endif
sysTime = (uint32_t)t;
nextSyncTime = (uint32_t)t + g_syncInterval;
Status = timeSet;
prevMillis = millis();
}
void setTime(int hr,int min,int sec,int dy, int mnth, int yr){
if( yr > 99)
yr = yr - 1970;
else
yr += 30;
g_tm.Year = yr;
g_tm.Month = mnth;
g_tm.Day = dy;
g_tm.Hour = hr;
g_tm.Minute = min;
g_tm.Second = sec;
setTime(makeTime(g_tm));
}
void adjustTime(long adjustment) {
sysTime += adjustment;
}
timeStatus_t timeStatus() {
now();
return Status;
}
void setSyncProvider( getExternalTime getTimeFunction){
getTimePtr = getTimeFunction;
nextSyncTime = sysTime;
now();
}
void setSyncInterval(time_t interval){
g_syncInterval = (uint32_t)interval;
nextSyncTime = sysTime + g_syncInterval;
}