home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / pascal / tplib21.zip / INSTALL.EXE / TIME.PAS < prev   
Pascal/Delphi Source File  |  1993-06-24  |  22KB  |  727 lines

  1. (*
  2.     TURBO PASCAL LIBRARY 2.1
  3.     TIME unit: Extended date and time routines
  4. *)
  5.  
  6. UNIT TIME;
  7.  
  8. {$V-}
  9.  
  10. {$L DATE}
  11. {$L TIME}
  12.  
  13.  
  14. INTERFACE
  15.  
  16. USES
  17.     DOS;
  18.  
  19. TYPE
  20.     DateString =    STRING[9];
  21.     TimeString =    STRING[13];
  22.  
  23.     DateRec =       RECORD
  24.                         M,D:    BYTE;
  25.                         Y:      WORD;
  26.                     END;
  27.  
  28.     TimeRec =       RECORD
  29.                         H,M,S:  BYTE;
  30.                     END;
  31.  
  32.  
  33.  
  34. CONST
  35.     DateFormNumeric      = 0;       { Values for DateFormat }
  36.     DateFormAlpha        = 1;
  37.     DateFormMDY          = 2;
  38.     DateFormDMY          = 3;
  39.     DateFormLower        = 4;
  40.     DateFormZeroFill     = 8;
  41.  
  42.     FullDateFormMDY      = 0;       { Values for FullDateFormat }
  43.     FullDateFormDMY      = 1;
  44.  
  45.     TimeFormNormal       = 0;       { TimeFormat values }
  46.     TimeFormNormalSec    = 1;
  47.     TimeFormShort        = 2;
  48.     TimeFormShortSec     = 3;
  49.     TimeFormMilitary     = 4;
  50.     TimeFormMilitarySec  = 5;
  51.     TimeFormMilitaryHHMM = 6;
  52.  
  53.     TimeFormat:         BYTE        = TimeFormNormal;
  54.     DateFormat:         BYTE        = DateFormNumeric;
  55.     FullDateFormat:     BYTE        = FullDateFormMDY;
  56.     TimeDelimiter:      CHAR        = ':';
  57.     DateDelimiter:      CHAR        = '/';
  58.     TimeParseDelims:    TimeString  = ':., '+#9;
  59.     DateParseDelims:    DateString  = '/-., '+#9;
  60.     TimeParseNow:       BOOLEAN     = FALSE;
  61.     DateParseToDay:     BOOLEAN     = FALSE;
  62.     DateParseCurYear:   BOOLEAN     = FALSE;
  63.     DateParseCent21:    BYTE        = 0;
  64.  
  65.  
  66.  
  67.  
  68. PROCEDURE CombineDateTime(VAR DtTm: DateTime; Dt: DateRec; Tm: TimeRec);
  69. PROCEDURE SplitDateTime(DtTm: DateTime; VAR Dt: DateRec; VAR Tm: TimeRec);
  70. PROCEDURE GetToDay(VAR Dt: DateRec);
  71. PROCEDURE GetTimeNow(VAR Tm: TimeRec);
  72. PROCEDURE GetDateTime(VAR DtTm: DateTime);
  73. FUNCTION  DateValid(Dt: DateRec): BOOLEAN;
  74. FUNCTION  TimeValid(Tm: TimeRec): BOOLEAN;
  75. FUNCTION  DateTimeValid(DtTm: DateTime): BOOLEAN;
  76. PROCEDURE WordToDate(w: WORD; VAR Dt: DateRec);
  77. FUNCTION  DateToWord(Dt: DateRec): WORD;
  78. FUNCTION  LeapYear(Y: WORD): BOOLEAN;
  79. FUNCTION  TimeAP(Tm: TimeRec): TimeString;
  80. PROCEDURE AdjustDate(VAR Dt: DateRec; n: INTEGER);
  81. PROCEDURE AdjustTime(VAR Tm: TimeRec; n: LongInt);
  82. PROCEDURE AdjustDateTime(VAR DtTm: DateTime; n: LongInt);
  83. PROCEDURE SetLastDay(VAR Dt: DateRec);
  84. FUNCTION  DayOfWeek(w: WORD): BYTE;
  85. FUNCTION  DayOfWeekStr(d: BYTE): DateString;
  86. FUNCTION  MonthStr(M: BYTE): DateString;
  87. FUNCTION  DayOfMonthStr(D: BYTE): DateString;
  88. FUNCTION  DateStr(Dt: DateRec): DateString;
  89. FUNCTION  FullDateStr(Dt: DateRec): STRING;
  90. FUNCTION  TimeStr(Tm: TimeRec): TimeString;
  91. FUNCTION  DateParse(s: STRING; VAR Dt: DateRec): BOOLEAN;
  92. FUNCTION  TimeParse(s: STRING; VAR Tm: TimeRec): BOOLEAN;
  93.  
  94.  
  95.  
  96. IMPLEMENTATION
  97.  
  98. USES
  99.     STRINGS;
  100.  
  101. VAR
  102.     BritishFormat:  BOOLEAN;    { Set from country-dependent information }
  103.  
  104.  
  105. PROCEDURE SetCountry; EXTERNAL;
  106.  
  107.  
  108. PROCEDURE CombineDateTime(VAR DtTm: DateTime; Dt: DateRec; Tm: TimeRec);
  109.  
  110.     BEGIN
  111.         WITH DtTm DO
  112.             BEGIN
  113.                 Year:=Dt.Y;
  114.                 Month:=Dt.M;
  115.                 Day:=Dt.D;
  116.                 Hour:=Tm.H;
  117.                 Min:=Tm.M;
  118.                 Sec:=Tm.S;
  119.             END;
  120.     END;
  121.  
  122.  
  123. PROCEDURE SplitDateTime(DtTm: DateTime; VAR Dt: DateRec; VAR Tm: TimeRec);
  124.  
  125.     BEGIN
  126.         WITH DtTm DO
  127.             BEGIN
  128.                 Dt.M:=Month;
  129.                 Dt.D:=Day;
  130.                 Dt.Y:=Year;
  131.                 Tm.H:=Hour;
  132.                 Tm.M:=Min;
  133.                 Tm.S:=Sec;
  134.             END;
  135.     END;
  136.  
  137.  
  138. PROCEDURE GetToDay(VAR Dt: DateRec); EXTERNAL;
  139. PROCEDURE GetTimeNow(VAR Tm: TimeRec); EXTERNAL;
  140.  
  141. PROCEDURE GetDateTime(VAR DtTm: DateTime);
  142.  
  143.     VAR
  144.         x:  WORD;
  145.  
  146.     BEGIN
  147.         WITH DtTm DO
  148.             BEGIN
  149.                 GetDate(Year,Month,Day,x);
  150.                 GetTime(Hour,Min,Sec,x);
  151.             END;
  152.     END;
  153.  
  154.  
  155. FUNCTION  DateValid(Dt: DateRec): BOOLEAN;
  156.  
  157.     VAR
  158.         v:  BOOLEAN;
  159.  
  160.     BEGIN
  161.         WITH Dt DO
  162.             BEGIN
  163.                 CASE M OF                           { Check upper day limit }
  164.                     1,3,5,7,8,10,12:  v:=D<=31;
  165.                     4,6,9,11:         v:=D<=30;
  166.                     2:                IF LeapYear(Y) THEN
  167.                                           v:=D<=29
  168.                                       ELSE
  169.                                           v:=D<=28;
  170.                     ELSE              v:=FALSE;     { Check month range }
  171.                 END;                                { Check lower day/year }
  172.                 DateValid:=v AND (D>0) AND (Y>=1900) AND (Y<=2079);
  173.                 IF (Y=2079) AND ((M>6) OR ((M=6) AND (D>6))) THEN
  174.                     DateValid:=FALSE;               { Limit of 6/6/2079 }
  175.             END;
  176.     END;
  177.  
  178.  
  179. FUNCTION  TimeValid(Tm: TimeRec): BOOLEAN;
  180.  
  181.     BEGIN
  182.         WITH Tm DO
  183.             TimeValid:=(H<24) AND (M<60) AND (S<60);
  184.     END;
  185.  
  186.  
  187.  
  188. FUNCTION DateTimeValid(DtTm: DateTime): BOOLEAN;
  189.  
  190.     VAR
  191.         d:  DateRec;
  192.         t:  TimeRec;
  193.         v:  BOOLEAN;
  194.  
  195.     BEGIN
  196.         WITH DtTm DO
  197.             v:=((Month OR Day OR Hour OR Min OR Sec) AND $FF00)=0;
  198.         SplitDateTime(DtTm,d,t);
  199.         DateTimeValid:=v AND DateValid(d) AND TimeValid(t);
  200.     END;
  201.  
  202.  
  203. PROCEDURE WordToDate(w: WORD; VAR Dt: DateRec);
  204.  
  205.     VAR
  206.         i:  INTEGER;
  207.         j:  LONGINT;
  208.  
  209.     BEGIN
  210.         WITH Dt DO
  211.             BEGIN
  212.                 IF w<=58 THEN
  213.                     BEGIN
  214.                         Y:=1900;
  215.                         IF w<=30 THEN
  216.                             BEGIN
  217.                                 M:=1;
  218.                                 D:=SUCC(w);
  219.                             END
  220.                         ELSE
  221.                             BEGIN
  222.                                 M:=2;
  223.                                 D:=w-30;
  224.                             END;
  225.                     END
  226.                 ELSE
  227.                     BEGIN
  228.                         j:=4*LONGINT(w)-233;
  229.                         Y:=J DIV 1461+1900;
  230.                         i:=J MOD 1461 DIV 4*5+2;
  231.                         M:=i DIV 153;
  232.                         D:=i MOD 153 DIV 5+1;
  233.                         IF M<10 THEN
  234.                             INC(M,3)
  235.                         ELSE
  236.                             BEGIN
  237.                                 DEC(M,9);
  238.                                 INC(Y);
  239.                             END;
  240.                     END;
  241.             END;  { WITH Dt }
  242.     END;  { WordToDate }
  243.  
  244.  
  245. FUNCTION  DateToWord(Dt: DateRec): WORD;
  246.  
  247.     BEGIN
  248.         WITH Dt DO
  249.             BEGIN
  250.                 IF (Y=1900) AND (M<3) THEN
  251.                     IF M=1 THEN
  252.                         DateToWord:=PRED(D)
  253.                     ELSE
  254.                         DateToWord:=D+30
  255.                 ELSE
  256.                     BEGIN
  257.                         IF M>2 THEN
  258.                             DEC(M,3)
  259.                         ELSE
  260.                             BEGIN
  261.                                 INC(M,9);
  262.                                 DEC(Y);
  263.                             END;
  264.                         DEC(Y,1900);
  265.                         DateToWord:=
  266.                             (1461*LONGINT(Y) DIV 4)+((153*M+2) DIV 5)+D+58;
  267.                     END;
  268.             END;  { WITH Dt }
  269.     END;  { DateToWord }
  270.  
  271.  
  272. FUNCTION  LeapYear(Y: WORD): BOOLEAN;
  273.  
  274.     BEGIN
  275.         IF (Y MOD 4)<>0 THEN        { If Y not divisible by 4, not leap year }
  276.             LeapYear:=FALSE
  277.         ELSE
  278.             IF (Y MOD 100)<>0 THEN  { If divisible by 4 but not 100, is leap }
  279.                 LeapYear:=TRUE
  280.             ELSE
  281.                 LeapYear:=(Y MOD 400)=0;    { If div. by 100, only leap year }
  282.     END;                                    { if also div. by 400 }
  283.  
  284.  
  285. FUNCTION  TimeAP(Tm: TimeRec): TimeString;
  286.  
  287.     BEGIN
  288.         IF Tm.H<12 THEN
  289.             TimeAP:='a.m.'
  290.         ELSE
  291.             TimeAP:='p.m.';
  292.     END;
  293.  
  294.  
  295.  
  296. PROCEDURE AdjustDate(VAR Dt: DateRec; n: INTEGER);
  297.  
  298.     VAR
  299.         w:  WORD;
  300.  
  301.     BEGIN
  302.         w:=DateToWord(Dt)+n;
  303.         WordToDate(w,Dt);
  304.     END;
  305.  
  306.  
  307.  
  308. { Adjust Tm by number of seconds specified.  Returns value indicating number
  309.   of days to adjust date by, or zero if adjustment did not pass midnight. }
  310.  
  311. FUNCTION AddSecsToTime(VAR Tm: TimeRec; n: LongInt): INTEGER;
  312.  
  313.     VAR
  314.         sc:     LongInt;
  315.         days:   INTEGER;
  316.  
  317.     BEGIN
  318.         days:=0;
  319.         WITH Tm DO
  320.             BEGIN
  321.                 sc:=S+n;                    { Adjust seconds }
  322.                 WHILE sc<0 DO               { If moving backward past zero }
  323.                     BEGIN                   { adjust mins/hrs back }
  324.                         sc:=sc+60;
  325.                         IF M>0 THEN
  326.                             DEC(M)
  327.                         ELSE
  328.                             BEGIN
  329.                                 M:=59;
  330.                                 IF H=0 THEN
  331.                                     BEGIN
  332.                                         H:=23;
  333.                                         DEC(days);
  334.                                     END
  335.                                 ELSE
  336.                                     DEC(H);
  337.                             END;
  338.                     END;
  339.                 WHILE sc>59 DO              { If moving forward past 59 secs }
  340.                     BEGIN                   { adjust mins/hrs forward }
  341.                         sc:=sc-60;
  342.                         IF M=59 THEN
  343.                             BEGIN
  344.                                 M:=0;
  345.                                 IF H=23 THEN
  346.                                     BEGIN
  347.                                         H:=0;
  348.                                         INC(days);
  349.                                     END
  350.                                 ELSE
  351.                                     INC(H);
  352.                             END
  353.                         ELSE
  354.                             INC(M);
  355.                     END;
  356.                 S:=sc;                      { Restore seconds field }
  357.             END;  { WITH Tm }
  358.         AddSecsToTime:=days;                { Return day adjustment figure }
  359.     END;
  360.  
  361.  
  362. PROCEDURE AdjustTime(VAR Tm: TimeRec; n: LongInt);
  363.  
  364.     VAR
  365.         x:  INTEGER;
  366.  
  367.     BEGIN
  368.         x:=AddSecsToTime(Tm,n);
  369.     END;
  370.  
  371.  
  372. PROCEDURE AdjustDateTime(VAR DtTm: DateTime; n: LongInt);
  373.  
  374.     VAR
  375.         d:  DateRec;
  376.         t:  TimeRec;
  377.  
  378.     BEGIN
  379.         SplitDateTime(DtTm,d,t);
  380.         AdjustDate(d,AddSecsToTime(t,n));
  381.         CombineDateTime(DtTm,d,t);
  382.     END;
  383.  
  384.  
  385. PROCEDURE SetLastDay(VAR Dt: DateRec);
  386.  
  387.     BEGIN
  388.         WITH Dt DO
  389.             CASE M OF
  390.                 2:        IF LeapYear(Y) THEN
  391.                               D:=29
  392.                           ELSE
  393.                               D:=28;
  394.                 4,6,9,11: D:=30;
  395.                 ELSE      D:=31;
  396.             END;
  397.     END;
  398.  
  399.  
  400. FUNCTION  DayOfWeek(w: WORD): BYTE;
  401.  
  402.     BEGIN
  403.         DayOfWeek:=SUCC(w) MOD 7;       { 0=Sunday thru 6=Saturday }
  404.     END;
  405.  
  406.  
  407. FUNCTION DayOfWeekStr(d: BYTE): DateString;
  408.  
  409.     CONST
  410.         days: ARRAY[0..6] OF DateString = ('Sunday','Monday','Tuesday',
  411.                             'Wednesday','Thursday','Friday','Saturday');
  412.  
  413.     BEGIN
  414.         IF (d>6) THEN
  415.             DayOfWeekStr:=''            { Return null if d out of range }
  416.         ELSE
  417.             DayOfWeekStr:=days[d];
  418.     END;
  419.  
  420.  
  421. FUNCTION  MonthStr(M: BYTE): DateString;
  422.  
  423.     CONST
  424.         months: ARRAY[1..12] OF DateString =
  425.             ('January','February','March','April','May','June','July',
  426.              'August','September','October','November','December');
  427.  
  428.     BEGIN
  429.         IF M IN [1..12] THEN
  430.             MonthStr:=months[M]
  431.         ELSE
  432.             MonthStr:='';           { Return null if M out of range }
  433.     END;
  434.  
  435.  
  436. FUNCTION  DayOfMonthStr(D: BYTE): DateString;
  437.  
  438.     VAR
  439.         s:  STRING[2];
  440.  
  441.     BEGIN
  442.         IF D IN [1..31] THEN
  443.             BEGIN
  444.                 STR(D,s);       { Convert to string, add appropriate suffix }
  445.                 CASE D OF
  446.                     1,21,31:  DayOfMonthStr:=CONCAT(s,'st');
  447.                     2,22:     DayOfMonthStr:=CONCAT(s,'nd');
  448.                     3,23:     DayOfMonthStr:=CONCAT(s,'rd');
  449.                     ELSE      DayOfMonthStr:=CONCAT(s,'th');
  450.                 END;
  451.             END
  452.         ELSE
  453.             DayOfMonthStr:='';  { Return null if D out of range }
  454.     END;
  455.  
  456.  
  457. FUNCTION  DateStr(Dt: DateRec): DateString;
  458.  
  459.     VAR
  460.         s:      DateString;
  461.         mm,dd:  STRING[2];
  462.         yy:     STRING[4];
  463.  
  464.     BEGIN
  465.         WITH Dt DO                  { Convert each field to a string }
  466.             BEGIN
  467.                 STR(M:2,mm);
  468.                 STR(D:2,dd);
  469.                 STR(Y:4,yy);
  470.             END;
  471.         CASE (DateFormat AND 3) OF
  472.             0:  IF BritishFormat THEN
  473.                     s:=CONCAT(dd,DateDelimiter,mm,DateDelimiter,COPY(yy,3,2))
  474.                 ELSE
  475.                     s:=CONCAT(mm,DateDelimiter,dd,DateDelimiter,COPY(yy,3,2));
  476.             1:  BEGIN
  477.                     s:=CONCAT(dd,DateDelimiter,COPY(MonthStr(Dt.M),1,3),
  478.                               DateDelimiter,COPY(yy,3,2));
  479.                     IF (DateFormat AND DateFormLower)=0 THEN
  480.                         s:=UpperCase(s);
  481.                 END;
  482.             2:  s:=CONCAT(mm,DateDelimiter,dd,DateDelimiter,COPY(yy,3,2));
  483.             3:  s:=CONCAT(dd,DateDelimiter,mm,DateDelimiter,COPY(yy,3,2));
  484.         END;  { CASE }
  485.         IF s[4]=#32 THEN
  486.             s[4]:='0';
  487.         IF ((DateFormat AND DateFormZeroFill)<>0) AND (s[1]=#32) THEN
  488.             s[1]:='0';
  489.         DateStr:=s;
  490.     END;
  491.  
  492.  
  493. FUNCTION  FullDateStr(Dt: DateRec): STRING;
  494.  
  495.     VAR
  496.         yy: STRING[4];
  497.         dd: STRING[2];
  498.  
  499.     BEGIN
  500.         WITH Dt DO
  501.             BEGIN
  502.                 STR(Y:4,yy);
  503.                 IF (FullDateFormat AND 1)<>0 THEN
  504.                     FullDateStr:=CONCAT(DayOfMonthStr(D),#32,
  505.                                         MonthStr(M),#32,yy)
  506.                 ELSE
  507.                     BEGIN
  508.                         STR(D,dd);
  509.                         FullDateStr:=CONCAT(MonthStr(M),#32,dd,', ',yy);
  510.                     END;
  511.             END;  { WITH Dt }
  512.     END;  { FullDateStr }
  513.  
  514.  
  515. FUNCTION  TimeStr(Tm: TimeRec): TimeString;
  516.  
  517.     VAR
  518.         hh,mm,ss:   STRING[2];
  519.         t:          TimeString;
  520.  
  521.     BEGIN
  522.         WITH Tm DO
  523.             IF TimeFormat>=TimeFormMilitary THEN    { Set hours 00 thru 23 }
  524.                 BEGIN
  525.                     STR(H:2,hh);
  526.                     IF hh[1]=#32 THEN
  527.                         hh[1]:='0';
  528.                 END
  529.             ELSE                        { If standard, set hours to 1 thru 12 }
  530.                 IF H>12 THEN
  531.                     STR((H-12):2,hh)
  532.                 ELSE
  533.                     BEGIN
  534.                         STR(H:2,hh);
  535.                         IF H=0 THEN
  536.                             hh:='12';
  537.                     END;
  538.         STR(Tm.M:2,mm);                 { Convert minutes field }
  539.         IF mm[1]=#32 THEN
  540.             mm[1]:='0';
  541.         IF TimeFormat=TimeFormMilitaryHHMM THEN
  542.             t:=CONCAT(hh,mm)            { Concatenate hours and minutes }
  543.         ELSE
  544.             t:=CONCAT(hh,TimeDelimiter,mm);
  545.         IF (TimeFormat AND 1)<>0 THEN   { Convert seconds if required }
  546.             BEGIN
  547.                 STR(Tm.S:2,ss);
  548.                 IF ss[1]=#32 THEN
  549.                     ss[1]:='0';
  550.                 t:=CONCAT(t,TimeDelimiter,ss);
  551.             END;
  552.         IF TimeFormat<TimeFormShort THEN            { Add a.m./p.m. suffix }
  553.             TimeStr:=CONCAT(t,#32,TimeAP(Tm))
  554.         ELSE
  555.             TimeStr:=t;
  556.     END;  { TimeStr }
  557.  
  558.  
  559.  
  560. FUNCTION  DateParse(s: STRING; VAR Dt: DateRec): BOOLEAN;
  561.  
  562.     CONST
  563.         blanks = #32+#9;
  564.  
  565.     VAR
  566.         s1:     STRING;
  567.         f1,f2:  BOOLEAN;
  568.         b:      BYTE;
  569.         x:      INTEGER;
  570.         td:     DateRec;
  571.  
  572.  
  573.     { Parse string s.  If it holds numeric characters only, return
  574.       converted value in v and set f to false.  If non-numeric characters
  575.       found, match string against month abbreviations and return month number
  576.       with f set to true.  Returns v=zero if conversion/match failed. }
  577.  
  578.     PROCEDURE GetVal(s: STRING; VAR v: BYTE; VAR f: BOOLEAN);
  579.  
  580.         CONST
  581.             months: ARRAY[1..12] OF STRING[3] =
  582.                         ('JAN','FEB','MAR','APR','MAY','JUN',
  583.                          'JUL','AUG','SEP','OCT','NOV','DEC');
  584.  
  585.         BEGIN
  586.             f:=LENGTH(Remove(s,DecDigits))<>0;  { Clear flag if nums. only }
  587.             IF f THEN
  588.                 BEGIN               { If not numeric, check month abbrevs. }
  589.                     v:=1;
  590.                     WHILE (v<=12) AND (TruncR(s,3)<>months[v]) DO
  591.                         INC(v);
  592.                     IF v>12 THEN
  593.                         v:=0;       { Return zero if no match found }
  594.                 END
  595.             ELSE
  596.                 BEGIN                       { If numeric, convert }
  597.                     VAL (TrimR(s),v,x);
  598.                     IF x<>0 THEN          { Return zero if unsuccessful }
  599.                         v:=0;
  600.                 END;
  601.         END;  { GetVal }
  602.  
  603.  
  604.     BEGIN  { DateParse }
  605.         s:=UpperCase(TrimL(TrimR(s)));  { Remove blanks, make upper case }
  606.         IF DateParseToDay AND (LENGTH(s)=0) THEN
  607.             BEGIN
  608.                 GetToDay(Dt);           { Return current date if null }
  609.                 DateParse:=TRUE;        { input and allowed }
  610.                 EXIT;
  611.             END;
  612.         s1:=Break(s,DateParseDelims);   { Extract first part of date }
  613.         GetVal(s1,Dt.M,f1);             { Assume it is month }
  614.         Delete(s,1,1);                  { Remove delimiter from input }
  615.         s1:=Span(s,blanks);             { Remove extra blanks }
  616.         s1:=Break(s,DateParseDelims);   { Extract second part of date }
  617.         GetVal(s1,Dt.D,f2);             { Assume it is day number }
  618.         Delete(s,1,1);                  { Remove delimiter and extra blanks }
  619.         s1:=Span(s,blanks);
  620.         WITH Dt DO
  621.             IF DateParseCurYear AND (LENGTH(s)=0) THEN         
  622.                 BEGIN
  623.                     GetToDay(td);       { If no year, assume current year }
  624.                     Y:=td.Y;
  625.                 END
  626.             ELSE
  627.                 BEGIN
  628.                     VAL(s,Y,x);         { Assume remaining input is year }
  629.                     IF x<>0 THEN        { Set year=zero if convert failed }
  630.                         Y:=0
  631.                     ELSE
  632.                         IF Y<100 THEN   { Convert years xx to 19xx or 20xx }
  633.                             IF Y<DateParseCent21 THEN
  634.                                 Y:=Y+2000
  635.                             ELSE
  636.                                 Y:=Y+1900;
  637.                 END;
  638.         IF f1 THEN                  { Check month and day fields }
  639.             BEGIN
  640.                 IF f2 THEN          { If both alphabetic, force error }
  641.                       Dt.M:=0;
  642.             END
  643.         ELSE
  644.             IF f2 OR ((DateFormat AND 3)=DateFormDMY) OR
  645.             (((DateFormat AND 3)=DateFormNumeric) AND BritishFormat) THEN
  646.                 BEGIN               { Swap fields if necessary }
  647.                     b:=Dt.M;
  648.                     Dt.M:=Dt.D;
  649.                     Dt.D:=b;
  650.                 END;
  651.         DateParse:=DateValid(Dt);       { Return success/failure flag }
  652.     END;  { DateParse }
  653.  
  654.  
  655.  
  656. FUNCTION  TimeParse(s: STRING; VAR Tm: TimeRec): BOOLEAN;
  657.  
  658.     CONST
  659.         blanks = #32+#9;
  660.  
  661.     VAR
  662.         s1: STRING;
  663.         x:  INTEGER;
  664.         i:  (none,am,pm);
  665.  
  666.     BEGIN
  667.         s:=LowerCase(TrimL(TrimR(s)));      { Tidy up input string }
  668.         IF TimeParseNow AND (LENGTH(s)=0) THEN
  669.             BEGIN
  670.                 GetTimeNow(Tm);             { Return current time if }
  671.                 TimeParse:=TRUE;            { null input and allowed }
  672.                 EXIT;
  673.             END;
  674.         s1:=Break(s,'ap');                  { Remove all up to a.m./p.m. }
  675.         IF LENGTH(s)=0 THEN
  676.             i:=none                         { Set a.m./p.m. indicator }
  677.         ELSE
  678.             CASE s[1] OF
  679.                 'a':    i:=am;
  680.                 'p':    i:=pm;
  681.             END;
  682.         s:=Break(s1,TimeParseDelims);       { Strip hours field from string }
  683.         VAL(s,Tm.H,x);
  684.         IF x<>0 THEN                        { If failed, force an error }
  685.             Tm.H:=24;
  686.         DELETE(s1,1,1);                     { Remove hh/mm delim. from input }
  687.         s:=Span(s1,blanks);                 { Remove any extra blanks }
  688.         s:=Break(s1,TimeParseDelims);       { Strip minutes field }
  689.         VAL(s,Tm.M,x);
  690.         IF x<>0 THEN                        { Force error if conv. failed }
  691.             Tm.M:=60;
  692.         DELETE(s1,1,1);             { Remove delim from input, strip blanks }
  693.         s:=Span(s1,blanks);
  694.         IF LENGTH(s1)=0 THEN        { If no other field, assume seconds=0 }
  695.             Tm.S:=0
  696.         ELSE
  697.             BEGIN
  698.                 VAL(TrimR(s1),Tm.S,x);  { Otherwise convert last field }
  699.                 IF x<>0 THEN
  700.                     Tm.S:=60;           { Force error if conversion failed }
  701.             END;
  702.         IF TimeValid(Tm) AND (i<>none) THEN
  703.             WITH Tm DO                  { If successful & a.m./p.m. specified }
  704.                 IF (H<1) OR (H>12) THEN { Force error if hours out of range }
  705.                     H:=24
  706.                 ELSE                    { Otherwise, adjust hours field }
  707.                     CASE i OF
  708.                         am: IF H=12 THEN
  709.                                 H:=0;
  710.                         pm: IF H<12 THEN
  711.                                 H:=H+12;
  712.                     END;
  713.         TimeParse:=TimeValid(Tm);       { Do final validation }
  714.     END;  { TimeParse }
  715.  
  716.  
  717.  
  718. BEGIN   { Initialization code }
  719.     SetCountry;
  720.     IF BritishFormat THEN
  721.         BEGIN
  722.             DateDelimiter:='-';
  723.             TimeDelimiter:='.';
  724.         END;
  725. END.
  726.  
  727.