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.

617 lines
15 KiB

  1. /////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998 Active Voice Corporation. All Rights Reserved.
  4. //
  5. // Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation.
  6. //
  7. // Other brand and product names used herein are trademarks of their respective owners.
  8. //
  9. // The entire program and user interface including the structure, sequence, selection,
  10. // and arrangement of the dialog, the exclusively "yes" and "no" choices represented
  11. // by "1" and "2," and each dialog message are protected by copyrights registered in
  12. // the United States and by international treaties.
  13. //
  14. // Protected by one or more of the following United States patents: 5,070,526, 5,488,650,
  15. // 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054.
  16. //
  17. // Active Voice Corporation
  18. // Seattle, Washington
  19. // USA
  20. //
  21. /////////////////////////////////////////////////////////////////////////////////////////
  22. ////
  23. // date.c - date functions
  24. ////
  25. #include "winlocal.h"
  26. #include <time.h>
  27. #include "date.h"
  28. #include "str.h"
  29. #include "mem.h"
  30. ////
  31. // private definitions
  32. ////
  33. // Date_t is stored as (year - BASEYEAR) * YEARFACTOR + month * MONTHFACTOR + day
  34. // i.e. July 25th, 1959 is stored as 590725
  35. //
  36. #define BASEYEAR 1900
  37. #define YEARFACTOR 10000L
  38. #define MONTHFACTOR 100
  39. static short aDays[] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  40. static TCHAR *aMonths[] = { TEXT(""),
  41. TEXT("JAN"), TEXT("FEB"), TEXT("MAR"),
  42. TEXT("APR"), TEXT("MAY"), TEXT("JUN"),
  43. TEXT("JUL"), TEXT("AUG"), TEXT("SEP"),
  44. TEXT("OCT"), TEXT("NOV"), TEXT("DEC") };
  45. // helper functions
  46. //
  47. static Month_t MonthValue(LPCTSTR lpszMonth);
  48. ////
  49. // public functions
  50. ////
  51. // Date - return date value representing year <y>, month <m>, and day <d>
  52. // <y> (i) year
  53. // <m> (i) month
  54. // <d> (i) day
  55. // return date value (0 if error)
  56. // NOTE: if year is between 0 and 27, 2000 is added to it
  57. // NOTE: if year is between 28 and 127, 1900 is added to it
  58. //
  59. Date_t DLLEXPORT WINAPI Date(Year_t y, Month_t m, Day_t d)
  60. {
  61. Date_t date;
  62. if (y < 28)
  63. y += 2000;
  64. else if (y < 128)
  65. y += 1900;
  66. date = (y - BASEYEAR) * YEARFACTOR + m * MONTHFACTOR + d;
  67. if (!DateIsValid(date))
  68. return (Date_t) 0;
  69. return date;
  70. }
  71. // DateToday - return date value representing current year, month, and day
  72. // return date value (0 if error)
  73. //
  74. Date_t DLLEXPORT WINAPI DateToday(void)
  75. {
  76. static time_t timeCurr;
  77. static struct tm *tmCurr;
  78. timeCurr = time(NULL);
  79. tmCurr = localtime(&timeCurr);
  80. return Date((Year_t) (tmCurr->tm_year + 1900),
  81. (Month_t) (tmCurr->tm_mon + 1), (Day_t) tmCurr->tm_mday);
  82. }
  83. // DateValue - return date value representing given date string
  84. // <lpszDate> (i) date string to convert
  85. // "JUL 25 1959"
  86. // "25 JUL 1959"
  87. // "7-25-1959"
  88. // etc.
  89. // return date value (0 if error)
  90. // NOTE: this function assumes English language month names only
  91. // NOTE: if no year specified, current year is assumed
  92. //
  93. Date_t DLLEXPORT WINAPI DateValue(LPCTSTR lpszDate)
  94. {
  95. Year_t y = 0;
  96. Month_t m = 0;
  97. Day_t d = 0;
  98. LPTSTR lpszDelimiters = TEXT(" \t/-.,;:");
  99. TCHAR szDateTmp[32];
  100. LPTSTR lpszToken1;
  101. LPTSTR lpszToken2;
  102. LPTSTR lpszToken3;
  103. *szDateTmp = '\0';
  104. if (lpszDate != NULL)
  105. StrNCpy(szDateTmp, lpszDate, SIZEOFARRAY(szDateTmp));
  106. lpszToken1 = StrTok(szDateTmp, lpszDelimiters);
  107. lpszToken2 = StrTok(NULL, lpszDelimiters);
  108. lpszToken3 = StrTok(NULL, lpszDelimiters);
  109. if (lpszToken1 != NULL && ChrIsAlpha(*lpszToken1))
  110. {
  111. // assume JAN 31 1991 format
  112. //
  113. m = MonthValue(lpszToken1);
  114. d = (lpszToken2 == NULL ? 0 : StrAtoI(lpszToken2));
  115. }
  116. else if (lpszToken2 != NULL && ChrIsAlpha(*lpszToken2))
  117. {
  118. // assume 31 JAN 1991 format
  119. //
  120. m = MonthValue(lpszToken2);
  121. d = (lpszToken1 == NULL ? 0 : StrAtoI(lpszToken1));
  122. }
  123. else
  124. {
  125. // assume 1-31-1991 format
  126. //
  127. m = (lpszToken1 == NULL ? 0 : StrAtoI(lpszToken1));
  128. d = (lpszToken2 == NULL ? 0 : StrAtoI(lpszToken2));
  129. }
  130. y = (lpszToken3 == NULL ? 0 : StrAtoI(lpszToken3));
  131. if (y == 0)
  132. y = DateYear(DateToday());
  133. return Date(y, m, d);
  134. }
  135. // DateYear - return year of a given date (1900-2027)
  136. // <d> (i) date value
  137. // return year
  138. //
  139. Year_t DLLEXPORT WINAPI DateYear(Date_t d)
  140. {
  141. return (Year_t) (d / YEARFACTOR) + BASEYEAR;
  142. }
  143. // DateMonth - return month of a given date (1-12)
  144. // <d> (i) date value
  145. // return month
  146. //
  147. Month_t DLLEXPORT WINAPI DateMonth(Date_t d)
  148. {
  149. return (Month_t) ((d % YEARFACTOR) / MONTHFACTOR);
  150. }
  151. // DateDay - return day of the month for a given date (1-31)
  152. // <d> (i) date value
  153. // return day
  154. //
  155. Day_t DLLEXPORT WINAPI DateDay(Date_t d)
  156. {
  157. return (Day_t) ((d % YEARFACTOR) % MONTHFACTOR);
  158. }
  159. // DateWeekDay - return day of the week for a given date
  160. // <date> (i) date value
  161. // <dwFlags> (i) control flags
  162. // 0 default algorithm
  163. // DATEWEEKDAY_MKTIME mktime algorithm (1/1/1970 - 1/18/2038)
  164. // DATEWEEKDAY_QUICK quick algorithm (3/2/1924 - 2/28/2100)
  165. // DATEWEEKDAY_ZELLER zeller congruence algorithm (1582 - )
  166. // DATEWEEKDAY_SAKAMOTO Tomohiko Sakamoto algorithm (1752 - )
  167. // return day of week (0 if error, 1 if SUN, 2 if MON, etc)
  168. //
  169. Weekday_t DLLEXPORT WINAPI DateWeekDay(Date_t date, DWORD dwFlags)
  170. {
  171. Year_t y;
  172. Month_t m;
  173. Day_t d;
  174. if (!DateIsValid(date))
  175. return (Weekday_t) 0;
  176. y = DateYear(date);
  177. m = DateMonth(date);
  178. d = DateDay(date);
  179. if (dwFlags == 0)
  180. dwFlags |= DATEWEEKDAY_ZELLER;
  181. if (dwFlags & DATEWEEKDAY_MKTIME)
  182. {
  183. #ifndef _WIN32
  184. static
  185. #endif
  186. struct tm tmRef;
  187. MemSet(&tmRef, 0, sizeof(tmRef));
  188. tmRef.tm_year = y - 1900;
  189. tmRef.tm_mon = m - 1;
  190. tmRef.tm_mday = d;
  191. if (mktime(&tmRef) == -1)
  192. return (Weekday_t) 0;
  193. else
  194. return (Weekday_t) (tmRef.tm_wday + 1);
  195. }
  196. if (dwFlags & DATEWEEKDAY_QUICK)
  197. {
  198. // NOTE: quick algorithm valid only for 3/2/1924 - 2/28/2100
  199. y -= 1900;
  200. if (m > 2)
  201. m -= 2;
  202. else
  203. {
  204. m += 10;
  205. --y;
  206. }
  207. return (Weekday_t) ((((m * 13 - 1) / 5) + d + y + (y / 4) - 34) % 7) + 1;
  208. }
  209. if (dwFlags & DATEWEEKDAY_ZELLER)
  210. {
  211. short ccyy = y;
  212. short mm = m;
  213. short dd = d;
  214. short n1;
  215. long n2;
  216. short r;
  217. short wccyy;
  218. short wm;
  219. short wccyyd400;
  220. short wccyyd100;
  221. short zday_num;
  222. wccyy = ccyy;
  223. wm = mm;
  224. if (wm < 3)
  225. {
  226. wm = wm + 12;
  227. wccyy = ccyy - 1;
  228. }
  229. n1 = (wm + 1) * 26 / 10;
  230. n2 = wccyy * 125 / 100;
  231. wccyyd400 = wccyy / 400;
  232. wccyyd100 = wccyy / 100;
  233. zday_num = wccyyd400 - wccyyd100 + dd + n1 + (short) n2;
  234. r = zday_num / 7;
  235. /* 0=sat 1=sun 2=mon 3=tue 4=wed 5=thu 6=fri */
  236. zday_num = zday_num - r * 7;
  237. /* 7=sat */
  238. if (zday_num == 0)
  239. zday_num = 7;
  240. return(zday_num);
  241. }
  242. if (dwFlags & DATEWEEKDAY_SAKAMOTO)
  243. {
  244. // Tomohiko Sakamoto
  245. //
  246. static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
  247. y -= m < 3;
  248. return ((y + y/4 - y/100 + y/400 + t[m-1] + d) % 7) + 1;
  249. }
  250. return 0;
  251. }
  252. // DateIsValid - test <date> for validity
  253. // <date> (i) date value
  254. // return TRUE if valid
  255. //
  256. BOOL DLLEXPORT WINAPI DateIsValid(Date_t date)
  257. {
  258. BOOL fValid = TRUE;
  259. Year_t y = DateYear(date);
  260. Month_t m = DateMonth(date);
  261. Day_t d = DateDay(date);
  262. // check for invalid year, month, or day
  263. //
  264. if (y < 0 || y > 9999 || m < 1 || m > 12 || d < 1 || d > aDays[m])
  265. fValid = FALSE;
  266. // February 29th only on leap years
  267. //
  268. if (m == 2 && d == 29 && !DateIsLeapYear(y))
  269. fValid = FALSE;
  270. return fValid;
  271. }
  272. // DateIsLeapYear - return TRUE if <y> represents a leap year
  273. // <y> (i) year value
  274. // return TRUE if leap year
  275. //
  276. BOOL DLLEXPORT WINAPI DateIsLeapYear(Year_t y)
  277. {
  278. return (BOOL) (y % 4 == 0 && y % 100 != 0 || y % 400 == 0);
  279. }
  280. // DateNew - return date value which is <n> days from date <date>
  281. // <date> (i) date value
  282. // <n> (i) delta
  283. // +1 one day later
  284. // -1 one day earlier, etc.
  285. // return date value (0 if error)
  286. //
  287. Date_t DLLEXPORT WINAPI DateNew(Date_t date, short n)
  288. {
  289. Year_t y;
  290. Month_t m;
  291. Day_t d;
  292. if (!DateIsValid(date))
  293. return (Date_t) 0;
  294. y = DateYear(date);
  295. m = DateMonth(date);
  296. d = DateDay(date);
  297. if (n > 0)
  298. {
  299. // increment date n times
  300. //
  301. for ( ; n != 0; n--)
  302. {
  303. if ((++d > aDays[m]) || (m == 2 && d == 29 && !DateIsLeapYear(y)))
  304. {
  305. d = 1;
  306. if (++m == 13)
  307. {
  308. m = 1;
  309. y++;
  310. }
  311. }
  312. }
  313. }
  314. else
  315. {
  316. // decrement date n times
  317. //
  318. for ( ; n != 0; n++)
  319. {
  320. if (--d == 0)
  321. {
  322. if (--m == 2 && !DateIsLeapYear(y))
  323. d = 28;
  324. else
  325. {
  326. if (m == 0)
  327. {
  328. m = 12;
  329. --y;
  330. }
  331. d = aDays[m];
  332. }
  333. }
  334. }
  335. }
  336. return Date(y, m, d);
  337. }
  338. // DateCmp - return number of days between date1 and date2 (date1 minus date2)
  339. // <date1> (i) date value
  340. // <date2> (i) date value
  341. // return days between dates
  342. //
  343. long DLLEXPORT WINAPI DateCmp(Date_t date1, Date_t date2)
  344. {
  345. Year_t y1 = DateYear(date1);
  346. Month_t m1 = DateMonth(date1);
  347. Day_t d1 = DateDay(date1);
  348. Year_t y2 = DateYear(date2);
  349. Month_t m2 = DateMonth(date2);
  350. Day_t d2 = DateDay(date2);
  351. if (m1 <= 2)
  352. {
  353. --y1;
  354. m1 += 13;
  355. }
  356. else
  357. ++m1;
  358. if (m2 <= 2)
  359. {
  360. --y2;
  361. m2 += 13;
  362. }
  363. else
  364. ++m2;
  365. return ((long) ((1461L * y1) / 4 + (153 * m1) / 5 + d1) -
  366. ((1461L * y2) / 4 + (153 * m2) / 5 + d2));
  367. }
  368. // DateStartWeek - return date representing first day of the week relative to date <d>
  369. // <d> (i) date value
  370. // return date value (0 if error)
  371. //
  372. Date_t DLLEXPORT WINAPI DateStartWeek(Date_t d)
  373. {
  374. return DateNew(d, (short) (- DateWeekDay(d, 0) + 1));
  375. }
  376. // DateEndWeek - return date representing last day of the week relative to date <d>
  377. // <d> (i) date value
  378. // return date value (0 if error)
  379. //
  380. Date_t DLLEXPORT WINAPI DateEndWeek(Date_t d)
  381. {
  382. return DateNew(d, (short) (- DateWeekDay(d, 0) + 7));
  383. }
  384. // DateStartMonth - return date representing first day of the month relative to date <d>
  385. // <d> (i) date value
  386. // return date value (0 if error)
  387. //
  388. Date_t DLLEXPORT WINAPI DateStartMonth(Date_t d)
  389. {
  390. return Date(DateYear(d), DateMonth(d), 1);
  391. }
  392. // DateEndMonth - return date representing last day of the month relative to date <d>
  393. // <d> (i) date value
  394. // return date value (0 if error)
  395. //
  396. Date_t DLLEXPORT WINAPI DateEndMonth(Date_t d)
  397. {
  398. Year_t year = DateYear(d);
  399. Month_t month = DateMonth(d);
  400. Day_t day = aDays[DateMonth(d)];
  401. if (month == 2 && !DateIsLeapYear(year))
  402. --day;
  403. return Date(year, month, day);
  404. }
  405. // DateStartQuarter - return date representing first day of the quarter relative to date <d>
  406. // <d> (i) date value
  407. // return date value (0 if error)
  408. //
  409. Date_t DLLEXPORT WINAPI DateStartQuarter(Date_t d)
  410. {
  411. return Date(DateYear(d), (Month_t) (3 * ((DateMonth(d) - 1) / 3) + 1), 1);
  412. }
  413. // DateEndQuarter - return date representing last day of the quarter relative to date <d>
  414. // <d> (i) date value
  415. // return date value (0 if error)
  416. //
  417. Date_t DLLEXPORT WINAPI DateEndQuarter(Date_t d)
  418. {
  419. return DateEndMonth(Date(DateYear(d), (Month_t) (3 * ((DateMonth(d) - 1) / 3) + 3), 1));
  420. }
  421. // DateStartYear - return date representing first day of the year relative to date <d>
  422. // <d> (i) date value
  423. // return date value (0 if error)
  424. //
  425. Date_t DLLEXPORT WINAPI DateStartYear(Date_t d)
  426. {
  427. return Date(DateYear(d), 1, 1);
  428. }
  429. // DateEndYear - return date representing last day of the year relative to date <d>
  430. // <d> (i) date value
  431. // return date value (0 if error)
  432. //
  433. Date_t DLLEXPORT WINAPI DateEndYear(Date_t d)
  434. {
  435. return Date(DateYear(d), 12, 31);
  436. }
  437. // DateStartLastWeek - return date representing first day of previous week
  438. // return date value (0 if error)
  439. //
  440. Date_t DLLEXPORT WINAPI DateStartLastWeek(void)
  441. {
  442. return DateStartWeek(DateEndLastWeek());
  443. }
  444. // DateEndLastWeek - return date representing last day of previous week
  445. // return date value (0 if error)
  446. //
  447. Date_t DLLEXPORT WINAPI DateEndLastWeek(void)
  448. {
  449. return DateNew(DateStartWeek(DateToday()), -1);
  450. }
  451. // DateStartLastMonth - return date representing first day of previous month
  452. // return date value (0 if error)
  453. //
  454. Date_t DLLEXPORT WINAPI DateStartLastMonth(void)
  455. {
  456. return DateStartMonth(DateEndLastMonth());
  457. }
  458. // DateEndLastMonth - return date representing last day of previous month
  459. // return date value (0 if error)
  460. //
  461. Date_t DLLEXPORT WINAPI DateEndLastMonth(void)
  462. {
  463. return DateNew(DateStartMonth(DateToday()), -1);
  464. }
  465. // DateStartLastQuarter - return date representing first day of previous quarter
  466. // return date value (0 if error)
  467. //
  468. Date_t DLLEXPORT WINAPI DateStartLastQuarter(void)
  469. {
  470. return DateStartQuarter(DateEndLastQuarter());
  471. }
  472. // DateEndLastQuarter - return date representing last day of previous quarter
  473. // return date value (0 if error)
  474. //
  475. Date_t DLLEXPORT WINAPI DateEndLastQuarter(void)
  476. {
  477. return DateNew(DateStartQuarter(DateToday()), -1);
  478. }
  479. // DateStartLastYear - return date representing first day of previous year
  480. // return date value (0 if error)
  481. //
  482. Date_t DLLEXPORT WINAPI DateStartLastYear(void)
  483. {
  484. return DateStartYear(DateEndLastYear());
  485. }
  486. // DateEndLastYear - return date representing last day of previous year
  487. // return date value (0 if error)
  488. //
  489. Date_t DLLEXPORT WINAPI DateEndLastYear(void)
  490. {
  491. return DateNew(DateStartYear(DateToday()), -1);
  492. }
  493. // DateThisMonth - return date representing specified day of current month
  494. // <day> (i) day value
  495. // return date value (0 if error)
  496. //
  497. Date_t DLLEXPORT WINAPI DateThisMonth(Day_t day)
  498. {
  499. return Date(DateYear(DateToday()), DateMonth(DateToday()), day);
  500. }
  501. // DateLastMonth - return date representing specified day of previous month
  502. // <day> (i) day value
  503. // return date value (0 if error)
  504. //
  505. Date_t DLLEXPORT WINAPI DateLastMonth(Day_t day)
  506. {
  507. return Date(DateYear(DateStartLastMonth()), DateMonth(DateStartLastMonth()), day);
  508. }
  509. ////
  510. // private functions
  511. ////
  512. // GetMonth - return month number equivalent to month name ("JAN" = 1, "FEB" = 2,...)
  513. // <lpszMonth> (i) string representing month
  514. // "JAN"
  515. // "Jan"
  516. // "JANUARY"
  517. // etc.
  518. // return month value (0 if error)
  519. //
  520. static Month_t MonthValue(LPCTSTR lpszMonth)
  521. {
  522. short i;
  523. Month_t month = 0;
  524. for (i = 1; i < SIZEOFARRAY(aMonths); ++i)
  525. {
  526. if (MemICmp(lpszMonth, aMonths[i], StrLen(aMonths[i])) == 0)
  527. {
  528. month = i;
  529. break;
  530. }
  531. }
  532. return month;
  533. }