mutt stable branch with some hacks
at master 199 lines 4.9 kB view raw
1/* 2 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 */ 18 19#if HAVE_CONFIG_H 20# include "config.h" 21#endif 22 23#include "mutt.h" 24#include <string.h> 25 26/* returns the seconds east of UTC given `g' and its corresponding gmtime() 27 representation */ 28static time_t compute_tz (time_t g, struct tm *utc) 29{ 30 struct tm *lt = localtime (&g); 31 time_t t; 32 int yday; 33 34 t = (((lt->tm_hour - utc->tm_hour) * 60) + (lt->tm_min - utc->tm_min)) * 60; 35 36 if ((yday = (lt->tm_yday - utc->tm_yday))) 37 { 38 /* This code is optimized to negative timezones (West of Greenwich) */ 39 if (yday == -1 || /* UTC passed midnight before localtime */ 40 yday > 1) /* UTC passed new year before localtime */ 41 t -= 24 * 60 * 60; 42 else 43 t += 24 * 60 * 60; 44 } 45 46 return t; 47} 48 49/* Returns the local timezone in seconds east of UTC for the time t, 50 * or for the current time if t is zero. 51 */ 52time_t mutt_local_tz (time_t t) 53{ 54 struct tm *ptm; 55 struct tm utc; 56 57 if (!t) 58 t = time (NULL); 59 ptm = gmtime (&t); 60 /* need to make a copy because gmtime/localtime return a pointer to 61 static memory (grr!) */ 62 memcpy (&utc, ptm, sizeof (utc)); 63 return (compute_tz (t, &utc)); 64} 65 66/* theoretically time_t can be float but it is integer on most (if not all) systems */ 67#define TIME_T_MAX ((((time_t) 1 << (sizeof(time_t) * 8 - 2)) - 1) * 2 + 1) 68#define TM_YEAR_MAX (1970 + (((((TIME_T_MAX - 59) / 60) - 59) / 60) - 23) / 24 / 366) 69 70/* converts struct tm to time_t, but does not take the local timezone into 71 account unless ``local'' is nonzero */ 72time_t mutt_mktime (struct tm *t, int local) 73{ 74 time_t g; 75 76 static const int AccumDaysPerMonth[12] = { 77 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 78 }; 79 80 /* Prevent an integer overflow. 81 * The time_t cast is an attempt to silence a clang range warning. */ 82 if ((time_t)t->tm_year > TM_YEAR_MAX) 83 return TIME_T_MAX; 84 85 /* Compute the number of days since January 1 in the same year */ 86 g = AccumDaysPerMonth [t->tm_mon % 12]; 87 88 /* The leap years are 1972 and every 4. year until 2096, 89 * but this algorithm will fail after year 2099 */ 90 g += t->tm_mday; 91 if ((t->tm_year % 4) || t->tm_mon < 2) 92 g--; 93 t->tm_yday = g; 94 95 /* Compute the number of days since January 1, 1970 */ 96 g += (t->tm_year - 70) * (time_t)365; 97 g += (t->tm_year - 69) / 4; 98 99 /* Compute the number of hours */ 100 g *= 24; 101 g += t->tm_hour; 102 103 /* Compute the number of minutes */ 104 g *= 60; 105 g += t->tm_min; 106 107 /* Compute the number of seconds */ 108 g *= 60; 109 g += t->tm_sec; 110 111 if (local) 112 g -= compute_tz (g, t); 113 114 return (g); 115} 116 117/* Return 1 if month is February of leap year, else 0 */ 118static int isLeapYearFeb (struct tm *tm) 119{ 120 if (tm->tm_mon == 1) 121 { 122 int y = tm->tm_year + 1900; 123 return (((y & 3) == 0) && (((y % 100) != 0) || ((y % 400) == 0))); 124 } 125 return (0); 126} 127 128void mutt_normalize_time (struct tm *tm) 129{ 130 static const char DaysPerMonth[12] = { 131 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 132 }; 133 int nLeap; 134 135 while (tm->tm_sec < 0) 136 { 137 tm->tm_sec += 60; 138 tm->tm_min--; 139 } 140 while (tm->tm_sec >= 60) 141 { 142 tm->tm_sec -= 60; 143 tm->tm_min++; 144 } 145 while (tm->tm_min < 0) 146 { 147 tm->tm_min += 60; 148 tm->tm_hour--; 149 } 150 while (tm->tm_min >= 60) 151 { 152 tm->tm_min -= 60; 153 tm->tm_hour++; 154 } 155 while (tm->tm_hour < 0) 156 { 157 tm->tm_hour += 24; 158 tm->tm_mday--; 159 } 160 while (tm->tm_hour >= 24) 161 { 162 tm->tm_hour -= 24; 163 tm->tm_mday++; 164 } 165 /* use loops on NNNdwmy user input values? */ 166 while (tm->tm_mon < 0) 167 { 168 tm->tm_mon += 12; 169 tm->tm_year--; 170 } 171 while (tm->tm_mon >= 12) 172 { 173 tm->tm_mon -= 12; 174 tm->tm_year++; 175 } 176 while (tm->tm_mday <= 0) 177 { 178 if (tm->tm_mon) 179 tm->tm_mon--; 180 else 181 { 182 tm->tm_mon = 11; 183 tm->tm_year--; 184 } 185 tm->tm_mday += DaysPerMonth[tm->tm_mon] + isLeapYearFeb (tm); 186 } 187 while (tm->tm_mday > (DaysPerMonth[tm->tm_mon] + 188 (nLeap = isLeapYearFeb (tm)))) 189 { 190 tm->tm_mday -= DaysPerMonth[tm->tm_mon] + nLeap; 191 if (tm->tm_mon < 11) 192 tm->tm_mon++; 193 else 194 { 195 tm->tm_mon = 0; 196 tm->tm_year++; 197 } 198 } 199}