Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

518 lines
14 KiB

  1. /* --------------------------------------------------------------------------
  2. timeconv.cpp
  3. Functions to perform various time conversion operations.
  4. Copyright (C) 1994, Microsoft Corporation.
  5. All rights reserved.
  6. Author:
  7. Lindsay Harris - lindsayh
  8. -------------------------------------------------------------------------- */
  9. //#include "tigris.hxx"
  10. #include "stdinc.h"
  11. #include <stdlib.h>
  12. /*
  13. * A handcrafted time zone string to GMT offsets table. This is not
  14. * a very good way to handle this.
  15. */
  16. static struct
  17. {
  18. int iTZOffset; // Arithmetic offset from GMT, in seconds.
  19. char rgchTZName[ 4 ]; // String representation of time zone.
  20. } _TZ_NAME[] =
  21. {
  22. { 0, { 'G', 'M', 'T', '\0' } },
  23. { 0, { 'U', 'T', 'C', '\0' } },
  24. { 0, { 'U', 'T', '\0', '\0' } },
  25. { -14400, { 'E', 'D', 'T', '\0' } },
  26. { -18000, { 'E', 'S', 'T', '\0' } },
  27. { -18000, { 'C', 'D', 'T', '\0' } },
  28. { -21600, { 'C', 'S', 'T', '\0' } },
  29. { -21600, { 'M', 'D', 'T', '\0' } },
  30. { -25200, { 'M', 'S', 'T', '\0' } },
  31. { -25200, { 'P', 'D', 'T', '\0' } },
  32. { -28800, { 'P', 'S', 'T', '\0' } },
  33. { 43200, { 'N', 'Z', 'S', '\0' } }, // NZ standard time.
  34. { 46800, { 'N', 'Z', 'D', '\0' } },
  35. };
  36. #define NUM_TZ (sizeof( _TZ_NAME ) / sizeof( _TZ_NAME[ 0 ] ))
  37. // The date Jan 1, 1970 00:00:00 in type FILETIME
  38. #define ft1970high 27111902
  39. #define ft1970low 3577643008
  40. static FILETIME ft1970 = {ft1970low, ft1970high};
  41. // The number of FILETIME units (100's of nanoseconds) in a time_t unit (seconds)
  42. #define dFiletimePerDTime_t 10000000
  43. #define BUNCH_FACTOR 6
  44. #define MESSAGE_ID_SPAN 64
  45. char MsgIdSet[MESSAGE_ID_SPAN] = {
  46. 'A','B','C','D','E','F','G','H','I','J','K','L','M',
  47. 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
  48. 'a','b','c','d','e','f','g','h','i','j','k','l','m',
  49. 'n','o','p','q','r','s','t','u','v','w','x','y','z',
  50. '0','1','2','3','4','5','6','7','8','9','#','$'
  51. };
  52. /*
  53. * English language month table.
  54. */
  55. static char *rgchMonth[ 12 ] =
  56. {
  57. "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  58. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  59. };
  60. /*
  61. * English language weekday table.
  62. */
  63. static char *rgchDayOfWeek[ 7 ] =
  64. {
  65. "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
  66. };
  67. /* --------------------------------------------------------------------------
  68. dwConvertAsciiTime
  69. Convert a usenet (unix) style date string into a MOS time value. There
  70. seem to be some variations on this format. Time returned is GMT/UNC.
  71. Author:
  72. Lindsay Harris - lindsayh
  73. History:
  74. 13:49 on Thu 31 Mar 1994 -by- Lindsay Harris [lindsayh]
  75. First version.
  76. -------------------------------------------------------------------------- */
  77. BOOL
  78. ConvertAsciiTime( char *pchInput, FILETIME &filetime )
  79. {
  80. DWORD dwRet; // Return value, 0 on error.
  81. int iTZOffset = 0; // Time zone offset, if it can be decided.
  82. SYSTEMTIME tm; // Result is built in here.
  83. char *pchTemp;
  84. dwRet = 0;
  85. GetSystemTime(&tm);
  86. // if less then 2 char long, skip everything and use system time (so we won't read invalid data)
  87. if( (strlen(pchInput) > 2) && (pchTemp = strchr( pchInput+2, ':' ) ) )
  88. {
  89. /*
  90. * Found a colon, which separates hours and minutes. Probably valid.
  91. * The other part of the test is if the preceeding character is a
  92. * digit which is also preceeded by either a digit or a space char.
  93. * That is, we have either <digit><digit>: or <space><digit>:
  94. */
  95. // if it's not <space><digit>:<digit><digit> or <digit><digit>:<digit><digit>, skip everything and use system time
  96. if( isdigit( (UCHAR)*(pchTemp - 1) ) &&
  97. (isdigit( (UCHAR)*(pchTemp - 2) ) || *(pchTemp - 2) == ' ') &&
  98. isdigit( (UCHAR)*(pchTemp + 1) ) &&
  99. isdigit( (UCHAR)*(pchTemp + 2) )
  100. )
  101. {
  102. tm.wHour = (WORD)atoi( pchTemp - 2 );
  103. tm.wMinute = (WORD)atoi( pchTemp + 1 );
  104. pchTemp += 3; // Skip to char after minutes digit.
  105. if( *pchTemp == ':' )
  106. {
  107. tm.wSecond = (WORD)atoi( pchTemp + 1 );
  108. tm.wMilliseconds = 0;
  109. pchTemp += 3; // Skip :ss to first byte past end.
  110. }
  111. else
  112. {
  113. tm.wSecond = 0;
  114. tm.wMilliseconds = 0;
  115. }
  116. // Time zone information - much guess work here!
  117. while( *pchTemp && *pchTemp == ' ' )
  118. ++pchTemp;
  119. /*
  120. * Sometimes there is a time zone offset encoded. This starts
  121. * with either a + or - sign or a digit, having 4 digits in all.
  122. * Otherwise, presume it is some sort of time zone string,
  123. * of 3 letters and totally ambiguous as to where it is unless
  124. * it happens to be GMT.
  125. */
  126. if( *pchTemp == '-' || *pchTemp == '+' || isdigit( (UCHAR)*pchTemp ) )
  127. {
  128. // Appears to be numeric value.
  129. int iSign;
  130. iSign = *pchTemp == '-' ? -60 : 60;
  131. if( !isdigit( (UCHAR)*pchTemp ) )
  132. ++pchTemp; // Skip the sign.
  133. // if incorrect formatted, skip the timezone adjustment.
  134. if( isdigit( (UCHAR)*pchTemp ) && isdigit( (UCHAR)*(pchTemp+1) ) &&
  135. isdigit( (UCHAR)*(pchTemp+2) ) && isdigit( (UCHAR)*(pchTemp+3) ) )
  136. {
  137. iTZOffset = (*pchTemp - '0') * 10 + *(pchTemp + 1) - '0';
  138. pchTemp += 2;
  139. iTZOffset *= 60; // Into minutes.
  140. iTZOffset += (*pchTemp - '0') * 10 + *(pchTemp + 1) - '0';
  141. iTZOffset *= iSign; // Into seconds.
  142. }
  143. }
  144. else
  145. {
  146. int iIndex;
  147. iTZOffset = 0; // Default to GMT if nothing found.
  148. for( iIndex = 0; iIndex < NUM_TZ; ++iIndex )
  149. {
  150. if( !strncmp( pchTemp, _TZ_NAME[ iIndex ].rgchTZName, 3 ) )
  151. {
  152. iTZOffset = _TZ_NAME[ iIndex ].iTZOffset;
  153. break;
  154. }
  155. }
  156. }
  157. /*
  158. * Now try for the date. The format is day of month, three
  159. * letter abbreviation of month, then year, as either 2 or 4
  160. * digits. This is at the start of the string, possibly
  161. * preceeded by a 3 letter day of week with following comma.
  162. */
  163. pchTemp = pchInput;
  164. // skip over any leading blanks
  165. while( *pchTemp && *pchTemp == ' ' )
  166. ++pchTemp;
  167. // make sure we don't pass the end of string
  168. if( (strlen(pchTemp) > 5) && (*(pchTemp + 3) == ',' ) )
  169. pchTemp += 5; // Skip over day + comma + space.
  170. if( (*pchTemp == ' ' || isdigit( (UCHAR)*pchTemp )) &&
  171. (*(pchTemp + 1) == ' ' || isdigit( (UCHAR)*(pchTemp + 1) )) )
  172. {
  173. // Looks good, so turn into day of month.
  174. int iIndex;
  175. tm.wDay = 0;
  176. if( isdigit( (UCHAR)*pchTemp ) )
  177. tm.wDay = *pchTemp - '0';
  178. ++pchTemp;
  179. if( isdigit( (UCHAR)*pchTemp ) )
  180. tm.wDay = tm.wDay * 10 + *pchTemp++ - '0';
  181. pchTemp++; // Skip the space before name of month.
  182. // make sure we have month and a space after it
  183. if (strlen(pchTemp) >= 4)
  184. {
  185. for( iIndex = 0; iIndex < 12; ++iIndex )
  186. {
  187. if( strncmp( pchTemp, rgchMonth[ iIndex ], 3 ) == 0 )
  188. {
  189. tm.wMonth = iIndex + 1;
  190. break;
  191. }
  192. }
  193. pchTemp += 4;
  194. iIndex = atoi( pchTemp );
  195. if( iIndex < 50 ) {
  196. iIndex += 2000;
  197. } else if (iIndex < 100) {
  198. iIndex += 1900;
  199. }
  200. tm.wYear = (WORD)iIndex;
  201. }
  202. }
  203. }
  204. }
  205. return SystemTimeToFileTime( &tm, &filetime ) ;
  206. }
  207. /* -----------------------------------------------------------------------
  208. GetArpaDate
  209. Returns a pointer to static memory containing the current date in
  210. Internet/ARPA standard format.
  211. Author
  212. Lindsay Harris - lindasyh
  213. History
  214. 13:49 on Wed 20 Apr 1994 -by- Lindsay Harris [lindsayh]
  215. First version.
  216. Imported to Tigris. Added passed-in buffer, changed year to 4-digit format
  217. ----------------------------------------------------------------------- */
  218. char *
  219. GetArpaDate( char achReturn[ cMaxArpaDate ] )
  220. {
  221. char chSign; // Sign to print.
  222. DWORD dwResult;
  223. int iBias; // Offset relative to GMT.
  224. TIME_ZONE_INFORMATION tzi; // Local time zone data.
  225. SYSTEMTIME stUTC; // The current time in UTC/GMT
  226. dwResult = GetTimeZoneInformation( &tzi );
  227. GetLocalTime( &stUTC );
  228. // Calculate the time zone offset.
  229. iBias = tzi.Bias;
  230. if( dwResult == TIME_ZONE_ID_DAYLIGHT )
  231. iBias += tzi.DaylightBias;
  232. /*
  233. * We always want to print the sign for the time zone offset, so
  234. * we decide what it is now and remember that when converting.
  235. * The convention is that west of the 0 degree meridian has a
  236. * negative offset - i.e. add the offset to GMT to get local time.
  237. */
  238. if( iBias > 0 )
  239. {
  240. chSign = '-'; // Yes, I do mean negative.
  241. }
  242. else
  243. {
  244. iBias = -iBias;
  245. chSign = '+';
  246. }
  247. /*
  248. * No major trickery here. We have all the data, so simply
  249. * format it according to the rules on how to do this.
  250. */
  251. _snprintf( achReturn, cMaxArpaDate , "%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d",
  252. rgchDayOfWeek[stUTC.wDayOfWeek], stUTC.wDay, rgchMonth[ stUTC.wMonth - 1 ],
  253. stUTC.wYear,
  254. stUTC.wHour, stUTC.wMinute, stUTC.wSecond, chSign,
  255. (iBias / 60) % 100, iBias % 60 );
  256. return achReturn;
  257. }
  258. /* -----------------------------------------------------------------------
  259. GetMessageIDDate
  260. ----------------------------------------------------------------------- */
  261. char *
  262. GetMessageIDDate( DWORD GroupId, DWORD ArticleId, char achReturn[ cMaxMessageIDDate ] )
  263. {
  264. SYSTEMTIME stUTC; // The current time in UTC/GMT
  265. FILETIME ftUTC;
  266. DWORD NumSextets = (sizeof(MsgIdSet) / BUNCH_FACTOR)+1;
  267. LARGE_INTEGER liMask;
  268. LARGE_INTEGER liSextet;
  269. LARGE_INTEGER * pliDate;
  270. #if 0
  271. GetSystemTime( &stUTC );
  272. /*
  273. * No major trickery here. We have all the data, so simply
  274. * format it according to the rules on how to do this.
  275. */
  276. wsprintf( achReturn, "%d%s%d.%02d%02d%02d%04d",
  277. stUTC.wYear,
  278. rgchMonth[ stUTC.wMonth - 1 ],
  279. stUTC.wDay,
  280. stUTC.wHour,
  281. stUTC.wMinute,
  282. stUTC.wSecond,
  283. stUTC.wMilliseconds);
  284. #endif
  285. // If articles are created sufficiently close, use the sum of grp and art id to create a difference
  286. // NOTE: Only 24 bits are taken so that the difference is within 1.6 secs
  287. DWORD dwGrpArtSuffix = GroupId + ArticleId;
  288. dwGrpArtSuffix &= 0x00ffffff;
  289. GetSystemTime( &stUTC );
  290. SystemTimeToFileTime( &stUTC, &ftUTC );
  291. liMask.QuadPart = 0x3F; // Mask to get sextets
  292. pliDate = (LARGE_INTEGER *) (void *) & ftUTC;
  293. // add a 24-bit offset that is a function of the group id and article id
  294. pliDate->QuadPart += dwGrpArtSuffix;
  295. // For each sextet in the date, lookup a char in the lookup array
  296. for(DWORD i=0; i<NumSextets; i++)
  297. {
  298. liSextet.QuadPart = ( pliDate->QuadPart ) & liMask.QuadPart;
  299. liSextet.QuadPart >>= i*BUNCH_FACTOR;
  300. liMask.QuadPart <<= BUNCH_FACTOR;
  301. _ASSERT( 0 <= liSextet.QuadPart && liSextet.QuadPart <= MESSAGE_ID_SPAN-1 );
  302. achReturn [i] = MsgIdSet [liSextet.QuadPart];
  303. }
  304. achReturn [i] = '\0';
  305. return achReturn;
  306. }
  307. /* -----------------------------------------------------------------------
  308. SystemTimeToTime_T
  309. Coverts SYSTEMTIME to time_t.
  310. Returns 0 if date is before 1970 or -1 if far, far into the future.
  311. Author
  312. Carl Kadie - carlk
  313. History
  314. Thu, 15 Dec 1994 -by- Carl Kadie [carlk]
  315. First version.
  316. ----------------------------------------------------------------------- */
  317. time_t
  318. SystemTimeToTime_T(SYSTEMTIME & st)
  319. {
  320. FILETIME ft;
  321. // Convert from SYSTEMTIME to FILETIME
  322. SystemTimeToFileTime(&st, &ft);
  323. // If date is before 1970, return 0
  324. if (filetimeGreaterThan(ft1970, ft))
  325. {
  326. return 0;
  327. } else {
  328. // Convert from FILETIME to time_t
  329. ft = filetimeSubtract(ft, ft1970);
  330. return dTime_tFromDFiletime(ft);
  331. }
  332. }
  333. /* -----------------------------------------------------------------------
  334. dTime_tFromDFiletime
  335. Converts changes in filetimes (dFiletime) to changes in time_ts (dTime_t)
  336. Do not use to change absolute FILETIME's to absolute time_t's
  337. Returns -1 if the dFiletime overflows the dTime_t
  338. Author
  339. Carl Kadie - carlk
  340. History
  341. 24 March 1995 - by - Carl Kadie [carlk]
  342. ----------------------------------------------------------------------- */
  343. time_t
  344. dTime_tFromDFiletime(const FILETIME & ft)
  345. {
  346. _ASSERT(sizeof(LARGE_INTEGER) == sizeof(FILETIME));
  347. _ASSERT(sizeof(LARGE_INTEGER) == (2 * sizeof(time_t)));
  348. LARGE_INTEGER * pli = (LARGE_INTEGER *)(void *) &ft;
  349. LARGE_INTEGER liHold;
  350. liHold.QuadPart = pli->QuadPart / dFiletimePerDTime_t;
  351. if (0 == liHold.HighPart)
  352. return (time_t) liHold.LowPart;
  353. else
  354. return (time_t) -1;
  355. }
  356. /* -----------------------------------------------------------------------
  357. filetimeSubtract
  358. Subtract two filetimes (or subtract a filetime by a dFiletime)
  359. Author
  360. Carl Kadie - carlk
  361. History
  362. 24 March 1995 - by - Carl Kadie [carlk]
  363. ----------------------------------------------------------------------- */
  364. FILETIME
  365. filetimeSubtract(const FILETIME & ft1, const FILETIME & ft2)
  366. {
  367. LARGE_INTEGER li;
  368. LARGE_INTEGER * pli1 = (LARGE_INTEGER *) (void *) & ft1;
  369. LARGE_INTEGER * pli2 = (LARGE_INTEGER *) (void *) & ft2;
  370. _ASSERT(0 <= pli1->HighPart && 0 <= pli2->HighPart); //LargeInteger is signed, FILETIME is not
  371. li.QuadPart = pli1->QuadPart - pli2->QuadPart;
  372. return *((FILETIME *)(void *)(&li));
  373. }
  374. /* -----------------------------------------------------------------------
  375. filetimeGreaterThan
  376. Compare two filetimes
  377. Author
  378. Carl Kadie - carlk
  379. History
  380. 24 March 1995 - by - Carl Kadie [carlk]
  381. ----------------------------------------------------------------------- */
  382. BOOL
  383. filetimeGreaterThan(const FILETIME & ft1, const FILETIME & ft2)
  384. {
  385. return ((ft1.dwHighDateTime == ft2.dwHighDateTime) && (ft1.dwLowDateTime > ft2.dwLowDateTime)) ||
  386. (ft1.dwHighDateTime > ft2.dwHighDateTime);
  387. }