DATEFUNC.MOD 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. IMPLEMENTATION MODULE DateFunctions;
  2. (*
  3. * REPERTOIRE
  4. * Release 1.6
  5. * By Charles Bradford and Cole Brecheen
  6. * (c) Copyright 1985-1992 PMI
  7. * Green Bay, WI
  8. * All rights reserved
  9. * (414) 468=6040
  10. *
  11. * $Header: D:/logfiles/mods/datefunc.mov 1.4 17 Mar 1991 17:53:06 coleb $
  12. *
  13. *)
  14. (*EntryDiag:
  15. IMPORT Diagnostics;
  16. :EntryDiag*)
  17. IMPORT M2Strings;
  18. IMPORT PosUtils;
  19. IMPORT StrConv;
  20. IMPORT StrEdit;
  21. VAR
  22. Initialized : BOOLEAN;
  23. TYPE
  24. RepType = (DB, US, UK, USMilitary, Correspondence);
  25. VAR
  26. monthtotal: ARRAY [1..12] OF CARDINAL;
  27. monthtotalleap : ARRAY[1..12] OF CARDINAL;
  28. monthsize: ARRAY [1..12] OF CARDINAL;
  29. PROCEDURE InitMonthTotal;
  30. BEGIN
  31. monthtotal[1] := 0; monthtotalleap[1] := 0;
  32. monthtotal[2] := 31; monthtotalleap[2] := 31;
  33. monthtotal[3] := 59; monthtotalleap[3] := 60;
  34. monthtotal[4] := 90; monthtotalleap[4] := 91;
  35. monthtotal[5] := 120; monthtotalleap[5] := 121;
  36. monthtotal[6] := 151; monthtotalleap[6] := 152;
  37. monthtotal[7] := 181; monthtotalleap[7] := 182;
  38. monthtotal[8] := 212; monthtotalleap[8] := 213;
  39. monthtotal[9] := 243; monthtotalleap[9] := 244;
  40. monthtotal[10] := 273; monthtotalleap[10] := 274;
  41. monthtotal[11] := 304; monthtotalleap[11] := 305;
  42. monthtotal[12] := 334; monthtotalleap[12] := 335;
  43. END InitMonthTotal;
  44. (*
  45. PROCEDURE DateToStr2(d: Date; VAR s: ARRAY OF CHAR;
  46. representation: RepType);
  47. VAR daystr, mostr: ARRAY [0..1] OF CHAR;
  48. yrstr: ARRAY [0..3] OF CHAR;
  49. BEGIN
  50. END DateToStr2;
  51. *)
  52. PROCEDURE DateToStr(d: Date; VAR s: ARRAY OF CHAR; VAR OK: BOOLEAN);
  53. VAR i: CARDINAL;
  54. PROCEDURE PutDigits(n: CARDINAL);
  55. BEGIN
  56. IF n < 10 THEN
  57. s[i] := '0';
  58. INC(i);
  59. s[i] := CHR(n + 48);
  60. INC(i);
  61. ELSE
  62. n := n MOD 100;
  63. s[i] := CHR((n DIV 10) + 48);
  64. INC(i);
  65. s[i] := CHR((n MOD 10) + 48);
  66. INC(i);
  67. END;
  68. END PutDigits;
  69. BEGIN
  70. IF (HIGH(s) < 7) OR (NOT ValidDate(d))THEN
  71. OK := FALSE;
  72. FOR i := 0 TO HIGH(s) DO
  73. s[i] := '*';
  74. END;
  75. ELSE
  76. OK := TRUE;
  77. i := 0;
  78. PutDigits(d.mo);
  79. s[i] := '-';
  80. INC(i);
  81. PutDigits(d.day);
  82. s[i] := '-';
  83. INC(i);
  84. PutDigits(d.yr-1900);
  85. IF HIGH(s) > 8 THEN
  86. s[i] := 0C;
  87. END;
  88. END;
  89. END DateToStr;
  90. PROCEDURE Digit(c : CHAR) : BOOLEAN;
  91. BEGIN
  92. RETURN (c>='0') AND (c<='9');
  93. END Digit;
  94. PROCEDURE StrToDate(s: ARRAY OF CHAR; VAR d: Date; VAR OK: BOOLEAN);
  95. (* expects mm dd yy *)
  96. VAR i, yeardigits: CARDINAL;
  97. BEGIN
  98. i := 0;
  99. WHILE (i <= HIGH(s)) AND (NOT Digit(s[i])) DO
  100. INC(i)
  101. END;
  102. d.mo := 0; d.yr := 0; d.day := 0;
  103. WHILE (i <= HIGH(s)) AND (Digit(s[i])) DO
  104. d.mo := d.mo * 10 + (ORD(s[i])-48);
  105. INC(i);
  106. END;
  107. INC(i);
  108. WHILE (i <= HIGH(s)) AND (Digit(s[i])) DO
  109. d.day := d.day * 10 + (ORD(s[i])-48);
  110. INC(i);
  111. END;
  112. INC(i);
  113. yeardigits := 0;
  114. WHILE (i <= HIGH(s)) AND (Digit(s[i])) DO
  115. d.yr := d.yr * 10 + (ORD(s[i])-48);
  116. INC(i);
  117. INC(yeardigits);
  118. END;
  119. IF yeardigits <= 2 THEN
  120. IF d.yr<40
  121. THEN
  122. INC(d.yr,2000);
  123. ELSE
  124. INC(d.yr, 1900);
  125. END;
  126. END;
  127. IF NOT ValidDate(d) THEN
  128. d.yr := 0; d.mo := 0; d.day := 0;
  129. OK := FALSE
  130. ELSE
  131. OK := TRUE;
  132. END;
  133. END StrToDate;
  134. PROCEDURE StrToDate2( DateStr: ARRAY OF CHAR; EuropeanStyle: BOOLEAN;
  135. VAR day, month, year: CARDINAL ): BOOLEAN;
  136. VAR
  137. spot: CARDINAL;
  138. separator: ARRAY [0..0] OF CHAR;
  139. BEGIN
  140. StrEdit.CrunchBlanks( DateStr );
  141. separator[0] := '/';
  142. IF NOT PosUtils.PresentPos( separator, DateStr, spot ) THEN
  143. separator[0] := '-';
  144. IF NOT PosUtils.PresentPos( separator, DateStr, spot ) THEN
  145. separator[0] := ':';
  146. IF NOT PosUtils.PresentPos( separator, DateStr, spot ) THEN
  147. separator[0] := ' ';
  148. IF NOT PosUtils.PresentPos( separator, DateStr, spot ) THEN
  149. RETURN FALSE;
  150. END;
  151. END;
  152. END;
  153. END;
  154. IF NOT StrConv.StrToCardinal( DateStr, 0, day ) THEN
  155. RETURN FALSE;
  156. END;
  157. IF NOT StrConv.StrToCardinal( DateStr, spot + 1, month ) THEN
  158. RETURN FALSE;
  159. END;
  160. IF (month > 12) OR (NOT EuropeanStyle) THEN
  161. (* use year as a temp to do swap *)
  162. year := day;
  163. day := month;
  164. month := year;
  165. END;
  166. spot := PosUtils.Positn( separator, DateStr, spot + 1 );
  167. IF spot > HIGH(DateStr) THEN
  168. RETURN FALSE;
  169. END;
  170. IF NOT StrConv.StrToCardinal( DateStr, spot + 1, year ) THEN
  171. RETURN FALSE;
  172. END;
  173. RETURN TRUE;
  174. END StrToDate2;
  175. PROCEDURE Day(d: Date): CARDINAL;
  176. BEGIN
  177. IF ValidDate(d) THEN
  178. RETURN d.day
  179. ELSE
  180. RETURN 0
  181. END;
  182. END Day;
  183. PROCEDURE LeapYear(year: CARDINAL): BOOLEAN;
  184. BEGIN
  185. RETURN ((year MOD 4 = 0) AND (year MOD 100 # 0)) OR (year MOD 400 = 0)
  186. END LeapYear;
  187. PROCEDURE DayOfWeek(d: Date; VAR wkday: ARRAY OF CHAR);
  188. VAR
  189. daytable: ARRAY [1..12] OF CARDINAL;
  190. centurytable: ARRAY [1..5] OF CARDINAL;
  191. century, yearincent, result, i: CARDINAL;
  192. PROCEDURE InitCent;
  193. BEGIN
  194. centurytable[1] := 1;
  195. centurytable[2] := 2;
  196. centurytable[3] := 0;
  197. centurytable[4] := 6;
  198. centurytable[5] := 4;
  199. END InitCent;
  200. PROCEDURE InitDayTable;
  201. BEGIN
  202. daytable[1] := 0;
  203. daytable[2] := 3;
  204. daytable[3] := 3;
  205. daytable[4] := 6;
  206. daytable[5] := 1;
  207. daytable[6] := 4;
  208. daytable[7] := 6;
  209. daytable[8] := 2;
  210. daytable[9] := 5;
  211. daytable[10] := 0;
  212. daytable[11] := 3;
  213. daytable[12] := 5;
  214. END InitDayTable;
  215. BEGIN
  216. IF ValidDate(d) THEN
  217. InitDayTable;
  218. InitCent;
  219. IF LeapYear(d.yr) THEN
  220. daytable[1] := 6;
  221. daytable[2] := 2;
  222. END;
  223. century := d.yr DIV 100;
  224. yearincent := d.yr - century*100;
  225. result := centurytable[century-16] + yearincent +
  226. (yearincent DIV 4) + daytable[d.mo] + d.day;
  227. (* NOTE!!! the above configuration is only likely to be accurate
  228. for 20th & 21st century *)
  229. CASE result MOD 7 OF
  230. 0: M2Strings.Copy("Sunday", 0, HIGH(wkday), wkday);
  231. | 1: M2Strings.Copy("Monday", 0, HIGH(wkday), wkday);
  232. | 2: M2Strings.Copy("Tuesday", 0, HIGH(wkday), wkday);
  233. | 3: M2Strings.Copy("Wednesday", 0, HIGH(wkday), wkday);
  234. | 4: M2Strings.Copy("Thursday", 0, HIGH(wkday), wkday);
  235. | 5: M2Strings.Copy("Friday", 0, HIGH(wkday), wkday);
  236. | 6: M2Strings.Copy("Saturday", 0, HIGH(wkday), wkday);
  237. END; (* case*)
  238. ELSE
  239. FOR i := 0 TO HIGH(wkday) DO
  240. wkday[i] := '*'
  241. END;
  242. END;
  243. END DayOfWeek;
  244. PROCEDURE Month(d: Date): CARDINAL;
  245. BEGIN
  246. IF ValidDate(d) THEN
  247. RETURN d.mo
  248. ELSE
  249. RETURN 0
  250. END;
  251. END Month;
  252. PROCEDURE CalendarMonth(d: Date; VAR cmonth: ARRAY OF CHAR);
  253. BEGIN
  254. IF ValidDate(d) THEN
  255. CASE d.mo OF
  256. 1: M2Strings.Copy('January', 0, 9, cmonth);
  257. | 2: M2Strings.Copy('February', 0, 9, cmonth);
  258. | 3: M2Strings.Copy('March', 0, 9, cmonth);
  259. | 4: M2Strings.Copy('April', 0, 9, cmonth);
  260. | 5: M2Strings.Copy('May', 0, 9, cmonth);
  261. | 6: M2Strings.Copy('June', 0, 9, cmonth);
  262. | 7: M2Strings.Copy('July', 0, 9, cmonth);
  263. | 8: M2Strings.Copy('August', 0, 9, cmonth);
  264. | 9: M2Strings.Copy('September', 0, 9, cmonth);
  265. | 10: M2Strings.Copy('October', 0, 9, cmonth);
  266. | 11: M2Strings.Copy('November', 0, 9, cmonth);
  267. | 12: M2Strings.Copy('December', 0, 9, cmonth);
  268. END; (* case *)
  269. ELSE
  270. M2Strings.Copy('********',0, 8, cmonth);
  271. END;
  272. END CalendarMonth;
  273. PROCEDURE Year(d: Date): CARDINAL;
  274. BEGIN
  275. IF ValidDate(d) THEN
  276. RETURN (d.yr)
  277. ELSE
  278. RETURN 0
  279. END;
  280. END Year;
  281. PROCEDURE DateToWritten(d: Date; VAR written: ARRAY OF CHAR);
  282. VAR
  283. temp: ARRAY [0..4] OF CHAR;
  284. BEGIN
  285. CalendarMonth(d, written);
  286. M2Strings.Concat(written, ' ', written);
  287. StrConv.CardinalToStr(d.day, 0, temp);
  288. M2Strings.Concat(written, temp, written);
  289. M2Strings.Concat(written, ', ', written);
  290. StrConv.CardinalToStr(d.yr, 0, temp);
  291. M2Strings.Concat(written, temp, written);
  292. END DateToWritten;
  293. PROCEDURE DatePlusDays(VAR d: Date; days: CARDINAL; VAR OK: BOOLEAN);
  294. BEGIN
  295. IF NOT ValidDate(d) THEN
  296. WITH d DO
  297. yr := 0;
  298. mo := 0;
  299. day := 0;
  300. END;
  301. OK := FALSE
  302. ELSE
  303. CardToDate(DaysSince1900(d) + days, d);
  304. OK := TRUE
  305. END;
  306. END DatePlusDays;
  307. PROCEDURE InitMonths;
  308. BEGIN
  309. monthsize[1] := 31;
  310. monthsize[2] := 28;
  311. monthsize[3] := 31;
  312. monthsize[4] := 30;
  313. monthsize[5] := 31;
  314. monthsize[6] := 30;
  315. monthsize[7] := 31;
  316. monthsize[8] := 31;
  317. monthsize[9] := 30;
  318. monthsize[10] := 31;
  319. monthsize[11] := 30;
  320. monthsize[12] := 31;
  321. END InitMonths;
  322. PROCEDURE ValidDate(d: Date): BOOLEAN;
  323. BEGIN
  324. IF LeapYear(d.yr)THEN
  325. monthsize[2] := 29;
  326. ELSE
  327. monthsize[2] := 28;
  328. END;
  329. RETURN((d.mo >= 1) AND (d.mo <= 12)) AND
  330. ((d.day >=1) AND (d.day <= monthsize[d.mo])) AND
  331. ((d.yr >= MinYear) AND (d.yr <= MaxYear));
  332. END ValidDate;
  333. PROCEDURE DaysSince1900(d: Date): CARDINAL;
  334. VAR
  335. yearsSince, leapYearsSince, result: CARDINAL;
  336. BEGIN
  337. IF ValidDate(d) THEN
  338. yearsSince := (d.yr - 1900) * 365;
  339. result:=d.yr-1900;
  340. IF result>1 THEN DEC(result) END;
  341. leapYearsSince := (result) DIV 4;
  342. result := yearsSince + leapYearsSince + DayOfYear(d)-1;
  343. (* IF LeapYear(d.yr) AND (d.mo > 2) THEN
  344. INC( result );
  345. END; *)
  346. RETURN result
  347. ELSE
  348. RETURN 0
  349. END;
  350. END DaysSince1900;
  351. PROCEDURE DayOfYear(d:Date): CARDINAL;
  352. (* Returns 0 if the date is not Valid *)
  353. VAR julian: CARDINAL;
  354. BEGIN
  355. IF ValidDate(d) THEN
  356. IF LeapYear(d.yr) AND (d.mo > 2) THEN
  357. julian := monthtotalleap[d.mo] + d.day;
  358. ELSE
  359. julian := monthtotal[d.mo] + d.day;
  360. END;
  361. RETURN julian
  362. ELSE
  363. RETURN 0
  364. END;
  365. END DayOfYear;
  366. PROCEDURE CardToDate(n: CARDINAL; VAR d: Date);
  367. VAR julday,
  368. c,LeapYears: CARDINAL;
  369. BEGIN
  370. d.yr := n DIV 365;
  371. julday:= n MOD 365+1;
  372. c:=d.yr;
  373. IF c >1 THEN DEC(c) END;
  374. LeapYears:= c DIV 4;(* leap years is to count preceding not current *)
  375. IF (julday > LeapYears) THEN
  376. DEC(julday,LeapYears)
  377. ELSE
  378. julday:=julday+365-LeapYears;
  379. DEC(d.yr);
  380. IF( d.yr#0) AND ((d.yr MOD 4) =0)
  381. THEN
  382. INC(julday);(* do not want to count leap day twice *)
  383. END;
  384. END;
  385. d.yr := d.yr + 1900;
  386. d.mo := 0;
  387. d.day := 0;
  388. IF NOT LeapYear(d.yr) THEN
  389. (* DEC (julday);*)
  390. REPEAT
  391. INC(d.mo)
  392. UNTIL (d.mo = 12) OR (julday <= monthtotal[d.mo + 1]);
  393. d.day := julday - monthtotal[d.mo];
  394. ELSE
  395. REPEAT
  396. INC(d.mo)
  397. UNTIL (d.mo = 12) OR (julday <= monthtotalleap[d.mo + 1]);
  398. (* note: can't just add 1 -- it throws January off!! *)
  399. d.day := julday - (monthtotalleap[d.mo]);
  400. END;
  401. END CardToDate;
  402. PROCEDURE CompareDates(d1, d2: Date): Comparison;
  403. BEGIN
  404. IF d1.yr > d2.yr THEN
  405. RETURN DateGreater
  406. ELSIF d1.yr < d2.yr THEN
  407. RETURN DateLess
  408. ELSE
  409. IF d1.mo > d2.mo THEN
  410. RETURN DateGreater
  411. ELSIF d1.mo < d2.mo THEN
  412. RETURN DateLess
  413. ELSE
  414. IF d1.day > d2.day THEN
  415. RETURN DateGreater
  416. ELSIF d1.day < d2.day THEN
  417. RETURN DateLess
  418. ELSE
  419. RETURN DateEqual
  420. END;
  421. END;
  422. END;
  423. RETURN DateEqual;
  424. END CompareDates;
  425. PROCEDURE DateDiff(d1, d2: Date): CARDINAL;
  426. BEGIN
  427. IF CompareDates(d1, d2) = DateGreater THEN
  428. RETURN(DaysSince1900(d1) - DaysSince1900(d2))
  429. ELSE
  430. RETURN(DaysSince1900(d2) - DaysSince1900(d1))
  431. END;
  432. END DateDiff;
  433. PROCEDURE Init();
  434. BEGIN
  435. IF Initialized THEN
  436. RETURN;
  437. ELSE
  438. Initialized := TRUE;
  439. END;
  440. (*EntryDiag:
  441. Diagnostics.Init();
  442. :EntryDiag*)
  443. M2Strings.Init();
  444. PosUtils.Init();
  445. StrConv.Init();
  446. StrEdit.Init();
  447. (*EntryDiag:
  448. Diagnostics.diagS( 'Entering DateFunctions', '' );
  449. :EntryDiag*)
  450. InitMonthTotal();
  451. InitMonths();
  452. (*EntryDiag:
  453. Diagnostics.diagS( 'Exiting DateFunctions', '' );
  454. :EntryDiag*)
  455. END Init;
  456. BEGIN
  457. Initialized := FALSE;
  458. Init();
  459. END DateFunctions.
  460.