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.

426 lines
12 KiB

  1. #include "ctlspriv.h"
  2. #include "scdttime.h"
  3. int mpcdymoAccum[13] =
  4. { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
  5. /*
  6. - LIncrWord
  7. -
  8. * Purpose:
  9. * Increment (or decrement) an integer by a specified amount,
  10. * given the constraints nMic and nMac.
  11. * Returns the amount of carry into the following (or preceding)
  12. * field, or zero if none.
  13. *
  14. * Intended for use with incrementing date/times.
  15. *
  16. * Arguments:
  17. * pn Pointer to integer to be modified.
  18. * nDelta Amount by which to modify *pn; may be positive,
  19. * negative or zero.
  20. * nMic Minimum value for *pn; if decrementing below this,
  21. * a carry is performed.
  22. * nMac Maximum value for *pn; if incrementing above this,
  23. * a carry is performed.
  24. *
  25. * Returns:
  26. * Zero if modification done within constraints, otherwise the
  27. * amount of carry (positive in incrementing, negative if
  28. * decrementing).
  29. *
  30. */
  31. LONG LIncrWord(WORD *pn, LONG nDelta, int nMic, int nMac)
  32. {
  33. LONG lNew, lIncr;
  34. lIncr = 0;
  35. lNew = *pn + nDelta;
  36. while (lNew >= nMac)
  37. {
  38. lNew -= nMac - nMic;
  39. lIncr++;
  40. }
  41. if (!lIncr)
  42. {
  43. while (lNew < nMic)
  44. {
  45. lNew += nMac - nMic;
  46. lIncr--;
  47. }
  48. }
  49. *pn = (WORD)lNew;
  50. return(lIncr);
  51. }
  52. void IncrSystemTime(SYSTEMTIME *pstSrc, SYSTEMTIME *pstDest, LONG nDelta, LONG flag)
  53. {
  54. int cdyMon;
  55. if (pstSrc != pstDest)
  56. *pstDest = *pstSrc;
  57. switch (flag)
  58. {
  59. case INCRSYS_SECOND:
  60. if (!(nDelta = LIncrWord(&pstDest->wSecond, nDelta, 0, 60)))
  61. break;
  62. case INCRSYS_MINUTE:
  63. if (!(nDelta = LIncrWord(&pstDest->wMinute, nDelta, 0, 60)))
  64. break;
  65. case INCRSYS_HOUR:
  66. if (!(nDelta = LIncrWord(&pstDest->wHour, nDelta, 0, 24)))
  67. break;
  68. case INCRSYS_DAY:
  69. IDTday:
  70. if (nDelta >= 0)
  71. {
  72. cdyMon = GetDaysForMonth(pstDest->wYear, pstDest->wMonth);
  73. while (pstDest->wDay + nDelta > cdyMon)
  74. {
  75. nDelta -= cdyMon + 1 - pstDest->wDay;
  76. pstDest->wDay = 1;
  77. IncrSystemTime(pstDest, pstDest, 1, INCRSYS_MONTH);
  78. cdyMon = GetDaysForMonth(pstDest->wYear, pstDest->wMonth);
  79. }
  80. }
  81. else
  82. {
  83. while (pstDest->wDay <= -nDelta)
  84. {
  85. nDelta += pstDest->wDay;
  86. IncrSystemTime(pstDest, pstDest, -1, INCRSYS_MONTH);
  87. cdyMon = GetDaysForMonth(pstDest->wYear, pstDest->wMonth);
  88. pstDest->wDay = (WORD) cdyMon;
  89. }
  90. }
  91. pstDest->wDay += (WORD)nDelta;
  92. break;
  93. case INCRSYS_MONTH:
  94. if (!(nDelta = LIncrWord(&pstDest->wMonth, nDelta, 1, 13)))
  95. {
  96. cdyMon = GetDaysForMonth(pstDest->wYear, pstDest->wMonth);
  97. if (pstDest->wDay > cdyMon)
  98. pstDest->wDay = (WORD) cdyMon;
  99. break;
  100. }
  101. case INCRSYS_YEAR:
  102. pstDest->wYear += (WORD)nDelta;
  103. cdyMon = GetDaysForMonth(pstDest->wYear, pstDest->wMonth);
  104. if (pstDest->wDay > cdyMon)
  105. pstDest->wDay = (WORD) cdyMon;
  106. break;
  107. case INCRSYS_WEEK:
  108. nDelta *= 7;
  109. goto IDTday;
  110. break;
  111. }
  112. }
  113. CmpDate(const SYSTEMTIME *pst1, const SYSTEMTIME *pst2)
  114. {
  115. int iRet;
  116. if (pst1->wYear < pst2->wYear)
  117. iRet = -1;
  118. else if (pst1->wYear > pst2->wYear)
  119. iRet = 1;
  120. else if (pst1->wMonth < pst2->wMonth)
  121. iRet = -1;
  122. else if (pst1->wMonth > pst2->wMonth)
  123. iRet = 1;
  124. else if (pst1->wDay < pst2->wDay)
  125. iRet = -1;
  126. else if (pst1->wDay > pst2->wDay)
  127. iRet = 1;
  128. else
  129. iRet = 0;
  130. return(iRet);
  131. }
  132. CmpSystemtime(const SYSTEMTIME *pst1, const SYSTEMTIME *pst2)
  133. {
  134. int iRet;
  135. if (pst1->wYear < pst2->wYear)
  136. iRet = -1;
  137. else if (pst1->wYear > pst2->wYear)
  138. iRet = 1;
  139. else if (pst1->wMonth < pst2->wMonth)
  140. iRet = -1;
  141. else if (pst1->wMonth > pst2->wMonth)
  142. iRet = 1;
  143. else if (pst1->wDay < pst2->wDay)
  144. iRet = -1;
  145. else if (pst1->wDay > pst2->wDay)
  146. iRet = 1;
  147. else if (pst1->wHour < pst2->wHour)
  148. iRet = -1;
  149. else if (pst1->wHour > pst2->wHour)
  150. iRet = 1;
  151. else if (pst1->wMinute < pst2->wMinute)
  152. iRet = -1;
  153. else if (pst1->wMinute > pst2->wMinute)
  154. iRet = 1;
  155. else if (pst1->wSecond < pst2->wSecond)
  156. iRet = -1;
  157. else if (pst1->wSecond > pst2->wSecond)
  158. iRet = 1;
  159. else
  160. iRet = 0;
  161. return(iRet);
  162. }
  163. /*
  164. - CdyBetweenYmd
  165. -
  166. * Purpose:
  167. * Calculate the number of days between two dates as expressed
  168. * in YMD's.
  169. *
  170. * Parameters:
  171. * pymdStart start day of range.
  172. * pymdEnd end day of range.
  173. *
  174. * Returns:
  175. * Number of days between two dates. The number
  176. * of days does not include the starting day, but does include
  177. * the last day. ie 1/24/1990-1/25/1990 = 1 day.
  178. */
  179. DWORD DaysBetweenDates(const SYSTEMTIME *pstStart, const SYSTEMTIME *pstEnd)
  180. {
  181. DWORD cday;
  182. WORD yr;
  183. // Calculate number of days between the start month/day and the
  184. // end month/day as if they were in the same year - since cday
  185. // is unsigned, cday could be really large if the end month/day
  186. // is before the start month.day.
  187. // This will be cleared up when we account for the days between
  188. // the years.
  189. ASSERT(pstEnd->wMonth >= 1 && pstEnd->wMonth <= 12);
  190. cday = mpcdymoAccum[pstEnd->wMonth - 1] - mpcdymoAccum[pstStart->wMonth - 1] +
  191. pstEnd->wDay - pstStart->wDay;
  192. yr = pstStart->wYear;
  193. // Check to see if the start year is before the end year,
  194. // and if the end month is after February and
  195. // if the end year is a leap year, then add an extra day
  196. // for to account for Feb. 29 in the end year.
  197. if ( ((yr < pstEnd->wYear) || (pstStart->wMonth <= 2)) &&
  198. pstEnd->wMonth > 2 &&
  199. (pstEnd->wYear & 03) == 0 &&
  200. (pstEnd->wYear <= 1750 || pstEnd->wYear % 100 != 0 || pstEnd->wYear % 400 == 0))
  201. {
  202. cday++;
  203. }
  204. // Now account for the leap years in between the start and end dates
  205. // as well as accounting for the days in each year.
  206. if (yr < pstEnd->wYear)
  207. {
  208. // If the start date is before march and the start year is
  209. // a leap year then add an extra day to account for Feb. 29.
  210. if ( pstStart->wMonth <= 2 &&
  211. (yr & 03) == 0 &&
  212. (yr <= 1750 || yr % 100 != 0 || yr % 400 == 0))
  213. {
  214. cday++;
  215. }
  216. // Account for the days in each year (disregarding leap years).
  217. cday += 365;
  218. yr++;
  219. // Keep on accounting for the days in each year including leap
  220. // years until we reach the end year.
  221. while (yr < pstEnd->wYear)
  222. {
  223. cday += 365;
  224. if ((yr & 03) == 0 && (yr <= 1750 || yr % 100 != 0 || yr % 400 == 0))
  225. cday++;
  226. yr++;
  227. }
  228. }
  229. return(cday);
  230. }
  231. /*
  232. - DowStartOfYrMo
  233. -
  234. * Purpose:
  235. * Find the day of the week the indicated month begins on
  236. *
  237. * Parameters:
  238. * yr year, must be > 0
  239. * mo month, number 1-12
  240. *
  241. * Returns:
  242. * day of the week (0-6) on which the month begins
  243. * (0 = Sunday, 1 = Monday etc.)
  244. */
  245. int GetStartDowForMonth(int yr, int mo)
  246. {
  247. int dow;
  248. // we want monday = 0, sunday = 6
  249. // dow = 6 + (yr - 1) + ((yr - 1) >> 2);
  250. dow = 5 + (yr - 1) + ((yr - 1) >> 2);
  251. if (yr > 1752)
  252. dow += ((yr - 1) - 1600) / 400 - ((yr - 1) - 1700) / 100 - 11;
  253. else if (yr == 1752 && mo > 9)
  254. dow -= 11;
  255. dow += mpcdymoAccum[mo - 1];
  256. if (mo > 2 && (yr & 03) == 0 && (yr <= 1750 || yr % 100 != 0 || yr % 400 == 0))
  257. dow++;
  258. dow %= 7;
  259. return(dow);
  260. }
  261. int DowFromDate(const SYSTEMTIME *pst)
  262. {
  263. int dow;
  264. dow = GetStartDowForMonth(pst->wYear, pst->wMonth);
  265. dow = (dow + pst->wDay - 1) % 7;
  266. return(dow);
  267. }
  268. int GetDaysForMonth(int yr, int mo)
  269. {
  270. int cdy;
  271. if (yr == 1752 && mo == 9)
  272. return(19);
  273. cdy = mpcdymoAccum[mo] - mpcdymoAccum[mo - 1];
  274. if (mo == 2 && (yr & 03) == 0 && (yr <= 1750 || yr % 100 != 0 || yr % 400 == 0))
  275. cdy++;
  276. return(cdy);
  277. }
  278. /*
  279. - NweekNumber
  280. -
  281. * Purpose:
  282. * Calculates week number in which a given date occurs, based
  283. * on a specified start-day of week.
  284. * Adjusts based on how a calendar would show this week
  285. * (ie. week 53 is probably week 1 on the calendar).
  286. *
  287. * Arguments:
  288. * pdtm Pointer to date in question
  289. * dowStartWeek Day-of-week on which weeks starts (0 - 6).
  290. *
  291. * Returns:
  292. * Week number of the year, in which *pdtr occurs.
  293. *
  294. */
  295. // TODO: this currently ignores woyFirst
  296. // it uses the 1st week containing 4+ days as the first week (woyFirst = 2)
  297. // need to make appropriate changes so it handles woyFirst = 0 and = 1...
  298. int GetWeekNumber(const SYSTEMTIME *pst, int dowFirst, int woyFirst)
  299. {
  300. int day, ddow, ddowT, nweek;
  301. SYSTEMTIME st;
  302. st.wYear = pst->wYear;
  303. st.wMonth = 1;
  304. st.wDay = 1;
  305. ddow = GetStartDowForMonth(st.wYear, st.wMonth) - dowFirst;
  306. if (ddow < 0)
  307. ddow += 7;
  308. if (pst->wMonth == 1 && pst->wDay < 8 - ddow)
  309. {
  310. nweek = 0;
  311. }
  312. else
  313. {
  314. if (ddow)
  315. st.wDay = 8 - ddow;
  316. nweek = (DaysBetweenDates(&st, pst) / 7) + 1;
  317. }
  318. if (ddow && ddow <= 3)
  319. nweek++;
  320. // adjust if necessary for calendar
  321. if (!nweek)
  322. {
  323. if (!ddow)
  324. return(1);
  325. // check what week Dec 31 is on
  326. st.wYear--;
  327. st.wMonth = 12;
  328. st.wDay = 31;
  329. return(GetWeekNumber(&st, dowFirst, woyFirst));
  330. }
  331. else if (nweek >= 52)
  332. {
  333. ddowT = (GetStartDowForMonth(pst->wYear, pst->wMonth) +
  334. pst->wDay - 1 + 7 - dowFirst) % 7;
  335. day = pst->wDay + (7 - ddowT);
  336. if (day > 31 + 4)
  337. nweek = 1;
  338. }
  339. return(nweek);
  340. }
  341. // ignores day of week and time-related fields...
  342. BOOL IsValidDate(const SYSTEMTIME *pst)
  343. {
  344. int cDay;
  345. if (pst && pst->wMonth >= 1 && pst->wMonth <= 12)
  346. {
  347. cDay = GetDaysForMonth(pst->wYear, pst->wMonth);
  348. if (pst->wDay >= 1 && pst->wDay <= cDay)
  349. return(TRUE);
  350. }
  351. return(FALSE);
  352. }
  353. // ignores milliseconds and date-related fields...
  354. BOOL IsValidTime(const SYSTEMTIME *pst)
  355. {
  356. return(pst->wHour <= 23 &&
  357. pst->wMinute <= 59 &&
  358. pst->wSecond <= 59);
  359. }
  360. // ignores day of week
  361. BOOL IsValidSystemtime(const SYSTEMTIME *pst)
  362. {
  363. if (pst && pst->wMonth >= 1 && pst->wMonth <= 12)
  364. {
  365. int cDay = GetDaysForMonth(pst->wYear, pst->wMonth);
  366. if (pst->wDay >= 1 &&
  367. pst->wDay <= cDay &&
  368. pst->wHour <= 23 &&
  369. pst->wMinute <= 59 &&
  370. pst->wSecond <= 59 &&
  371. pst->wMilliseconds < 1000)
  372. return(TRUE);
  373. }
  374. return(FALSE);
  375. }