tclMacTime.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:13k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclMacTime.c --
  3.  *
  4.  * Contains Macintosh specific versions of Tcl functions that
  5.  * obtain time values from the operating system.
  6.  *
  7.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tclMacTime.c,v 1.7 2002/01/04 11:21:05 das Exp $
  13.  */
  14. #include "tclInt.h"
  15. #include "tclPort.h"
  16. #include "tclMacInt.h"
  17. #include <OSUtils.h>
  18. #include <Timer.h>
  19. #include <time.h>
  20. /*
  21.  * Static variables used by the Tcl_GetTime function.
  22.  */
  23.  
  24. static int initalized = false;
  25. static unsigned long baseSeconds;
  26. static UnsignedWide microOffset;
  27. static int gmt_initialized = false;
  28. static long gmt_offset;
  29. static int gmt_isdst;
  30. TCL_DECLARE_MUTEX(gmtMutex)
  31. static int gmt_lastGetDateUseGMT = 0;
  32. typedef struct _TABLE {
  33.     char        *name;
  34.     int         type;
  35.     time_t      value;
  36. } TABLE;
  37. #define HOUR(x)         ((time_t) (3600 * x))
  38. #define tZONE 0
  39. #define tDAYZONE 1
  40. /*
  41.  * inverse timezone table, adapted from tclDate.c by removing duplicates and
  42.  * adding some made up names for unusual daylight savings
  43.  */
  44. static TABLE    invTimezoneTable[] = {
  45.     { "Z",    -1,     HOUR( 36) },      /* Unknown */
  46.     { "GMT",    tZONE,     HOUR( 0) },      /* Greenwich Mean */
  47.     { "BST",    tDAYZONE,  HOUR( 0) },      /* British Summer */
  48.     { "WAT",    tZONE,     HOUR( 1) },      /* West Africa */
  49.     { "WADST",  tDAYZONE,  HOUR( 1) },      /* West Africa Daylight*/
  50.     { "AT",     tZONE,     HOUR( 2) },      /* Azores Daylight*/
  51.     { "ADST",   tDAYZONE,  HOUR( 2) },      /* Azores */
  52.     { "NFT",    tZONE,     HOUR( 7/2) },    /* Newfoundland */
  53.     { "NDT",    tDAYZONE,  HOUR( 7/2) },    /* Newfoundland Daylight */
  54.     { "AST",    tZONE,     HOUR( 4) },      /* Atlantic Standard */
  55.     { "ADT",    tDAYZONE,  HOUR( 4) },      /* Atlantic Daylight */
  56.     { "EST",    tZONE,     HOUR( 5) },      /* Eastern Standard */
  57.     { "EDT",    tDAYZONE,  HOUR( 5) },      /* Eastern Daylight */
  58.     { "CST",    tZONE,     HOUR( 6) },      /* Central Standard */
  59.     { "CDT",    tDAYZONE,  HOUR( 6) },      /* Central Daylight */
  60.     { "MST",    tZONE,     HOUR( 7) },      /* Mountain Standard */
  61.     { "MDT",    tDAYZONE,  HOUR( 7) },      /* Mountain Daylight */
  62.     { "PST",    tZONE,     HOUR( 8) },      /* Pacific Standard */
  63.     { "PDT",    tDAYZONE,  HOUR( 8) },      /* Pacific Daylight */
  64.     { "YST",    tZONE,     HOUR( 9) },      /* Yukon Standard */
  65.     { "YDT",    tDAYZONE,  HOUR( 9) },      /* Yukon Daylight */
  66.     { "HST",    tZONE,     HOUR(10) },      /* Hawaii Standard */
  67.     { "HDT",    tDAYZONE,  HOUR(10) },      /* Hawaii Daylight */
  68.     { "NT",     tZONE,     HOUR(11) },      /* Nome */
  69.     { "NST",    tDAYZONE,  HOUR(11) },      /* Nome Daylight*/
  70.     { "IDLW",   tZONE,     HOUR(12) },      /* International Date Line West */
  71.     { "CET",    tZONE,    -HOUR( 1) },      /* Central European */
  72.     { "CEST",   tDAYZONE, -HOUR( 1) },      /* Central European Summer */
  73.     { "EET",    tZONE,    -HOUR( 2) },      /* Eastern Europe, USSR Zone 1 */
  74.     { "EEST",   tDAYZONE, -HOUR( 2) },      /* Eastern Europe, USSR Zone 1 Daylight*/
  75.     { "BT",     tZONE,    -HOUR( 3) },      /* Baghdad, USSR Zone 2 */
  76.     { "BDST",   tDAYZONE, -HOUR( 3) },      /* Baghdad, USSR Zone 2 Daylight*/
  77.     { "IT",     tZONE,    -HOUR( 7/2) },    /* Iran */
  78.     { "IDST",   tDAYZONE, -HOUR( 7/2) },    /* Iran Daylight*/
  79.     { "ZP4",    tZONE,    -HOUR( 4) },      /* USSR Zone 3 */
  80.     { "ZP4S",   tDAYZONE, -HOUR( 4) },      /* USSR Zone 3 */
  81.     { "ZP5",    tZONE,    -HOUR( 5) },      /* USSR Zone 4 */
  82.     { "ZP5S",   tDAYZONE, -HOUR( 5) },      /* USSR Zone 4 */
  83.     { "IST",    tZONE,    -HOUR(11/2) },    /* Indian Standard */
  84.     { "ISDST",  tDAYZONE, -HOUR(11/2) },    /* Indian Standard */
  85.     { "ZP6",    tZONE,    -HOUR( 6) },      /* USSR Zone 5 */
  86.     { "ZP6S",   tDAYZONE, -HOUR( 6) },      /* USSR Zone 5 */
  87.     { "WAST",   tZONE,    -HOUR( 7) },      /* West Australian Standard */
  88.     { "WADT",   tDAYZONE, -HOUR( 7) },      /* West Australian Daylight */
  89.     { "JT",     tZONE,    -HOUR(15/2) },    /* Java (3pm in Cronusland!) */
  90.     { "JDST",   tDAYZONE, -HOUR(15/2) },    /* Java (3pm in Cronusland!) */
  91.     { "CCT",    tZONE,    -HOUR( 8) },      /* China Coast, USSR Zone 7 */
  92.     { "CCST",   tDAYZONE, -HOUR( 8) },      /* China Coast, USSR Zone 7 */
  93.     { "JST",    tZONE,    -HOUR( 9) },      /* Japan Standard, USSR Zone 8 */
  94.     { "JSDST",  tDAYZONE, -HOUR( 9) },      /* Japan Standard, USSR Zone 8 */
  95.     { "CAST",   tZONE,    -HOUR(19/2) },    /* Central Australian Standard */
  96.     { "CADT",   tDAYZONE, -HOUR(19/2) },    /* Central Australian Daylight */
  97.     { "EAST",   tZONE,    -HOUR(10) },      /* Eastern Australian Standard */
  98.     { "EADT",   tDAYZONE, -HOUR(10) },      /* Eastern Australian Daylight */
  99.     { "NZT",    tZONE,    -HOUR(12) },      /* New Zealand */
  100.     { "NZDT",   tDAYZONE, -HOUR(12) },      /* New Zealand Daylight */
  101.     {  NULL  }
  102. };
  103. /*
  104.  * Prototypes for procedures that are private to this file:
  105.  */
  106. static void SubtractUnsignedWide _ANSI_ARGS_((UnsignedWide *x,
  107. UnsignedWide *y, UnsignedWide *result));
  108. /*
  109.  *-----------------------------------------------------------------------------
  110.  *
  111.  * TclpGetGMTOffset --
  112.  *
  113.  * This procedure gets the offset seconds that needs to be _added_ to tcl time
  114.  *  in seconds (i.e. GMT time) to get local time needed as input to various
  115.  *  Mac OS APIs, to convert Mac OS API output to tcl time, _subtract_ this value.
  116.  *
  117.  * Results:
  118.  * Number of seconds separating GMT time and mac.
  119.  *
  120.  * Side effects:
  121.  * None.
  122.  *
  123.  *-----------------------------------------------------------------------------
  124.  */
  125. long
  126. TclpGetGMTOffset()
  127. {
  128.     if (gmt_initialized == false) {
  129. MachineLocation loc;
  130.     Tcl_MutexLock(&gmtMutex);
  131. ReadLocation(&loc);
  132. gmt_offset = loc.u.gmtDelta & 0x00ffffff;
  133. if (gmt_offset & 0x00800000) {
  134.     gmt_offset = gmt_offset | 0xff000000;
  135. }
  136. gmt_isdst=(loc.u.dlsDelta < 0);
  137. gmt_initialized = true;
  138.     Tcl_MutexUnlock(&gmtMutex);
  139.     }
  140. return (gmt_offset);
  141. }
  142. /*
  143.  *-----------------------------------------------------------------------------
  144.  *
  145.  * TclpGetSeconds --
  146.  *
  147.  * This procedure returns the number of seconds from the epoch.  On
  148.  * the Macintosh the epoch is Midnight Jan 1, 1904.  Unfortunatly,
  149.  * the Macintosh doesn't tie the epoch to a particular time zone.  For
  150.  * Tcl we tie the epoch to GMT.  This makes the time zone date parsing
  151.  * code work.  The epoch for Mac-Tcl is: Midnight Jan 1, 1904 GMT.
  152.  *
  153.  * Results:
  154.  * Number of seconds from the epoch in GMT.
  155.  *
  156.  * Side effects:
  157.  * None.
  158.  *
  159.  *-----------------------------------------------------------------------------
  160.  */
  161. unsigned long
  162. TclpGetSeconds()
  163. {
  164.     unsigned long seconds;
  165.     GetDateTime(&seconds);
  166. return (seconds - TclpGetGMTOffset() + tcl_mac_epoch_offset);
  167. }
  168. /*
  169.  *-----------------------------------------------------------------------------
  170.  *
  171.  * TclpGetClicks --
  172.  *
  173.  * This procedure returns a value that represents the highest resolution
  174.  * clock available on the system.  There are no garantees on what the
  175.  * resolution will be.  In Tcl we will call this value a "click".  The
  176.  * start time is also system dependant.
  177.  *
  178.  * Results:
  179.  * Number of clicks from some start time.
  180.  *
  181.  * Side effects:
  182.  * None.
  183.  *
  184.  *-----------------------------------------------------------------------------
  185.  */
  186. unsigned long
  187. TclpGetClicks()
  188. {
  189.     UnsignedWide micros;
  190.     Microseconds(&micros);
  191.     return micros.lo;
  192. }
  193. /*
  194.  *----------------------------------------------------------------------
  195.  *
  196.  * TclpGetTimeZone --
  197.  *
  198.  * Get the current time zone.
  199.  *
  200.  * Results:
  201.  * The return value is the local time zone, measured in
  202.  * minutes away from GMT (-ve for east, +ve for west).
  203.  *
  204.  * Side effects:
  205.  * None.
  206.  *
  207.  *----------------------------------------------------------------------
  208.  */
  209. int
  210. TclpGetTimeZone (
  211.     unsigned long  currentTime) /* Ignored on Mac. */
  212. {
  213.     long offset;
  214.     /*
  215.      * Convert the Mac offset from seconds to minutes and
  216.      * add an hour if we have daylight savings time.
  217.      */
  218.     offset = -TclpGetGMTOffset();
  219.     offset /= 60;
  220.     if (gmt_isdst) {
  221. offset += 60;
  222.     }
  223.     
  224.     return offset;
  225. }
  226. /*
  227.  *----------------------------------------------------------------------
  228.  *
  229.  * Tcl_GetTime --
  230.  *
  231.  * Gets the current system time in seconds and microseconds
  232.  * since the beginning of the epoch: 00:00 UCT, January 1, 1970.
  233.  *
  234.  * Results:
  235.  * Returns the current time (in the local timezone) in timePtr.
  236.  *
  237.  * Side effects:
  238.  * None.
  239.  *
  240.  *----------------------------------------------------------------------
  241.  */
  242. void
  243. Tcl_GetTime(
  244.     Tcl_Time *timePtr) /* Location to store time information. */
  245. {
  246.     UnsignedWide micro;
  247. #ifndef NO_LONG_LONG
  248.     long long *microPtr;
  249. #endif
  250.     if (initalized == false) {
  251. GetDateTime(&baseSeconds);
  252. /*
  253.  * Remove the local offset that ReadDateTime() adds.
  254.  */
  255. baseSeconds -= TclpGetGMTOffset() - tcl_mac_epoch_offset;
  256. Microseconds(&microOffset);
  257. initalized = true;
  258.     }
  259.     Microseconds(&micro);
  260. #ifndef NO_LONG_LONG
  261.     microPtr = (long long *) &micro;
  262.     *microPtr -= *((long long *) &microOffset);
  263.     timePtr->sec = baseSeconds + (*microPtr / 1000000);
  264.     timePtr->usec = *microPtr % 1000000;
  265. #else
  266.     SubtractUnsignedWide(&micro, &microOffset, &micro);
  267.     /*
  268.      * This lovely computation is equal to: base + (micro / 1000000)
  269.      * For the .hi part the ratio of 0x100000000 / 1000000 has been
  270.      * reduced to avoid overflow.  This computation certainly has 
  271.      * problems as the .hi part gets large.  However, your application
  272.      * would have to run for a long time to make that happen.
  273.      */
  274.     timePtr->sec = baseSeconds + (micro.lo / 1000000) + 
  275.      (long) (micro.hi * ((double) 33554432.0 / 15625.0));
  276.     timePtr->usec = micro.lo % 1000000;
  277. #endif
  278. }
  279. /*
  280.  *----------------------------------------------------------------------
  281.  *
  282.  * TclpGetDate --
  283.  *
  284.  * Converts raw seconds to a struct tm data structure.  The
  285.  * returned time will be for Greenwich Mean Time if the useGMT flag 
  286.  * is set.  Otherwise, the returned time will be for the local
  287.  * time zone.  This function is meant to be used as a replacement
  288.  * for localtime and gmtime which is broken on most ANSI libs
  289.  * on the Macintosh.
  290.  *
  291.  * Results:
  292.  * None.
  293.  *
  294.  * Side effects:
  295.  *   The passed in struct tm data structure is modified.
  296.  *
  297.  *----------------------------------------------------------------------
  298.  */
  299. struct tm *
  300. TclpGetDate(
  301.     TclpTime_t time, /* Time struct to fill. */
  302.     int useGMT) /* True if date should reflect GNT time. */
  303. {
  304.     const time_t *tp = (const time_t *)time;
  305.     DateTimeRec dtr;
  306.     unsigned long offset=0L;
  307.     static struct tm statictime;
  308.     static const short monthday[12] =
  309.         {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  310.     
  311. if(useGMT)
  312. SecondsToDate(*tp - tcl_mac_epoch_offset, &dtr);
  313. else
  314. SecondsToDate(*tp + TclpGetGMTOffset() - tcl_mac_epoch_offset, &dtr);
  315.     statictime.tm_sec = dtr.second;
  316.     statictime.tm_min = dtr.minute;
  317.     statictime.tm_hour = dtr.hour;
  318.     statictime.tm_mday = dtr.day;
  319.     statictime.tm_mon = dtr.month - 1;
  320.     statictime.tm_year = dtr.year - 1900;
  321.     statictime.tm_wday = dtr.dayOfWeek - 1;
  322.     statictime.tm_yday = monthday[statictime.tm_mon]
  323. + statictime.tm_mday - 1;
  324.     if (1 < statictime.tm_mon && !(statictime.tm_year & 3)) {
  325. ++statictime.tm_yday;
  326.     }
  327.     if(useGMT)
  328.      statictime.tm_isdst = 0;
  329.     else
  330.      statictime.tm_isdst = gmt_isdst;
  331.     gmt_lastGetDateUseGMT=useGMT; /* hack to make TclpGetTZName below work */
  332.     return(&statictime);
  333. }
  334. /*
  335.  *----------------------------------------------------------------------
  336.  *
  337.  * TclpGetTZName --
  338.  *
  339.  * Gets the current timezone string.
  340.  *
  341.  * Results:
  342.  * Returns a pointer to a static string, or NULL on failure.
  343.  *
  344.  * Side effects:
  345.  * None.
  346.  *
  347.  *----------------------------------------------------------------------
  348.  */
  349. char *
  350. TclpGetTZName(int dst)
  351. {
  352.     register TABLE *tp;
  353. long zonevalue=-TclpGetGMTOffset();
  354.     if (gmt_isdst)
  355.         zonevalue += HOUR(1);
  356. if(gmt_lastGetDateUseGMT) /* hack: if last TclpGetDate was called */
  357. zonevalue=0;          /* with useGMT==1 then we're using GMT  */
  358.     for (tp = invTimezoneTable; tp->name; tp++) {
  359.         if ((tp->value == zonevalue) && (tp->type == dst)) break;
  360.     }
  361. if(!tp->name)
  362. tp = invTimezoneTable; /* default to unknown */
  363.     return tp->name;
  364. }
  365. #ifdef NO_LONG_LONG
  366. /*
  367.  *----------------------------------------------------------------------
  368.  *
  369.  * SubtractUnsignedWide --
  370.  *
  371.  * Subtracts one UnsignedWide value from another.
  372.  *
  373.  * Results:
  374.  *   The subtracted value.
  375.  *
  376.  * Side effects:
  377.  * None.
  378.  *
  379.  *----------------------------------------------------------------------
  380.  */
  381. static void
  382. SubtractUnsignedWide(
  383.     UnsignedWide *x, /* Ptr to wide int. */
  384.     UnsignedWide *y, /* Ptr to wide int. */
  385.     UnsignedWide *result) /* Ptr to result. */
  386. {
  387.     result->hi = x->hi - y->hi;
  388.     if (x->lo < y->lo) {
  389. result->hi--;
  390.     }
  391.     result->lo = x->lo - y->lo;
  392. }
  393. #endif