]> git.sur5r.net Git - cc65/blob - libsrc/common/mktime.c
Fixed comments.
[cc65] / libsrc / common / mktime.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 mktime.c                                  */
4 /*                                                                           */
5 /*           Make calendar time from broken down time and cleanup            */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2002      Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <limits.h>
37 #include <stdlib.h>
38 #include <time.h>
39
40
41
42 /*****************************************************************************/
43 /*                                   Data                                    */
44 /*****************************************************************************/
45
46
47
48 #define JANUARY         0
49 #define FEBRUARY        1
50 #define DECEMBER       11
51 #define JAN_1_1970      4               /* 1/1/1970 is a thursday */
52
53
54
55 static const unsigned char MonthLength [] = {
56     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
57 };
58 static const unsigned MonthDays [] = {
59     0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
60 };
61
62
63
64 /*****************************************************************************/
65 /*                                   Code                                    */
66 /*****************************************************************************/
67
68
69
70 static unsigned char __fastcall__ IsLeapYear (unsigned Year)
71 /* Returns 1 if the given year is a leap year */
72 {
73     return (((Year % 4) == 0) && ((Year % 100) != 0 || (Year % 400) == 0));
74 }
75
76
77
78 time_t __fastcall__ mktime (register struct tm* TM)
79 /* Make a time in seconds since 1/1/1970 from the broken down time in TM.
80 ** A call to mktime does also correct the time in TM to contain correct
81 ** values.
82 */
83 {
84     register div_t D;
85     int Max;
86     unsigned DayCount;
87
88     /* Check if TM is valid */
89     if (TM == 0) {
90         /* Invalid data */
91         goto Error;
92     }
93
94     /* Adjust seconds. */
95     D = div (TM->tm_sec, 60);
96     TM->tm_sec = D.rem;
97
98     /* Adjust minutes */
99     if (TM->tm_min + D.quot < 0) {
100         goto Error;
101     }
102     TM->tm_min += D.quot;
103     D = div (TM->tm_min, 60);
104     TM->tm_min = D.rem;
105
106     /* Adjust hours */
107     if (TM->tm_hour + D.quot < 0) {
108         goto Error;
109     }
110     TM->tm_hour += D.quot;
111     D = div (TM->tm_hour, 24);
112     TM->tm_hour = D.rem;
113
114     /* Adjust days */
115     if (TM->tm_mday + D.quot < 0) {
116         goto Error;
117     }
118     TM->tm_mday += D.quot;
119
120     /* Adjust month and year. This is an iterative process, since changing
121     ** the month will change the allowed days for this month.
122     */
123     while (1) {
124
125         /* Make sure, month is in the range 0..11 */
126         D = div (TM->tm_mon, 12);
127         TM->tm_mon = D.rem;
128         if (TM->tm_year + D.quot < 0) {
129             goto Error;
130         }
131         TM->tm_year += D.quot;
132
133         /* Now check if mday is in the correct range, if not, correct month
134         ** and eventually year and repeat the process.
135         */
136         if (TM->tm_mon == FEBRUARY && IsLeapYear (TM->tm_year + 1900)) {
137             Max = 29;
138         } else {
139             Max = MonthLength[TM->tm_mon];
140         }
141         if (TM->tm_mday > Max) {
142             /* Must correct month and eventually, year */
143             if (TM->tm_mon == DECEMBER) {
144                 TM->tm_mon = JANUARY;
145                 ++TM->tm_year;
146             } else {
147                 ++TM->tm_mon;
148             }
149             TM->tm_mday -= Max;
150         } else {
151             /* Done */
152             break;
153         }
154     }
155
156     /* Ok, all time/date fields are now correct. Calculate the days in this
157     ** year.
158     */
159     TM->tm_yday = MonthDays[TM->tm_mon] + TM->tm_mday - 1;
160     if (TM->tm_mon > FEBRUARY && IsLeapYear (TM->tm_year + 1900)) {
161         ++TM->tm_yday;
162     }
163
164     /* Calculate days since 1/1/1970. In the complete epoch (1/1/1970 to
165     ** somewhere in 2038) all years dividable by 4 are leap years, so
166     ** dividing by 4 gives the days that must be added cause of leap years.
167     ** (and the last leap year before 1970 was 1968)
168     */
169     DayCount = ((unsigned) (TM->tm_year-70)) * 365U +
170                (((unsigned) (TM->tm_year-(68+1))) / 4) +
171                TM->tm_yday;
172
173     /* Calculate the weekday */
174     TM->tm_wday = (JAN_1_1970 + DayCount) % 7;
175
176     /* No (US) daylight saving (for now) */
177     TM->tm_isdst = 0;
178
179     /* Return seconds since 1970 */
180     return DayCount * 86400UL +
181            ((unsigned) TM->tm_hour) * 3600UL +
182            ((unsigned) TM->tm_min) * 60U +
183            ((unsigned) TM->tm_sec);
184
185 Error:
186     /* Error exit */
187     return (time_t) -1L;
188 }
189
190
191