small fix
[apps/madmutt.git] / date.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #include "mutt.h"
15 #include <string.h>
16
17 /* returns the seconds east of UTC given `g' and its corresponding gmtime()
18    representation */
19 static time_t compute_tz (time_t g, struct tm *utc)
20 {
21   struct tm *lt = localtime (&g);
22   time_t t;
23   int yday;
24
25   t = (((lt->tm_hour - utc->tm_hour) * 60) + (lt->tm_min - utc->tm_min)) * 60;
26
27   if ((yday = (lt->tm_yday - utc->tm_yday))) {
28     /* This code is optimized to negative timezones (West of Greenwich) */
29     if (yday == -1 ||           /* UTC passed midnight before localtime */
30         yday > 1)               /* UTC passed new year before localtime */
31       t -= 24 * 60 * 60;
32     else
33       t += 24 * 60 * 60;
34   }
35
36   return t;
37 }
38
39 /* Returns the local timezone in seconds east of UTC for the time t,
40  * or for the current time if t is zero.
41  */
42 time_t mutt_local_tz (time_t t)
43 {
44   struct tm *ptm;
45   struct tm utc;
46
47   if (!t)
48     t = time (NULL);
49   ptm = gmtime (&t);
50   /* need to make a copy because gmtime/localtime return a pointer to
51      static memory (grr!) */
52   memcpy (&utc, ptm, sizeof (utc));
53   return (compute_tz (t, &utc));
54 }
55
56 /* converts struct tm to time_t, but does not take the local timezone into
57    account unless ``local'' is nonzero */
58 time_t mutt_mktime (struct tm * t, int local)
59 {
60   time_t g;
61
62   static int AccumDaysPerMonth[12] = {
63     0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
64   };
65
66   /* Compute the number of days since January 1 in the same year */
67   g = AccumDaysPerMonth[t->tm_mon % 12];
68
69   /* The leap years are 1972 and every 4. year until 2096,
70    * but this algoritm will fail after year 2099 */
71   g += t->tm_mday;
72   if ((t->tm_year % 4) || t->tm_mon < 2)
73     g--;
74   t->tm_yday = g;
75
76   /* Compute the number of days since January 1, 1970 */
77   g += (t->tm_year - 70) * 365;
78   g += (t->tm_year - 69) / 4;
79
80   /* Compute the number of hours */
81   g *= 24;
82   g += t->tm_hour;
83
84   /* Compute the number of minutes */
85   g *= 60;
86   g += t->tm_min;
87
88   /* Compute the number of seconds */
89   g *= 60;
90   g += t->tm_sec;
91
92   if (local)
93     g -= compute_tz (g, t);
94
95   return (g);
96 }
97
98 /* Return 1 if month is February of leap year, else 0 */
99 static int isLeapYearFeb (struct tm *tm)
100 {
101   if (tm->tm_mon == 1) {
102     int y = tm->tm_year + 1900;
103
104     return (((y & 3) == 0) && (((y % 100) != 0) || ((y % 400) == 0)));
105   }
106   return (0);
107 }
108
109 void mutt_normalize_time (struct tm *tm)
110 {
111   static char DaysPerMonth[12] = {
112     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
113   };
114   int nLeap;
115
116   while (tm->tm_sec < 0) {
117     tm->tm_sec += 60;
118     tm->tm_min--;
119   }
120   while (tm->tm_sec >= 60) {
121     tm->tm_sec -= 60;
122     tm->tm_min++;
123   }
124   while (tm->tm_min < 0) {
125     tm->tm_min += 60;
126     tm->tm_hour--;
127   }
128   while (tm->tm_min >= 60) {
129     tm->tm_min -= 60;
130     tm->tm_hour++;
131   }
132   while (tm->tm_hour < 0) {
133     tm->tm_hour += 24;
134     tm->tm_mday--;
135   }
136   while (tm->tm_hour >= 24) {
137     tm->tm_hour -= 24;
138     tm->tm_mday++;
139   }
140   /* use loops on NNNdwmy user input values? */
141   while (tm->tm_mon < 0) {
142     tm->tm_mon += 12;
143     tm->tm_year--;
144   }
145   while (tm->tm_mon >= 12) {
146     tm->tm_mon -= 12;
147     tm->tm_year++;
148   }
149   while (tm->tm_mday <= 0) {
150     if (tm->tm_mon)
151       tm->tm_mon--;
152     else {
153       tm->tm_mon = 11;
154       tm->tm_year--;
155     }
156     tm->tm_mday += DaysPerMonth[tm->tm_mon] + isLeapYearFeb (tm);
157   }
158   while (tm->tm_mday > (DaysPerMonth[tm->tm_mon] +
159                         (nLeap = isLeapYearFeb (tm)))) {
160     tm->tm_mday -= DaysPerMonth[tm->tm_mon] + nLeap;
161     if (tm->tm_mon < 11)
162       tm->tm_mon++;
163     else {
164       tm->tm_mon = 0;
165       tm->tm_year++;
166     }
167   }
168 }