]> git.piffa.net Git - arduino/blob - books/pdummies/Libraries/Time/Time.cpp
first commit
[arduino] / books / pdummies / Libraries / Time / Time.cpp
1 /*
2   time.c - low level time and date functions
3   Copyright (c) Michael Margolis 2009
4
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19   6  Jan 2010 - initial release
20   12 Feb 2010 - fixed leap year calculation error
21   1  Nov 2010 - fixed setTime bug (thanks to Korman for this)
22 */
23
24 #if defined(ARDUINO) && ARDUINO >= 100
25 #include "Arduino.h"
26 #else
27 #include "WProgram.h"
28 #endif
29
30 #include "Time.h"
31
32 static tmElements_t tm;          // a cache of time elements
33 static time_t       cacheTime;   // the time the cache was updated
34 static time_t       syncInterval = 300;  // time sync will be attempted after this many seconds
35
36 void refreshCache( time_t t){
37   if( t != cacheTime)
38   {
39     breakTime(t, tm);
40     cacheTime = t;
41   }
42 }
43
44 int hour() { // the hour now
45   return hour(now());
46 }
47
48 int hour(time_t t) { // the hour for the given time
49   refreshCache(t);
50   return tm.Hour;
51 }
52
53 int hourFormat12() { // the hour now in 12 hour format
54   return hourFormat12(now());
55 }
56
57 int hourFormat12(time_t t) { // the hour for the given time in 12 hour format
58   refreshCache(t);
59   if( tm.Hour == 0 )
60     return 12; // 12 midnight
61   else if( tm.Hour  > 12)
62     return tm.Hour - 12 ;
63   else
64     return tm.Hour ;
65 }
66
67 uint8_t isAM() { // returns true if time now is AM
68   return !isPM(now());
69 }
70
71 uint8_t isAM(time_t t) { // returns true if given time is AM
72   return !isPM(t);
73 }
74
75 uint8_t isPM() { // returns true if PM
76   return isPM(now());
77 }
78
79 uint8_t isPM(time_t t) { // returns true if PM
80   return (hour(t) >= 12);
81 }
82
83 int minute() {
84   return minute(now());
85 }
86
87 int minute(time_t t) { // the minute for the given time
88   refreshCache(t);
89   return tm.Minute;
90 }
91
92 int second() {
93   return second(now());
94 }
95
96 int second(time_t t) {  // the second for the given time
97   refreshCache(t);
98   return tm.Second;
99 }
100
101 int day(){
102   return(day(now()));
103 }
104
105 int day(time_t t) { // the day for the given time (0-6)
106   refreshCache(t);
107   return tm.Day;
108 }
109
110 int weekday() {   // Sunday is day 1
111   return  weekday(now());
112 }
113
114 int weekday(time_t t) {
115   refreshCache(t);
116   return tm.Wday;
117 }
118
119 int month(){
120   return month(now());
121 }
122
123 int month(time_t t) {  // the month for the given time
124   refreshCache(t);
125   return tm.Month;
126 }
127
128 int year() {  // as in Processing, the full four digit year: (2009, 2010 etc)
129   return year(now());
130 }
131
132 int year(time_t t) { // the year for the given time
133   refreshCache(t);
134   return tmYearToCalendar(tm.Year);
135 }
136
137 /*============================================================================*/
138 /* functions to convert to and from system time */
139 /* These are for interfacing with time serivces and are not normally needed in a sketch */
140
141 // leap year calulator expects year argument as years offset from 1970
142 #define LEAP_YEAR(Y)     ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
143
144 static  const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0\r
145
146 void breakTime(time_t time, tmElements_t &tm){
147 // break the given time_t into time components
148 // this is a more compact version of the C library localtime function
149 // note that year is offset from 1970 !!!
150
151   uint8_t year;
152   uint8_t month, monthLength;
153   unsigned long days;
154
155   tm.Second = time % 60;
156   time /= 60; // now it is minutes
157   tm.Minute = time % 60;
158   time /= 60; // now it is hours
159   tm.Hour = time % 24;
160   time /= 24; // now it is days
161   tm.Wday = ((time + 4) % 7) + 1;  // Sunday is day 1
162
163   year = 0;
164   days = 0;
165   while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
166     year++;
167   }
168   tm.Year = year; // year is offset from 1970
169
170   days -= LEAP_YEAR(year) ? 366 : 365;
171   time  -= days; // now it is days in this year, starting at 0
172
173   days=0;
174   month=0;
175   monthLength=0;
176   for (month=0; month<12; month++) {
177     if (month==1) { // february
178       if (LEAP_YEAR(year)) {
179         monthLength=29;
180       } else {
181         monthLength=28;
182       }
183     } else {
184       monthLength = monthDays[month];
185     }
186
187     if (time >= monthLength) {
188       time -= monthLength;
189     } else {
190         break;
191     }
192   }
193   tm.Month = month + 1;  // jan is month 1
194   tm.Day = time + 1;     // day of month
195 }
196
197 time_t makeTime(tmElements_t &tm){
198 // assemble time elements into time_t
199 // note year argument is offset from 1970 (see macros in time.h to convert to other formats)
200 // previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9
201
202   int i;
203   time_t seconds;
204
205   // seconds from 1970 till 1 jan 00:00:00 of the given year
206   seconds= tm.Year*(SECS_PER_DAY * 365);
207   for (i = 0; i < tm.Year; i++) {
208     if (LEAP_YEAR(i)) {
209       seconds +=  SECS_PER_DAY;   // add extra days for leap years
210     }
211   }
212
213   // add days for this year, months start from 1
214   for (i = 1; i < tm.Month; i++) {
215     if ( (i == 2) && LEAP_YEAR(tm.Year)) {
216       seconds += SECS_PER_DAY * 29;
217     } else {
218       seconds += SECS_PER_DAY * monthDays[i-1];  //monthDay array starts from 0
219     }
220   }
221   seconds+= (tm.Day-1) * SECS_PER_DAY;
222   seconds+= tm.Hour * SECS_PER_HOUR;
223   seconds+= tm.Minute * SECS_PER_MIN;
224   seconds+= tm.Second;
225   return seconds;
226 }
227 /*=====================================================*/
228 /* Low level system time functions  */
229
230 static time_t sysTime = 0;
231 static time_t prevMillis = 0;
232 static time_t nextSyncTime = 0;
233 static timeStatus_t Status = timeNotSet;
234
235 getExternalTime getTimePtr;  // pointer to external sync function
236 //setExternalTime setTimePtr; // not used in this version
237
238 #ifdef TIME_DRIFT_INFO   // define this to get drift data
239 time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync
240 #endif
241
242
243 time_t now(){
244   while( millis() - prevMillis >= 1000){
245     sysTime++;
246     prevMillis += 1000;
247 #ifdef TIME_DRIFT_INFO
248     sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift
249 #endif
250   }
251   if(nextSyncTime <= sysTime){
252         if(getTimePtr != 0){
253           time_t t = getTimePtr();
254       if( t != 0)
255         setTime(t);
256       else
257         Status = (Status == timeNotSet) ?  timeNotSet : timeNeedsSync;
258     }
259   }
260   return sysTime;
261 }
262
263 void setTime(time_t t){
264 #ifdef TIME_DRIFT_INFO
265  if(sysUnsyncedTime == 0)
266    sysUnsyncedTime = t;   // store the time of the first call to set a valid Time
267 #endif
268
269   sysTime = t;
270   nextSyncTime = t + syncInterval;
271   Status = timeSet;
272   prevMillis = millis();  // restart counting from now (thanks to Korman for this fix)
273 }
274
275 void  setTime(int hr,int min,int sec,int dy, int mnth, int yr){
276  // year can be given as full four digit year or two digts (2010 or 10 for 2010);
277  //it is converted to years since 1970
278   if( yr > 99)
279       yr = yr - 1970;
280   else
281       yr += 30;
282   tm.Year = yr;
283   tm.Month = mnth;
284   tm.Day = dy;
285   tm.Hour = hr;
286   tm.Minute = min;
287   tm.Second = sec;
288   setTime(makeTime(tm));
289 }
290
291 void adjustTime(long adjustment){
292   sysTime += adjustment;
293 }
294
295 timeStatus_t timeStatus(){ // indicates if time has been set and recently synchronized
296   return Status;
297 }
298
299 void setSyncProvider( getExternalTime getTimeFunction){
300   getTimePtr = getTimeFunction;
301   nextSyncTime = sysTime;
302   now(); // this will sync the clock
303 }
304
305 void setSyncInterval(time_t interval){ // set the number of seconds between re-sync
306   syncInterval = interval;
307 }