os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacTime.c
Update contrib.
4 * Contains Macintosh specific versions of Tcl functions that
5 * obtain time values from the operating system.
7 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
9 * See the file "license.terms" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 * RCS: @(#) $Id: tclMacTime.c,v 1.7 2002/01/04 11:21:05 das Exp $
17 #include "tclMacInt.h"
23 * Static variables used by the Tcl_GetTime function.
26 static int initalized = false;
27 static unsigned long baseSeconds;
28 static UnsignedWide microOffset;
30 static int gmt_initialized = false;
31 static long gmt_offset;
33 TCL_DECLARE_MUTEX(gmtMutex)
35 static int gmt_lastGetDateUseGMT = 0;
37 typedef struct _TABLE {
44 #define HOUR(x) ((time_t) (3600 * x))
51 * inverse timezone table, adapted from tclDate.c by removing duplicates and
52 * adding some made up names for unusual daylight savings
54 static TABLE invTimezoneTable[] = {
55 { "Z", -1, HOUR( 36) }, /* Unknown */
56 { "GMT", tZONE, HOUR( 0) }, /* Greenwich Mean */
57 { "BST", tDAYZONE, HOUR( 0) }, /* British Summer */
58 { "WAT", tZONE, HOUR( 1) }, /* West Africa */
59 { "WADST", tDAYZONE, HOUR( 1) }, /* West Africa Daylight*/
60 { "AT", tZONE, HOUR( 2) }, /* Azores Daylight*/
61 { "ADST", tDAYZONE, HOUR( 2) }, /* Azores */
62 { "NFT", tZONE, HOUR( 7/2) }, /* Newfoundland */
63 { "NDT", tDAYZONE, HOUR( 7/2) }, /* Newfoundland Daylight */
64 { "AST", tZONE, HOUR( 4) }, /* Atlantic Standard */
65 { "ADT", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
66 { "EST", tZONE, HOUR( 5) }, /* Eastern Standard */
67 { "EDT", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
68 { "CST", tZONE, HOUR( 6) }, /* Central Standard */
69 { "CDT", tDAYZONE, HOUR( 6) }, /* Central Daylight */
70 { "MST", tZONE, HOUR( 7) }, /* Mountain Standard */
71 { "MDT", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
72 { "PST", tZONE, HOUR( 8) }, /* Pacific Standard */
73 { "PDT", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
74 { "YST", tZONE, HOUR( 9) }, /* Yukon Standard */
75 { "YDT", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
76 { "HST", tZONE, HOUR(10) }, /* Hawaii Standard */
77 { "HDT", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
78 { "NT", tZONE, HOUR(11) }, /* Nome */
79 { "NST", tDAYZONE, HOUR(11) }, /* Nome Daylight*/
80 { "IDLW", tZONE, HOUR(12) }, /* International Date Line West */
81 { "CET", tZONE, -HOUR( 1) }, /* Central European */
82 { "CEST", tDAYZONE, -HOUR( 1) }, /* Central European Summer */
83 { "EET", tZONE, -HOUR( 2) }, /* Eastern Europe, USSR Zone 1 */
84 { "EEST", tDAYZONE, -HOUR( 2) }, /* Eastern Europe, USSR Zone 1 Daylight*/
85 { "BT", tZONE, -HOUR( 3) }, /* Baghdad, USSR Zone 2 */
86 { "BDST", tDAYZONE, -HOUR( 3) }, /* Baghdad, USSR Zone 2 Daylight*/
87 { "IT", tZONE, -HOUR( 7/2) }, /* Iran */
88 { "IDST", tDAYZONE, -HOUR( 7/2) }, /* Iran Daylight*/
89 { "ZP4", tZONE, -HOUR( 4) }, /* USSR Zone 3 */
90 { "ZP4S", tDAYZONE, -HOUR( 4) }, /* USSR Zone 3 */
91 { "ZP5", tZONE, -HOUR( 5) }, /* USSR Zone 4 */
92 { "ZP5S", tDAYZONE, -HOUR( 5) }, /* USSR Zone 4 */
93 { "IST", tZONE, -HOUR(11/2) }, /* Indian Standard */
94 { "ISDST", tDAYZONE, -HOUR(11/2) }, /* Indian Standard */
95 { "ZP6", tZONE, -HOUR( 6) }, /* USSR Zone 5 */
96 { "ZP6S", tDAYZONE, -HOUR( 6) }, /* USSR Zone 5 */
97 { "WAST", tZONE, -HOUR( 7) }, /* West Australian Standard */
98 { "WADT", tDAYZONE, -HOUR( 7) }, /* West Australian Daylight */
99 { "JT", tZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */
100 { "JDST", tDAYZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */
101 { "CCT", tZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */
102 { "CCST", tDAYZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */
103 { "JST", tZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */
104 { "JSDST", tDAYZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */
105 { "CAST", tZONE, -HOUR(19/2) }, /* Central Australian Standard */
106 { "CADT", tDAYZONE, -HOUR(19/2) }, /* Central Australian Daylight */
107 { "EAST", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
108 { "EADT", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
109 { "NZT", tZONE, -HOUR(12) }, /* New Zealand */
110 { "NZDT", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
115 * Prototypes for procedures that are private to this file:
118 static void SubtractUnsignedWide _ANSI_ARGS_((UnsignedWide *x,
119 UnsignedWide *y, UnsignedWide *result));
122 *-----------------------------------------------------------------------------
124 * TclpGetGMTOffset --
126 * This procedure gets the offset seconds that needs to be _added_ to tcl time
127 * in seconds (i.e. GMT time) to get local time needed as input to various
128 * Mac OS APIs, to convert Mac OS API output to tcl time, _subtract_ this value.
131 * Number of seconds separating GMT time and mac.
136 *-----------------------------------------------------------------------------
142 if (gmt_initialized == false) {
145 Tcl_MutexLock(&gmtMutex);
147 gmt_offset = loc.u.gmtDelta & 0x00ffffff;
148 if (gmt_offset & 0x00800000) {
149 gmt_offset = gmt_offset | 0xff000000;
151 gmt_isdst=(loc.u.dlsDelta < 0);
152 gmt_initialized = true;
153 Tcl_MutexUnlock(&gmtMutex);
159 *-----------------------------------------------------------------------------
163 * This procedure returns the number of seconds from the epoch. On
164 * the Macintosh the epoch is Midnight Jan 1, 1904. Unfortunatly,
165 * the Macintosh doesn't tie the epoch to a particular time zone. For
166 * Tcl we tie the epoch to GMT. This makes the time zone date parsing
167 * code work. The epoch for Mac-Tcl is: Midnight Jan 1, 1904 GMT.
170 * Number of seconds from the epoch in GMT.
175 *-----------------------------------------------------------------------------
181 unsigned long seconds;
183 GetDateTime(&seconds);
184 return (seconds - TclpGetGMTOffset() + tcl_mac_epoch_offset);
188 *-----------------------------------------------------------------------------
192 * This procedure returns a value that represents the highest resolution
193 * clock available on the system. There are no garantees on what the
194 * resolution will be. In Tcl we will call this value a "click". The
195 * start time is also system dependant.
198 * Number of clicks from some start time.
203 *-----------------------------------------------------------------------------
211 Microseconds(µs);
216 *----------------------------------------------------------------------
220 * Get the current time zone.
223 * The return value is the local time zone, measured in
224 * minutes away from GMT (-ve for east, +ve for west).
229 *----------------------------------------------------------------------
234 unsigned long currentTime) /* Ignored on Mac. */
239 * Convert the Mac offset from seconds to minutes and
240 * add an hour if we have daylight savings time.
242 offset = -TclpGetGMTOffset();
252 *----------------------------------------------------------------------
256 * Gets the current system time in seconds and microseconds
257 * since the beginning of the epoch: 00:00 UCT, January 1, 1970.
260 * Returns the current time (in the local timezone) in timePtr.
265 *----------------------------------------------------------------------
270 Tcl_Time *timePtr) /* Location to store time information. */
277 if (initalized == false) {
278 GetDateTime(&baseSeconds);
280 * Remove the local offset that ReadDateTime() adds.
282 baseSeconds -= TclpGetGMTOffset() - tcl_mac_epoch_offset;
283 Microseconds(µOffset);
287 Microseconds(µ);
290 microPtr = (long long *) µ
291 *microPtr -= *((long long *) µOffset);
292 timePtr->sec = baseSeconds + (*microPtr / 1000000);
293 timePtr->usec = *microPtr % 1000000;
295 SubtractUnsignedWide(µ, µOffset, µ);
298 * This lovely computation is equal to: base + (micro / 1000000)
299 * For the .hi part the ratio of 0x100000000 / 1000000 has been
300 * reduced to avoid overflow. This computation certainly has
301 * problems as the .hi part gets large. However, your application
302 * would have to run for a long time to make that happen.
305 timePtr->sec = baseSeconds + (micro.lo / 1000000) +
306 (long) (micro.hi * ((double) 33554432.0 / 15625.0));
307 timePtr->usec = micro.lo % 1000000;
312 *----------------------------------------------------------------------
316 * Converts raw seconds to a struct tm data structure. The
317 * returned time will be for Greenwich Mean Time if the useGMT flag
318 * is set. Otherwise, the returned time will be for the local
319 * time zone. This function is meant to be used as a replacement
320 * for localtime and gmtime which is broken on most ANSI libs
327 * The passed in struct tm data structure is modified.
329 *----------------------------------------------------------------------
334 TclpTime_t time, /* Time struct to fill. */
335 int useGMT) /* True if date should reflect GNT time. */
337 const time_t *tp = (const time_t *)time;
339 unsigned long offset=0L;
340 static struct tm statictime;
341 static const short monthday[12] =
342 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
345 SecondsToDate(*tp - tcl_mac_epoch_offset, &dtr);
347 SecondsToDate(*tp + TclpGetGMTOffset() - tcl_mac_epoch_offset, &dtr);
349 statictime.tm_sec = dtr.second;
350 statictime.tm_min = dtr.minute;
351 statictime.tm_hour = dtr.hour;
352 statictime.tm_mday = dtr.day;
353 statictime.tm_mon = dtr.month - 1;
354 statictime.tm_year = dtr.year - 1900;
355 statictime.tm_wday = dtr.dayOfWeek - 1;
356 statictime.tm_yday = monthday[statictime.tm_mon]
357 + statictime.tm_mday - 1;
358 if (1 < statictime.tm_mon && !(statictime.tm_year & 3)) {
359 ++statictime.tm_yday;
362 statictime.tm_isdst = 0;
364 statictime.tm_isdst = gmt_isdst;
365 gmt_lastGetDateUseGMT=useGMT; /* hack to make TclpGetTZName below work */
370 *----------------------------------------------------------------------
374 * Gets the current timezone string.
377 * Returns a pointer to a static string, or NULL on failure.
382 *----------------------------------------------------------------------
386 TclpGetTZName(int dst)
389 long zonevalue=-TclpGetGMTOffset();
392 zonevalue += HOUR(1);
394 if(gmt_lastGetDateUseGMT) /* hack: if last TclpGetDate was called */
395 zonevalue=0; /* with useGMT==1 then we're using GMT */
397 for (tp = invTimezoneTable; tp->name; tp++) {
398 if ((tp->value == zonevalue) && (tp->type == dst)) break;
401 tp = invTimezoneTable; /* default to unknown */
408 *----------------------------------------------------------------------
410 * SubtractUnsignedWide --
412 * Subtracts one UnsignedWide value from another.
415 * The subtracted value.
420 *----------------------------------------------------------------------
424 SubtractUnsignedWide(
425 UnsignedWide *x, /* Ptr to wide int. */
426 UnsignedWide *y, /* Ptr to wide int. */
427 UnsignedWide *result) /* Ptr to result. */
429 result->hi = x->hi - y->hi;
433 result->lo = x->lo - y->lo;