// VitTimeLib.c // // Description on russian (charset KOI-8R). // // Убивши немало времени, чтобы разобраться с функциями времени, не могу // не поделиться впечатлениями. // // В C библиотеке есть функции для преобразования time_t в tm (time_t - // это время в секундах с 1 янв 1970, а tm - структура, где: год, месяц, // дни, часы, минуты, секунды). // // Но отсутствует напрочь функция для обратного преобразования tm в // time_t. А нужна (чтобы прочитать дату из http заголовков Last-Modified // и Date)! Поиски в инете кода для преобразования tm в time_t не // увенчались успехом, хотя потратил я на это несколько часов. // // В резульате непредвиденно больших напрягов родились таки функции, // которые это делают - это хозяйство в аттаченном VitTimeLib.zip Там всё // подогнано и проверено перебором всех дат (эта демка как раз перебирает // и печатает различия). // // И вот что интересно: // // 1. Программа, компилировванная Ms Visual C 6.0 возвращает NULL в // результате вызова gmtime когда доходит до time_t t=0x80000000: // time_t t=(time_t)0x80000000; // struct tm *tmStruc = gmtime(&t); // (это значит поддерживаются даты до 19.01.2038) // // 2. Программа, компилированная GCC глючит (неправильную дату печатет, // типа 1907 год), когда доходит до time_t = 0x80000000. И под Linux // тоже. // // 3. Самый стойкий оловянный солдатик оказался WatcomC 11.0 - только при // time_t t=0xF4D41F80 (01.03.2100) начинаются интересные вещи, наверное, // там действительно произойдёт сдвиг високосного года на нечётный или // просто и у Watcom-а имеются глюки в библиотеке. // // 4. И по-моему (хотя не уверен), глючит под Linux-ом localtime() - // выдаёт на 1 час меньше время. // // // 24.08.2000 // Vitaliy Vasiliev mailto:vitaliy_vasiliev@mail.ru // http://www.chat.ru/~vitaliy_vasiliev/ // http://free.prohosting.com/~vitivas/ #include <sys/types.h> #include <stdio.h> #include <time.h> #include <string.h> #include <stdlib.h> #ifdef WIN32 #include <io.h> #include <windows.h> #include <process.h> #endif void logoAndVersion(void) { printf("\n\ VitTimeLib demo: VIT(R) Time Functions Demo\n\ Version 1.0 Copyright (C) Vitaliy I. Vasiliev 24.08.2000\n\ Vitaliy Vasiliev homepage: http://www.chat.ru/~vitaliy_vasiliev/\n\ Vitaliy Vasiliev homepage mirror: http://free.prohosting.com/~vitivas/\n\ \n\ "); } void sleepThread(unsigned long dwMilliseconds) { #ifdef _GNU_SOURCE #ifdef WIN32 Sleep(dwMilliseconds); // under cygwin #else usleep(dwMilliseconds*1000); // under unix #endif #else Sleep(dwMilliseconds); // under win #endif } int szCmp(char *s1, char *s2) { #define CHAREOSTR ((unsigned char)'\0') #define StringCHAREOSTR "\0" if(*s1 == *s2) { while(*++s1 == *++s2) if((unsigned char)*s1<=CHAREOSTR) break; } return ((unsigned char)(*s1) - (unsigned char)(*s2)); } time_t tmToTimeT(struct tm *tmStruc) { // Note: to convert tm --> time_t available library functions: // tmStruc = gmtime(&timeOfDayGmt); // tmStruc = localtime(&timeOfDayGmt); // struct tm { // from <time.h> // int tm_sec; // seconds after the minute -- [0,61] // int tm_min; // minutes after the hour -- [0,59] // int tm_hour; // hours after midnight -- [0,23] // int tm_mday; // day of the month -- [1,31] // int tm_mon; // months since January -- [0,11] // int tm_year; // years since 1900 // int tm_wday; // days since Sunday -- [0,6] // int tm_yday; // days since January 1 -- [0,365] // int tm_isdst; // Daylight Savings Time flag */ // }; unsigned long i, date, month, year; date = tmStruc->tm_mday; // now: date=1...31 month = tmStruc->tm_mon; // now: month=0...11 year = 1900+tmStruc->tm_year; // now: year=0...9999 if(year<1970) return 0; year-=1970; i = year*366 + month*31 + (date-1); // subtracting number of full non-visokosnih years: i -= ((year+2)*3/4 - 1); // subtracting number of 30-day-months: if(month<7) i-=(month+0)/2; else i-=(month-1)/2; // subtracting 28-day-feb (if after): if(((year+2)%4) == 0) { // if visokosniy year: if(month>1) i-=1; } else { // if non-visokosniy year: if(month>1) i-=2; } i *= 24; i += tmStruc->tm_hour; i *= 60; i += tmStruc->tm_min; i *= 60; i += tmStruc->tm_sec; // WATCOM'S LIB after feb 2100: // // skip 1 day 01.03.2100 (in feb 2100) // WATCOM'S LIB after feb 2100: // if(i>=0xF4D57100) { // WATCOM'S LIB after feb 2100: // i-=60*60*24; // 0x15180 // WATCOM'S LIB after feb 2100: // } // WATCOM'S LIB after feb 2100: // if(i>=0xF72E9D00) { // WATCOM'S LIB after feb 2100: // i+=60*60*24; // WATCOM'S LIB after feb 2100: // } return i; } time_t stringTimeToTimeT(char *timeStringBuf) { unsigned long i, date, month, year; date = (*timeStringBuf++ - '0'); date*=10; date += (*timeStringBuf++ - '0'); // now: date=1...31 timeStringBuf++; // skip '.' month = (*timeStringBuf++ - '0'); month*=10; month += (*timeStringBuf++ - '0'); month--; // now: month=0...11 timeStringBuf++; // skip '.' year = (*timeStringBuf++ - '0'); year*=10; year += (*timeStringBuf++ - '0'); year*=10; year += (*timeStringBuf++ - '0'); year*=10; year += (*timeStringBuf++ - '0'); // now: year=0...9999 if(year<1970) return 0; year-=1970; i = year*366 + month*31 + (date-1); // subtracting number of full non-visokosnih years: i -= ((year+2)*3/4 - 1); // subtracting number of 30-day-months: if(month<7) i-=(month+0)/2; else i-=(month-1)/2; // subtracting 28-day-feb (if after): if(((year+2)%4) == 0) { // if visokosniy year: if(month>1) i-=1; } else { // if non-visokosniy year: if(month>1) i-=2; } i *= 24; timeStringBuf++; // skip ' ' i += (*timeStringBuf++ - '0')*10; // 0...2 (tens of hours) i += (*timeStringBuf++ - '0') ; // 0...9 hours i *= 60; timeStringBuf++; // skip ':' i += (*timeStringBuf++ - '0')*10; // 0...5 (tens of minutes) i += (*timeStringBuf++ - '0') ; // 0...9 minutes i *= 60; timeStringBuf++; // skip ':' i += (*timeStringBuf++ - '0')*10; // 0...5 (tens of seconds) i += (*timeStringBuf++ - '0') ; // 0...9 seconds // WATCOM'S LIB after feb 2100: // // skip 1 day 01.03.2100 (in feb 2100) // WATCOM'S LIB after feb 2100: // if(i>=0xF4D57100) { // WATCOM'S LIB after feb 2100: // i-=60*60*24; // 0x15180 // WATCOM'S LIB after feb 2100: // } // WATCOM'S LIB after feb 2100: // if(i>=0xF72E9D00) { // WATCOM'S LIB after feb 2100: // i+=60*60*24; // WATCOM'S LIB after feb 2100: // } return i; } void strftimeVit(char *timeStringBuf, time_t t) { // Note: time_t - is time in seconds since 1 jan 1970 unsigned long tt; // WATCOM'S LIB after feb 2100: // // skip 1 day 01.03.2100 (in feb 2100 must be 28 days?): // WATCOM'S LIB after feb 2100: // if(t>=0xF4D41F80) t+=60*60*24; // init. buf: timeStringBuf+=19; *timeStringBuf-- = 0; *timeStringBuf-- = (char)('0'+((unsigned long)t%10)); t=(unsigned long)t/10; // seconds *timeStringBuf-- = (char)('0'+(t%6)); t/=6; // tens of seconds *timeStringBuf-- = ':'; *timeStringBuf-- = (char)('0'+(t%10)); t/=10; // minutes *timeStringBuf-- = (char)('0'+(t%6)); t/=6; // tens of minutes *timeStringBuf-- = ':'; *timeStringBuf-- = (char)('0'+((t%24)%10)); // hours *timeStringBuf-- = (char)('0'+(t%24)/10); t/=24; // tens of hours *timeStringBuf-- = ' '; // So, here t=days_from_1970_year: tt = 1968 + ((t+365+366)*4)/(365*4+1); // years: *timeStringBuf-- = (char)('0'+(tt%10)); // years '9' *timeStringBuf-- = (char)('0'+((tt/10)%10)); // years '9' *timeStringBuf-- = (char)('0'+((tt/100)%10)); // years '9' *timeStringBuf-- = (char)('0'+((tt/1000)%10));// years '1' // computation: days since 1 jan of nearest 4*year: t = t+365+366 - (unsigned long)((t+365+366)/(365*4+1)) * (365*4+1); if(t<366) { // visokosniy year t=t%366; if(t>=31+29) t++; // (december 29 days-->30 days) } else { t=(t-366)%365; if(t>=31+28) t++; // (december 29 days-->30 days) if(t>=31+28) t++; } if(t<=31+30+31+30+31+30+31) { tt = t%(31+30); // day of 2*month (0...30) t = t/(31+30); // 2*month of year t = t*2 + tt/31; // month of year tt = tt%31; // day of 2*month (0...30) } else { t--; tt = t%(31+30); // day of 2*month (0...30) t = t/(31+30); // 2*month of year t = t*2; if(tt>=30) { t++; // month of year tt-=30; // day of 2*month (0...30) } } tt++; // tt = day: 1...31 t++; // tt = month: 1...12 *timeStringBuf-- = '.'; *timeStringBuf-- = (char)('0'+(t%10)); // month of year *timeStringBuf-- = (char)('0'+(t/10)); // month of year *timeStringBuf-- = '.'; *timeStringBuf-- = (char)('0'+(tt%10)); // day of month *timeStringBuf-- = (char)('0'+(tt/10)); // day of month } time_t getTzSecondsShift() { time_t timeOfDayGmt; time_t timeOfDayLocal; struct tm *tmStruc; timeOfDayGmt = 10000000; // time(NULL); tmStruc = localtime(&timeOfDayGmt); timeOfDayLocal = tmToTimeT(tmStruc); return timeOfDayLocal-timeOfDayGmt; } int main(int argc, char *argv[]) { time_t timeOfDayGmt; time_t timeOfDayLocal; char timeStringBuf[255]; char genStringBuf[255]; unsigned long i; int tzSecondsShift; logoAndVersion(); tzSecondsShift = getTzSecondsShift(); printf("TimeZone shift: getTzSecondsShift()=%d seconds (%d hours)\n", getTzSecondsShift(), tzSecondsShift/60/60); timeOfDayGmt = time(NULL); strftimeVit(timeStringBuf, timeOfDayGmt); printf("time(NULL) =%d: Now time GMT : %s\n", timeOfDayGmt, timeStringBuf); timeOfDayLocal = timeOfDayGmt+tzSecondsShift; strftimeVit(timeStringBuf, timeOfDayLocal); printf("time(NULL)+tzSecondsShift=%d: Now time LOCAL: %s\n", timeOfDayLocal, timeStringBuf); for(i=0; ; ) { struct tm *tmStruc; time_t t; //timeOfDayGmt = time(NULL); timeOfDayGmt=i; tmStruc = gmtime(&timeOfDayGmt); //tmStruc = localtime(&timeOfDayGmt); sprintf(timeStringBuf, "%02d.%02d.%04d %02d:%02d:%02d", tmStruc->tm_mday, tmStruc->tm_mon+1, 1900+tmStruc->tm_year, tmStruc->tm_hour, tmStruc->tm_min, tmStruc->tm_sec); strftimeVit(genStringBuf, i); t = stringTimeToTimeT(genStringBuf); if((int)t!=(int)i || szCmp(timeStringBuf, genStringBuf)!=0) { printf("i=0x%X t=0x%X tm_yday=%d %s|%s|\n", i, t, tmStruc->tm_yday, timeStringBuf, genStringBuf); sleepThread(2000); } //if(++i == 0) break; if((i+=60*60*24) > 0xfff00000) break; } exit(0); return 0; }
Created:
august 24, 2000,
http://www.chat.ru/~vitaliy_vasiliev/
http://free.prohosting.com/~vitivas/