Imported Upstream version 2.9.0
[debian/cc1111] / device / lib / time.c
1 /*-------------------------------------------------------------------------
2   time.c - stdlib time conversion routines
3   
4    Written By - Johan Knol, johan.knol@iduna.nl
5     
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19    
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!  
23 -------------------------------------------------------------------------*/
24
25 #include <stdio.h>
26 #include <time.h>
27
28 // please note that the tm structure has the years since 1900,
29 // but time returns the seconds since 1970
30
31 /* You need some kind of real time clock for the time() function.
32    Either a rtc-chip or some kind of DCF device will do. For TINI, the 
33    HAVE_RTC is defined in tinibios.h
34    If not, the conversion routines still work.
35 */
36
37 #ifndef HAVE_RTC
38 unsigned char RtcRead(struct tm *timeptr) {
39   // no real time hardware 
40   timeptr; // hush the compiler
41   return 0;
42 }
43 #endif
44
45 // return the calendar time, seconds since the Epoch (Jan 1 1970 00:00:00)
46 time_t time(time_t *timeptr) {
47   struct tm now;
48   time_t t=-1;
49
50   if (RtcRead(&now)) {
51     t=mktime(&now);
52   }
53   if (timeptr) {
54     *timeptr=t;
55   }
56   return t;
57 }
58
59 static _CODE char monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31};
60
61 _CODE char * _CODE __month[]={"Jan","Feb","Mar","Apr","May","Jun",
62                               "Jul","Aug","Sep","Oct","Nov","Dec"};
63
64 _CODE char * _CODE __day[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
65
66 static char ascTimeBuffer[32];
67
68 // validate the tm structure
69 static void CheckTime(struct tm *timeptr) {
70     // we could do some normalization here, e.g.
71     // change 40 october to 9 november
72     #if !__TIME_UNSIGNED
73     if (timeptr->tm_sec<0) timeptr->tm_sec=0;
74     if (timeptr->tm_min<0) timeptr->tm_min=0;
75     if (timeptr->tm_hour<0) timeptr->tm_hour=0;
76     if (timeptr->tm_wday<0) timeptr->tm_wday=0;
77     if (timeptr->tm_mon<0) timeptr->tm_mon=0;
78     #endif
79     
80     if (timeptr->tm_sec>59) timeptr->tm_sec=59;
81     if (timeptr->tm_min>59) timeptr->tm_min=59;
82     if (timeptr->tm_hour>23) timeptr->tm_hour=23;
83     if (timeptr->tm_wday>6) timeptr->tm_wday=6;
84     if (timeptr->tm_mday<1) timeptr->tm_mday=1;
85     else if (timeptr->tm_mday>31) timeptr->tm_mday=31;
86     if (timeptr->tm_mon>11) timeptr->tm_mon=11;
87     if (timeptr->tm_year<0) timeptr->tm_year=0;
88 }
89
90 // format the time into "Sat Feb 17 17:45:23 2001\n"
91 char *asctime(struct tm *timeptr) {
92   CheckTime(timeptr);
93   sprintf (ascTimeBuffer, "%s %s %2d %02d:%02d:%02d %04d\n",
94            __day[timeptr->tm_wday], __month[timeptr->tm_mon], timeptr->tm_mday,
95            timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec, 
96            timeptr->tm_year+1900);
97   return ascTimeBuffer;
98 }
99
100 char *ctime(time_t *timep) {
101   return asctime(localtime(timep));
102 }
103
104 static struct tm lastTime;
105
106 /* convert calendar time (seconds since 1970) to broken-time
107    This only works for dates between 01-01-1970 00:00:00 and 
108    19-01-2038 03:14:07
109
110    A leap year is ((((year%4)==0) && ((year%100)!=0)) || ((year%400)==0)) 
111    but since we have no fancy years between 1970 and 2038 we can do:
112 */
113
114 #define LEAP_YEAR(year) ((year%4)==0)
115
116 // forget about timezones for now
117 struct tm *localtime(time_t *timep) {
118     return gmtime(timep);
119 }
120
121 struct tm *gmtime(time_t *timep) {
122   unsigned long epoch=*timep;
123   unsigned int year;
124   unsigned char month, monthLength;
125   unsigned long days;
126   
127   lastTime.tm_sec=epoch%60;
128   epoch/=60; // now it is minutes
129   lastTime.tm_min=epoch%60;
130   epoch/=60; // now it is hours
131   lastTime.tm_hour=epoch%24;
132   epoch/=24; // now it is days
133   lastTime.tm_wday=(epoch+4)%7;
134   
135   year=1970;
136   days=0;
137   while((days += (LEAP_YEAR(year) ? 366 : 365)) <= epoch) {
138     year++;
139   }
140   lastTime.tm_year=year-1900;
141   
142   days -= LEAP_YEAR(year) ? 366 : 365;
143   epoch -= days; // now it is days in this year, starting at 0
144   lastTime.tm_yday=epoch;
145   
146   days=0;
147   month=0;
148   monthLength=0;
149   for (month=0; month<12; month++) {
150     if (month==1) { // februari
151       if (LEAP_YEAR(year)) {
152         monthLength=29;
153       } else {
154         monthLength=28;
155       }
156     } else {
157       monthLength = monthDays[month];
158     }
159     
160     if (epoch>=monthLength) {
161       epoch-=monthLength;
162     } else {
163         break;
164     }
165   }
166   lastTime.tm_mon=month;
167   lastTime.tm_mday=epoch+1;
168   
169   lastTime.tm_isdst=0;
170   
171   return &lastTime;
172 }
173
174 // convert broken time to calendar time (seconds since 1970)
175 time_t mktime(struct tm *timeptr) {
176     int year=timeptr->tm_year+1900, month=timeptr->tm_mon, i;
177     long seconds;
178     
179     CheckTime(timeptr);
180
181     // seconds from 1970 till 1 jan 00:00:00 this year
182     seconds= (year-1970)*(60*60*24L*365);
183
184     // add extra days for leap years
185     for (i=1970; i<year; i++) {
186         if (LEAP_YEAR(i)) {
187             seconds+= 60*60*24L;
188         }
189     }
190
191     // add days for this year
192     for (i=0; i<month; i++) {
193       if (i==1 && LEAP_YEAR(year)) { 
194         seconds+= 60*60*24L*29;
195       } else {
196         seconds+= 60*60*24L*monthDays[i];
197       }
198     }
199
200     seconds+= (timeptr->tm_mday-1)*60*60*24L;
201     seconds+= timeptr->tm_hour*60*60L;
202     seconds+= timeptr->tm_min*60;
203     seconds+= timeptr->tm_sec;
204     return seconds;
205 }
206