mactime.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*
  2. Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
  3. See the accompanying file LICENSE, version 2000-Apr-09 or later
  4. (the contents of which are also included in zip.h) for terms of use.
  5. If, for some reason, all these files are missing, the Info-ZIP license
  6. also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
  7. */
  8. /* -----------------------------------------------------------------------------
  9. The original functions (Metrowerks Codewarrior pro 3.0) gmtime, localtime,
  10. mktime and time do not work correctly. The supplied link library mactime.c
  11. contains replacement functions for them.
  12. * Caveat: On a Mac, we only know the GMT and DST offsets for
  13. * the current time, not for the time in question.
  14. * Mac has no support for DST handling.
  15. * DST changeover is all manually set by the user.
  16. ------------------------------------------------------------------------------*/
  17. /*****************************************************************************/
  18. /* Includes */
  19. /*****************************************************************************/
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <time.h>
  24. #include <OSUtils.h>
  25. #include "mactime.h"
  26. /*
  27. The MacOS function GetDateTime returns the
  28. number of seconds elapsed since midnight, January 1, 1904.
  29. */
  30. const unsigned long MacOS_2_Unix = 2082844800L;
  31. /*****************************************************************************/
  32. /* Macros, typedefs */
  33. /*****************************************************************************/
  34. #ifndef TEST_TIME_LIB
  35. #define my_gmtime gmtime
  36. #define my_localtime localtime
  37. #define my_mktime mktime
  38. #define my_time time
  39. #endif
  40. /*****************************************************************************/
  41. /* Prototypes */
  42. /*****************************************************************************/
  43. /* internal prototypes */
  44. static void clear_tm(struct tm * tm);
  45. static long GMTDelta(void);
  46. static Boolean DaylightSaving(void);
  47. static time_t GetTimeMac(void);
  48. static time_t Mactime(time_t *timer);
  49. static void normalize(int *i,int *j,int norm);
  50. static struct tm *time2tm(const time_t *timer);
  51. static time_t tm2time(struct tm *tp);
  52. /* Because serial port and SLIP conflict with ReadXPram calls,
  53. we cache the call here so we don't hang on calling ReadLocation() */
  54. static void myReadLocation(MachineLocation * loc);
  55. /* prototypes for STD lib replacement functions */
  56. struct tm *my_gmtime(const time_t *t);
  57. struct tm *my_localtime(const time_t *t);
  58. time_t my_mktime(struct tm *tp);
  59. time_t my_time(time_t *t);
  60. /*****************************************************************************/
  61. /* Functions */
  62. /*****************************************************************************/
  63. /*
  64. * Mac file times are based on 1904 Jan 1 00:00 local time,
  65. * not 1970 Jan 1 00:00 UTC.
  66. * So we have to convert the time stamps into UNIX UTC
  67. * compatible values.
  68. */
  69. time_t MacFtime2UnixFtime(unsigned long macftime)
  70. {
  71. long UTCoffset;
  72. GetGMToffsetMac(macftime, &UTCoffset);
  73. MACOS_TO_UNIX(macftime);
  74. macftime -= UTCoffset;
  75. return macftime;
  76. }
  77. /*
  78. * Mac file times are based on 1904 Jan 1 00:00 local time,
  79. * not 1970 Jan 1 00:00 UTC.
  80. * So we have to convert the time stamps into MacOS local
  81. * compatible values.
  82. */
  83. unsigned long UnixFtime2MacFtime(time_t unxftime)
  84. {
  85. long UTCoffset;
  86. unsigned long macftime = unxftime;
  87. UNIX_TO_MACOS(macftime);
  88. GetGMToffsetMac(macftime, &UTCoffset);
  89. macftime += UTCoffset;
  90. return macftime;
  91. }
  92. /*
  93. * This function convert a file-localtime to an another
  94. * file-localtime.
  95. */
  96. time_t AdjustForTZmoveMac(unsigned long macloctim, long s_gmtoffs)
  97. {
  98. time_t MacGMTTime;
  99. long UTCoffset;
  100. /* convert macloctim into corresponding UTC value */
  101. MacGMTTime = macloctim - s_gmtoffs;
  102. GetGMToffsetMac(macloctim, &UTCoffset);
  103. return (MacGMTTime + UTCoffset);
  104. } /* AdjustForTZmove() */
  105. /*
  106. * This function calculates the difference between the supplied Mac
  107. * ftime value (local time) and the corresponding UTC time in seconds.
  108. */
  109. Boolean GetGMToffsetMac(unsigned long mactime, long *UTCoffset)
  110. {
  111. mactime = mactime;
  112. /*
  113. * Caveat: On a Mac, we only know the GMT and DST offsets for
  114. * the current time, not for the time in question.
  115. * Mac has no support for DST handling.
  116. * DST changeover is all manually set by the user.
  117. May be later I can include a support of GMT offset calculation for the
  118. time in question here.
  119. */
  120. *UTCoffset = GMTDelta();
  121. return true;
  122. }
  123. /*****************************************************************************
  124. * Standard Library Replacement Functions
  125. * gmtime(), mktime(), localtime(), time()
  126. *
  127. * The unix epoch is used here.
  128. * These functions gmtime(), mktime(), localtime() and time()
  129. * expects and returns unix times.
  130. *
  131. * At midnight Jan. 1, 1970 GMT, the local time was
  132. * midnight Jan. 1, 1970 + GMTDelta().
  133. *
  134. *
  135. *****************************************************************************/
  136. struct tm *my_gmtime(const time_t *timer)
  137. {
  138. return time2tm(timer);
  139. }
  140. struct tm *my_localtime(const time_t *timer)
  141. {
  142. time_t maclocal;
  143. maclocal = *timer;
  144. maclocal += GMTDelta();
  145. return time2tm(&maclocal);
  146. }
  147. time_t my_mktime(struct tm *tp)
  148. {
  149. time_t maclocal;
  150. maclocal = tm2time(tp);
  151. maclocal -= GMTDelta();
  152. return maclocal;
  153. }
  154. time_t my_time(time_t *time)
  155. {
  156. time_t tmp_time;
  157. GetDateTime(&tmp_time);
  158. MACOS_TO_UNIX(tmp_time);
  159. if (time)
  160. {
  161. *time = tmp_time;
  162. }
  163. return tmp_time;
  164. }
  165. /*****************************************************************************/
  166. /* static module level functions
  167. /*****************************************************************************/
  168. /*
  169. * The geographic location and time zone information of a Mac
  170. * are stored in extended parameter RAM. The ReadLocation
  171. * produdure uses the geographic location record, MachineLocation,
  172. * to read the geographic location and time zone information in
  173. * extended parameter RAM.
  174. *
  175. * Because serial port and SLIP conflict with ReadXPram calls,
  176. * we cache the call here.
  177. *
  178. * Caveat: this caching will give the wrong result if a session
  179. * extend across the DST changeover time, but
  180. * this function resets itself every 2 hours.
  181. */
  182. static void myReadLocation(MachineLocation * loc)
  183. {
  184. static MachineLocation storedLoc; /* InsideMac, OSUtilities, page 4-20 */
  185. static time_t first_call = 0, last_call = 86400;
  186. if ((last_call - first_call) > 7200)
  187. {
  188. GetDateTime(&first_call);
  189. ReadLocation(&storedLoc);
  190. }
  191. GetDateTime(&last_call);
  192. *loc = storedLoc;
  193. }
  194. static Boolean DaylightSaving(void)
  195. {
  196. MachineLocation loc;
  197. unsigned char dlsDelta;
  198. myReadLocation(&loc);
  199. dlsDelta = loc.u.dlsDelta;
  200. return (dlsDelta != 0);
  201. }
  202. /* current local time = GMTDelta() + GMT
  203. GMT = local time - GMTDelta() */
  204. static long GMTDelta(void)
  205. {
  206. MachineLocation loc;
  207. long gmtDelta;
  208. myReadLocation(&loc);
  209. /*
  210. * On a Mac, the GMT value is in seconds east of GMT. For example,
  211. * San Francisco is at -28,800 seconds (8 hours * 3600 seconds per hour)
  212. * east of GMT. The gmtDelta field is a 3-byte value contained in a
  213. * long word, so you must take care to get it properly.
  214. */
  215. gmtDelta = loc.u.gmtDelta & 0x00FFFFFF;
  216. if ((gmtDelta & 0x00800000) != 0)
  217. {
  218. gmtDelta |= 0xFF000000;
  219. }
  220. return gmtDelta;
  221. }
  222. /* This routine simulates stdclib time(), time in seconds since 1.1.1970
  223. The time is in GMT */
  224. static time_t GetTimeMac(void)
  225. {
  226. unsigned long maclocal;
  227. /*
  228. * Get the current time expressed as the number of seconds
  229. * elapsed since the Mac epoch, midnight, Jan. 1, 1904 (local time).
  230. * On a Mac, current time accuracy is up to a second.
  231. */
  232. GetDateTime(&maclocal); /* Get Mac local time */
  233. maclocal -= GMTDelta(); /* Get Mac GMT */
  234. MACOS_TO_UNIX(maclocal);
  235. return maclocal; /* return unix GMT */
  236. }
  237. /*
  238. * clear_tm - sets a broken-down time to the equivalent of 1970/1/1 00:00:00
  239. */
  240. static void clear_tm(struct tm * tm)
  241. {
  242. tm->tm_sec = 0;
  243. tm->tm_min = 0;
  244. tm->tm_hour = 0;
  245. tm->tm_mday = 1;
  246. tm->tm_mon = 0;
  247. tm->tm_year = 0;
  248. tm->tm_wday = 1;
  249. tm->tm_yday = 0;
  250. tm->tm_isdst = -1;
  251. }
  252. static void normalize(int *i,int *j,int norm)
  253. {
  254. while(*i < 0)
  255. {
  256. *i += norm;
  257. (*j)--;
  258. }
  259. while(*i >= norm)
  260. {
  261. *i -= norm;
  262. (*j)++;
  263. }
  264. }
  265. /* Returns the GMT times */
  266. static time_t Mactime(time_t *timer)
  267. {
  268. time_t t = GetTimeMac();
  269. if (timer != NULL)
  270. *timer = t;
  271. return t;
  272. }
  273. static struct tm *time2tm(const time_t *timer)
  274. {
  275. DateTimeRec dtr;
  276. MachineLocation loc;
  277. time_t macLocal = *timer;
  278. static struct tm statictime;
  279. static const short monthday[12] =
  280. {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  281. UNIX_TO_MACOS(macLocal);
  282. SecondsToDate(macLocal, &dtr);
  283. statictime.tm_sec = dtr.second; /* second, from 0 to 59 */
  284. statictime.tm_min = dtr.minute; /* minute, from 0 to 59 */
  285. statictime.tm_hour = dtr.hour; /* hour, from 0 to 23 */
  286. statictime.tm_mday = dtr.day; /* day of the month, from 1 to 31 */
  287. statictime.tm_mon = dtr.month - 1; /* month, 1= January and 12 = December */
  288. statictime.tm_year = dtr.year - 1900; /* year, ranging from 1904 to 2040 */
  289. statictime.tm_wday = dtr.dayOfWeek - 1; /* day of the week, 1 = Sun, 7 = Sat */
  290. statictime.tm_yday = monthday[statictime.tm_mon]
  291. + statictime.tm_mday - 1;
  292. if (2 < statictime.tm_mon && !(statictime.tm_year & 3))
  293. {
  294. ++statictime.tm_yday;
  295. }
  296. myReadLocation(&loc);
  297. statictime.tm_isdst = DaylightSaving();
  298. return(&statictime);
  299. }
  300. static time_t tm2time(struct tm *tp)
  301. {
  302. time_t intMacTime;
  303. DateTimeRec dtr;
  304. normalize(&tp->tm_sec, &tp->tm_min, 60);
  305. normalize(&tp->tm_min, &tp->tm_hour,60);
  306. normalize(&tp->tm_hour,&tp->tm_mday,24);
  307. normalize(&tp->tm_mon, &tp->tm_year,12);
  308. dtr.year = tp->tm_year + 1900; /* years since 1900 */
  309. dtr.month = tp->tm_mon + 1; /* month, 0 = January and 11 = December */
  310. dtr.day = tp->tm_mday; /* day of the month, from 1 to 31 */
  311. dtr.hour = tp->tm_hour; /* hour, from 0 to 23 */
  312. dtr.minute = tp->tm_min; /* minute, from 0 to 59 */
  313. dtr.second = tp->tm_sec; /* second, from 0 to 59 */
  314. DateToSeconds(&dtr, &intMacTime);
  315. MACOS_TO_UNIX(intMacTime);
  316. return intMacTime;
  317. }