📄 tclwintime.c
字号:
* Skip the offset string and get the DST string. */ p = zone + len; p += strspn(p, "+-:0123456789"); if (*p != '\0') { zone = p; len = strlen(zone); if (len > 3) { len = 3; } } } Tcl_ExternalToUtf(NULL, NULL, zone, len, 0, NULL, name, sizeof(tsdPtr->tzName), NULL, NULL, NULL); } if (name[0] == '\0') { if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_UNKNOWN) { /* * MSDN: On NT this is returned if DST is not used in * the current TZ */ dst = 0; } encoding = Tcl_GetEncoding(NULL, "unicode"); Tcl_ExternalToUtf(NULL, encoding, (char *) ((dst) ? tz.DaylightName : tz.StandardName), -1, 0, NULL, name, sizeof(tsdPtr->tzName), NULL, NULL, NULL); Tcl_FreeEncoding(encoding); } return name;}/* *---------------------------------------------------------------------- * * TclpGetDate -- * * This function converts between seconds and struct tm. If * useGMT is true, then the returned date will be in Greenwich * Mean Time (GMT). Otherwise, it will be in the local time zone. * * Results: * Returns a static tm structure. * * Side effects: * None. * *---------------------------------------------------------------------- */struct tm *TclpGetDate(t, useGMT) TclpTime_t t; int useGMT;{ const time_t *tp = (const time_t *) t; struct tm *tmPtr; long time; if (!useGMT) { tzset(); /* * If we are in the valid range, let the C run-time library * handle it. Otherwise we need to fake it. Note that this * algorithm ignores daylight savings time before the epoch. */ if (*tp >= 0) { return localtime(tp); } time = *tp - _timezone; /* * If we aren't near to overflowing the long, just add the bias and * use the normal calculation. Otherwise we will need to adjust * the result at the end. */ if (*tp < (LONG_MAX - 2 * SECSPERDAY) && *tp > (LONG_MIN + 2 * SECSPERDAY)) { tmPtr = ComputeGMT(&time); } else { tmPtr = ComputeGMT(tp); tzset(); /* * Add the bias directly to the tm structure to avoid overflow. * Propagate seconds overflow into minutes, hours and days. */ time = tmPtr->tm_sec - _timezone; tmPtr->tm_sec = (int)(time % 60); if (tmPtr->tm_sec < 0) { tmPtr->tm_sec += 60; time -= 60; } time = tmPtr->tm_min + time/60; tmPtr->tm_min = (int)(time % 60); if (tmPtr->tm_min < 0) { tmPtr->tm_min += 60; time -= 60; } time = tmPtr->tm_hour + time/60; tmPtr->tm_hour = (int)(time % 24); if (tmPtr->tm_hour < 0) { tmPtr->tm_hour += 24; time -= 24; } time /= 24; tmPtr->tm_mday += time; tmPtr->tm_yday += time; tmPtr->tm_wday = (tmPtr->tm_wday + time) % 7; } } else { tmPtr = ComputeGMT(tp); } return tmPtr;}/* *---------------------------------------------------------------------- * * ComputeGMT -- * * This function computes GMT given the number of seconds since * the epoch (midnight Jan 1 1970). * * Results: * Returns a (per thread) statically allocated struct tm. * * Side effects: * Updates the values of the static struct tm. * *---------------------------------------------------------------------- */static struct tm *ComputeGMT(tp) const time_t *tp;{ struct tm *tmPtr; long tmp, rem; int isLeap; int *days; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); tmPtr = &tsdPtr->tm; /* * Compute the 4 year span containing the specified time. */ tmp = *tp / SECSPER4YEAR; rem = *tp % SECSPER4YEAR; /* * Correct for weird mod semantics so the remainder is always positive. */ if (rem < 0) { tmp--; rem += SECSPER4YEAR; } /* * Compute the year after 1900 by taking the 4 year span and adjusting * for the remainder. This works because 2000 is a leap year, and * 1900/2100 are out of the range. */ tmp = (tmp * 4) + 70; isLeap = 0; if (rem >= SECSPERYEAR) { /* 1971, etc. */ tmp++; rem -= SECSPERYEAR; if (rem >= SECSPERYEAR) { /* 1972, etc. */ tmp++; rem -= SECSPERYEAR; if (rem >= SECSPERYEAR + SECSPERDAY) { /* 1973, etc. */ tmp++; rem -= SECSPERYEAR + SECSPERDAY; } else { isLeap = 1; } } } tmPtr->tm_year = tmp; /* * Compute the day of year and leave the seconds in the current day in * the remainder. */ tmPtr->tm_yday = rem / SECSPERDAY; rem %= SECSPERDAY; /* * Compute the time of day. */ tmPtr->tm_hour = rem / 3600; rem %= 3600; tmPtr->tm_min = rem / 60; tmPtr->tm_sec = rem % 60; /* * Compute the month and day of month. */ days = (isLeap) ? leapDays : normalDays; for (tmp = 1; days[tmp] < tmPtr->tm_yday; tmp++) { } tmPtr->tm_mon = --tmp; tmPtr->tm_mday = tmPtr->tm_yday - days[tmp]; /* * Compute day of week. Epoch started on a Thursday. */ tmPtr->tm_wday = (*tp / SECSPERDAY) + 4; if ((*tp % SECSPERDAY) < 0) { tmPtr->tm_wday--; } tmPtr->tm_wday %= 7; if (tmPtr->tm_wday < 0) { tmPtr->tm_wday += 7; } return tmPtr;}/* *---------------------------------------------------------------------- * * CalibrationThread -- * * Thread that manages calibration of the hi-resolution time * derived from the performance counter, to keep it synchronized * with the system clock. * * Parameters: * arg -- Client data from the CreateThread call. This parameter * points to the static TimeInfo structure. * * Return value: * None. This thread embeds an infinite loop. * * Side effects: * At an interval of clockCalibrateWakeupInterval ms, this thread * performs virtual time discipline. * * Note: When this thread is entered, TclpInitLock has been called * to safeguard the static storage. There is therefore no synchronization * in the body of this procedure. * *---------------------------------------------------------------------- */static DWORD WINAPICalibrationThread( LPVOID arg ){ FILETIME curFileTime; DWORD waitResult; /* Get initial system time and performance counter */ GetSystemTimeAsFileTime( &curFileTime ); QueryPerformanceCounter( &timeInfo.lastCounter ); QueryPerformanceFrequency( &timeInfo.curCounterFreq ); timeInfo.lastFileTime.LowPart = curFileTime.dwLowDateTime; timeInfo.lastFileTime.HighPart = curFileTime.dwHighDateTime; /* Initialize the working storage for the calibration callback */ timeInfo.lastPerfCounter = timeInfo.lastCounter.QuadPart; timeInfo.estPerfCounterFreq = timeInfo.curCounterFreq.QuadPart; /* * Wake up the calling thread. When it wakes up, it will release the * initialization lock. */ SetEvent( timeInfo.readyEvent ); /* Run the calibration once a second */ for ( ; ; ) { /* If the exitEvent is set, break out of the loop. */ waitResult = WaitForSingleObjectEx(timeInfo.exitEvent, 1000, FALSE); if ( waitResult == WAIT_OBJECT_0 ) { break; } UpdateTimeEachSecond(); } /* lint */ return (DWORD) 0;}/* *---------------------------------------------------------------------- * * UpdateTimeEachSecond -- * * Callback from the waitable timer in the clock calibration thread * that updates system time. * * Parameters: * info -- Pointer to the static TimeInfo structure * * Results: * None. * * Side effects: * Performs virtual time calibration discipline. * *---------------------------------------------------------------------- */static voidUpdateTimeEachSecond(){ LARGE_INTEGER curPerfCounter; /* Current value returned from * QueryPerformanceCounter */ LONGLONG perfCounterDiff; /* Difference between the current value * and the value of 1 second ago */ FILETIME curSysTime; /* Current system time */ LARGE_INTEGER curFileTime; /* File time at the time this callback * was scheduled. */ LONGLONG fileTimeDiff; /* Elapsed time on the system clock * since the last time this procedure * was called */ LONGLONG instantFreq; /* Instantaneous estimate of the * performance counter frequency */ LONGLONG delta; /* Increment to add to the estimated * performance counter frequency in the * loop filter */ LONGLONG fuzz; /* Tolerance for the perf counter frequency */ LONGLONG lowBound; /* Lower bound for the frequency assuming * 1000 ppm tolerance */ LONGLONG hiBound; /* Upper bound for the frequency */ /* * Get current performance counter and system time. */ QueryPerformanceCounter( &curPerfCounter ); GetSystemTimeAsFileTime( &curSysTime ); curFileTime.LowPart = curSysTime.dwLowDateTime; curFileTime.HighPart = curSysTime.dwHighDateTime; EnterCriticalSection( &timeInfo.cs ); /* * Find out how many ticks of the performance counter and the * system clock have elapsed since we got into this procedure. * Estimate the current frequency. */ perfCounterDiff = curPerfCounter.QuadPart - timeInfo.lastPerfCounter; timeInfo.lastPerfCounter = curPerfCounter.QuadPart; fileTimeDiff = curFileTime.QuadPart - timeInfo.lastSysTime; timeInfo.lastSysTime = curFileTime.QuadPart; instantFreq = ( 10000000 * perfCounterDiff / fileTimeDiff ); /* * Consider this a timing glitch if instant frequency varies * significantly from the current estimate. */ fuzz = timeInfo.estPerfCounterFreq >> 10; lowBound = timeInfo.estPerfCounterFreq - fuzz; hiBound = timeInfo.estPerfCounterFreq + fuzz; if ( instantFreq < lowBound || instantFreq > hiBound ) { LeaveCriticalSection( &timeInfo.cs ); return; } /* * Update the current estimate of performance counter frequency. * This code is equivalent to the loop filter of a phase locked * loop. */ delta = ( instantFreq - timeInfo.estPerfCounterFreq ) >> 6; timeInfo.estPerfCounterFreq += delta; /* * Update the current virtual time. */ timeInfo.lastFileTime.QuadPart += ( ( curPerfCounter.QuadPart - timeInfo.lastCounter.QuadPart ) * 10000000 / timeInfo.curCounterFreq.QuadPart ); timeInfo.lastCounter.QuadPart = curPerfCounter.QuadPart; delta = curFileTime.QuadPart - timeInfo.lastFileTime.QuadPart; if ( delta > 10000000 || delta < -10000000 ) { /* * If the virtual time slip exceeds one second, then adjusting * the counter frequency is hopeless (it'll take over fifteen * minutes to line up with the system clock). The most likely * cause of this large a slip is a sudden change to the system * clock, perhaps because it was being corrected by wristwatch * and eyeball. Accept the system time, and set the performance * counter frequency to the current estimate. */ timeInfo.lastFileTime.QuadPart = curFileTime.QuadPart; timeInfo.curCounterFreq.QuadPart = timeInfo.estPerfCounterFreq; } else { /* * Compute a counter frequency that will cause virtual time to line * up with system time one second from now, assuming that the * performance counter continues to tick at timeInfo.estPerfCounterFreq. */ timeInfo.curCounterFreq.QuadPart = 10000000 * timeInfo.estPerfCounterFreq / ( delta + 10000000 ); /* * Limit frequency excursions to 1000 ppm from estimate */ if ( timeInfo.curCounterFreq.QuadPart < lowBound ) { timeInfo.curCounterFreq.QuadPart = lowBound; } else if ( timeInfo.curCounterFreq.QuadPart > hiBound ) { timeInfo.curCounterFreq.QuadPart = hiBound; } } LeaveCriticalSection( &timeInfo.cs );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -