tclMacTime.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:13k
- /*
- * tclMacTime.c --
- *
- * Contains Macintosh specific versions of Tcl functions that
- * obtain time values from the operating system.
- *
- * Copyright (c) 1995-1997 Sun Microsystems, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tclMacTime.c,v 1.7 2002/01/04 11:21:05 das Exp $
- */
- #include "tclInt.h"
- #include "tclPort.h"
- #include "tclMacInt.h"
- #include <OSUtils.h>
- #include <Timer.h>
- #include <time.h>
- /*
- * Static variables used by the Tcl_GetTime function.
- */
-
- static int initalized = false;
- static unsigned long baseSeconds;
- static UnsignedWide microOffset;
- static int gmt_initialized = false;
- static long gmt_offset;
- static int gmt_isdst;
- TCL_DECLARE_MUTEX(gmtMutex)
- static int gmt_lastGetDateUseGMT = 0;
- typedef struct _TABLE {
- char *name;
- int type;
- time_t value;
- } TABLE;
- #define HOUR(x) ((time_t) (3600 * x))
- #define tZONE 0
- #define tDAYZONE 1
- /*
- * inverse timezone table, adapted from tclDate.c by removing duplicates and
- * adding some made up names for unusual daylight savings
- */
- static TABLE invTimezoneTable[] = {
- { "Z", -1, HOUR( 36) }, /* Unknown */
- { "GMT", tZONE, HOUR( 0) }, /* Greenwich Mean */
- { "BST", tDAYZONE, HOUR( 0) }, /* British Summer */
- { "WAT", tZONE, HOUR( 1) }, /* West Africa */
- { "WADST", tDAYZONE, HOUR( 1) }, /* West Africa Daylight*/
- { "AT", tZONE, HOUR( 2) }, /* Azores Daylight*/
- { "ADST", tDAYZONE, HOUR( 2) }, /* Azores */
- { "NFT", tZONE, HOUR( 7/2) }, /* Newfoundland */
- { "NDT", tDAYZONE, HOUR( 7/2) }, /* Newfoundland Daylight */
- { "AST", tZONE, HOUR( 4) }, /* Atlantic Standard */
- { "ADT", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
- { "EST", tZONE, HOUR( 5) }, /* Eastern Standard */
- { "EDT", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
- { "CST", tZONE, HOUR( 6) }, /* Central Standard */
- { "CDT", tDAYZONE, HOUR( 6) }, /* Central Daylight */
- { "MST", tZONE, HOUR( 7) }, /* Mountain Standard */
- { "MDT", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
- { "PST", tZONE, HOUR( 8) }, /* Pacific Standard */
- { "PDT", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
- { "YST", tZONE, HOUR( 9) }, /* Yukon Standard */
- { "YDT", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
- { "HST", tZONE, HOUR(10) }, /* Hawaii Standard */
- { "HDT", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
- { "NT", tZONE, HOUR(11) }, /* Nome */
- { "NST", tDAYZONE, HOUR(11) }, /* Nome Daylight*/
- { "IDLW", tZONE, HOUR(12) }, /* International Date Line West */
- { "CET", tZONE, -HOUR( 1) }, /* Central European */
- { "CEST", tDAYZONE, -HOUR( 1) }, /* Central European Summer */
- { "EET", tZONE, -HOUR( 2) }, /* Eastern Europe, USSR Zone 1 */
- { "EEST", tDAYZONE, -HOUR( 2) }, /* Eastern Europe, USSR Zone 1 Daylight*/
- { "BT", tZONE, -HOUR( 3) }, /* Baghdad, USSR Zone 2 */
- { "BDST", tDAYZONE, -HOUR( 3) }, /* Baghdad, USSR Zone 2 Daylight*/
- { "IT", tZONE, -HOUR( 7/2) }, /* Iran */
- { "IDST", tDAYZONE, -HOUR( 7/2) }, /* Iran Daylight*/
- { "ZP4", tZONE, -HOUR( 4) }, /* USSR Zone 3 */
- { "ZP4S", tDAYZONE, -HOUR( 4) }, /* USSR Zone 3 */
- { "ZP5", tZONE, -HOUR( 5) }, /* USSR Zone 4 */
- { "ZP5S", tDAYZONE, -HOUR( 5) }, /* USSR Zone 4 */
- { "IST", tZONE, -HOUR(11/2) }, /* Indian Standard */
- { "ISDST", tDAYZONE, -HOUR(11/2) }, /* Indian Standard */
- { "ZP6", tZONE, -HOUR( 6) }, /* USSR Zone 5 */
- { "ZP6S", tDAYZONE, -HOUR( 6) }, /* USSR Zone 5 */
- { "WAST", tZONE, -HOUR( 7) }, /* West Australian Standard */
- { "WADT", tDAYZONE, -HOUR( 7) }, /* West Australian Daylight */
- { "JT", tZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */
- { "JDST", tDAYZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */
- { "CCT", tZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */
- { "CCST", tDAYZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */
- { "JST", tZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */
- { "JSDST", tDAYZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */
- { "CAST", tZONE, -HOUR(19/2) }, /* Central Australian Standard */
- { "CADT", tDAYZONE, -HOUR(19/2) }, /* Central Australian Daylight */
- { "EAST", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
- { "EADT", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
- { "NZT", tZONE, -HOUR(12) }, /* New Zealand */
- { "NZDT", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
- { NULL }
- };
- /*
- * Prototypes for procedures that are private to this file:
- */
- static void SubtractUnsignedWide _ANSI_ARGS_((UnsignedWide *x,
- UnsignedWide *y, UnsignedWide *result));
- /*
- *-----------------------------------------------------------------------------
- *
- * TclpGetGMTOffset --
- *
- * This procedure gets the offset seconds that needs to be _added_ to tcl time
- * in seconds (i.e. GMT time) to get local time needed as input to various
- * Mac OS APIs, to convert Mac OS API output to tcl time, _subtract_ this value.
- *
- * Results:
- * Number of seconds separating GMT time and mac.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
- long
- TclpGetGMTOffset()
- {
- if (gmt_initialized == false) {
- MachineLocation loc;
-
- Tcl_MutexLock(&gmtMutex);
- ReadLocation(&loc);
- gmt_offset = loc.u.gmtDelta & 0x00ffffff;
- if (gmt_offset & 0x00800000) {
- gmt_offset = gmt_offset | 0xff000000;
- }
- gmt_isdst=(loc.u.dlsDelta < 0);
- gmt_initialized = true;
- Tcl_MutexUnlock(&gmtMutex);
- }
- return (gmt_offset);
- }
- /*
- *-----------------------------------------------------------------------------
- *
- * TclpGetSeconds --
- *
- * This procedure returns the number of seconds from the epoch. On
- * the Macintosh the epoch is Midnight Jan 1, 1904. Unfortunatly,
- * the Macintosh doesn't tie the epoch to a particular time zone. For
- * Tcl we tie the epoch to GMT. This makes the time zone date parsing
- * code work. The epoch for Mac-Tcl is: Midnight Jan 1, 1904 GMT.
- *
- * Results:
- * Number of seconds from the epoch in GMT.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
- unsigned long
- TclpGetSeconds()
- {
- unsigned long seconds;
- GetDateTime(&seconds);
- return (seconds - TclpGetGMTOffset() + tcl_mac_epoch_offset);
- }
- /*
- *-----------------------------------------------------------------------------
- *
- * TclpGetClicks --
- *
- * This procedure returns a value that represents the highest resolution
- * clock available on the system. There are no garantees on what the
- * resolution will be. In Tcl we will call this value a "click". The
- * start time is also system dependant.
- *
- * Results:
- * Number of clicks from some start time.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
- unsigned long
- TclpGetClicks()
- {
- UnsignedWide micros;
- Microseconds(µs);
- return micros.lo;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TclpGetTimeZone --
- *
- * Get the current time zone.
- *
- * Results:
- * The return value is the local time zone, measured in
- * minutes away from GMT (-ve for east, +ve for west).
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int
- TclpGetTimeZone (
- unsigned long currentTime) /* Ignored on Mac. */
- {
- long offset;
- /*
- * Convert the Mac offset from seconds to minutes and
- * add an hour if we have daylight savings time.
- */
- offset = -TclpGetGMTOffset();
- offset /= 60;
- if (gmt_isdst) {
- offset += 60;
- }
-
- return offset;
- }
- /*
- *----------------------------------------------------------------------
- *
- * Tcl_GetTime --
- *
- * Gets the current system time in seconds and microseconds
- * since the beginning of the epoch: 00:00 UCT, January 1, 1970.
- *
- * Results:
- * Returns the current time (in the local timezone) in timePtr.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- void
- Tcl_GetTime(
- Tcl_Time *timePtr) /* Location to store time information. */
- {
- UnsignedWide micro;
- #ifndef NO_LONG_LONG
- long long *microPtr;
- #endif
-
- if (initalized == false) {
- GetDateTime(&baseSeconds);
- /*
- * Remove the local offset that ReadDateTime() adds.
- */
- baseSeconds -= TclpGetGMTOffset() - tcl_mac_epoch_offset;
- Microseconds(µOffset);
- initalized = true;
- }
- Microseconds(µ);
- #ifndef NO_LONG_LONG
- microPtr = (long long *) µ
- *microPtr -= *((long long *) µOffset);
- timePtr->sec = baseSeconds + (*microPtr / 1000000);
- timePtr->usec = *microPtr % 1000000;
- #else
- SubtractUnsignedWide(µ, µOffset, µ);
- /*
- * This lovely computation is equal to: base + (micro / 1000000)
- * For the .hi part the ratio of 0x100000000 / 1000000 has been
- * reduced to avoid overflow. This computation certainly has
- * problems as the .hi part gets large. However, your application
- * would have to run for a long time to make that happen.
- */
- timePtr->sec = baseSeconds + (micro.lo / 1000000) +
- (long) (micro.hi * ((double) 33554432.0 / 15625.0));
- timePtr->usec = micro.lo % 1000000;
- #endif
- }
- /*
- *----------------------------------------------------------------------
- *
- * TclpGetDate --
- *
- * Converts raw seconds to a struct tm data structure. The
- * returned time will be for Greenwich Mean Time if the useGMT flag
- * is set. Otherwise, the returned time will be for the local
- * time zone. This function is meant to be used as a replacement
- * for localtime and gmtime which is broken on most ANSI libs
- * on the Macintosh.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The passed in struct tm data structure is modified.
- *
- *----------------------------------------------------------------------
- */
- struct tm *
- TclpGetDate(
- TclpTime_t time, /* Time struct to fill. */
- int useGMT) /* True if date should reflect GNT time. */
- {
- const time_t *tp = (const time_t *)time;
- DateTimeRec dtr;
- unsigned long offset=0L;
- static struct tm statictime;
- static const short monthday[12] =
- {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
-
- if(useGMT)
- SecondsToDate(*tp - tcl_mac_epoch_offset, &dtr);
- else
- SecondsToDate(*tp + TclpGetGMTOffset() - tcl_mac_epoch_offset, &dtr);
-
- statictime.tm_sec = dtr.second;
- statictime.tm_min = dtr.minute;
- statictime.tm_hour = dtr.hour;
- statictime.tm_mday = dtr.day;
- statictime.tm_mon = dtr.month - 1;
- statictime.tm_year = dtr.year - 1900;
- statictime.tm_wday = dtr.dayOfWeek - 1;
- statictime.tm_yday = monthday[statictime.tm_mon]
- + statictime.tm_mday - 1;
- if (1 < statictime.tm_mon && !(statictime.tm_year & 3)) {
- ++statictime.tm_yday;
- }
- if(useGMT)
- statictime.tm_isdst = 0;
- else
- statictime.tm_isdst = gmt_isdst;
- gmt_lastGetDateUseGMT=useGMT; /* hack to make TclpGetTZName below work */
- return(&statictime);
- }
- /*
- *----------------------------------------------------------------------
- *
- * TclpGetTZName --
- *
- * Gets the current timezone string.
- *
- * Results:
- * Returns a pointer to a static string, or NULL on failure.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- char *
- TclpGetTZName(int dst)
- {
- register TABLE *tp;
- long zonevalue=-TclpGetGMTOffset();
-
- if (gmt_isdst)
- zonevalue += HOUR(1);
- if(gmt_lastGetDateUseGMT) /* hack: if last TclpGetDate was called */
- zonevalue=0; /* with useGMT==1 then we're using GMT */
- for (tp = invTimezoneTable; tp->name; tp++) {
- if ((tp->value == zonevalue) && (tp->type == dst)) break;
- }
- if(!tp->name)
- tp = invTimezoneTable; /* default to unknown */
- return tp->name;
- }
- #ifdef NO_LONG_LONG
- /*
- *----------------------------------------------------------------------
- *
- * SubtractUnsignedWide --
- *
- * Subtracts one UnsignedWide value from another.
- *
- * Results:
- * The subtracted value.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static void
- SubtractUnsignedWide(
- UnsignedWide *x, /* Ptr to wide int. */
- UnsignedWide *y, /* Ptr to wide int. */
- UnsignedWide *result) /* Ptr to result. */
- {
- result->hi = x->hi - y->hi;
- if (x->lo < y->lo) {
- result->hi--;
- }
- result->lo = x->lo - y->lo;
- }
- #endif