2 *********************************************************************
4 Copyright (C) 1997, 1998 Gertjan Schouten
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *********************************************************************
21 System Utilities For Free Pascal
24 {==============================================================================}
25 { internal functions }
26 {==============================================================================}
29 DayTable: array[Boolean, 1..12] of longint =
30 ((0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334),
31 (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335));
33 function DoEncodeDate(Year, Month, Day: Word): longint;
37 if (Month > 0) and (Month < 13) and (Day > 0) and (Day < 32) then
48 result := (146097*c) SHR 2 + (1461*ya) SHR 2 + (153*cardinal(Month)+2) DIV 5 + cardinal(Day) - 693900;
54 function DoEncodeTime(Hour, Minute, Second, MilliSecond: word): longint;
56 If ((hour>=0) and (Hour<24)) and
57 ((Minute>=0) and (Minute<60)) and
58 ((Second>=0) and (Second<60)) and
59 ((MilliSecond>=0) and (Millisecond<1000)) then
60 Result := (Hour * 3600000 + Minute * 60000 + Second * 1000 + MilliSecond)
66 {==============================================================================}
68 {==============================================================================}
70 { DateTimeToTimeStamp converts DateTime to a TTimeStamp }
72 function DateTimeToTimeStamp(DateTime: TDateTime): TTimeStamp;
74 result.Time := Trunc(Frac(DateTime) * MSecsPerDay);
75 result.Date := 1 + DateDelta + Trunc(System.Int(DateTime));
78 { TimeStampToDateTime converts TimeStamp to a TDateTime value }
80 function TimeStampToDateTime(const TimeStamp: TTimeStamp): TDateTime;
82 result := (TimeStamp.Date - DateDelta - 1) + (TimeStamp.Time / MSecsPerDay);
87 function MSecsToTimeStamp(MSecs: comp): TTimeStamp;
89 result.Date := Round(msecs / msecsperday);
90 msecs:= comp(msecs-result.date*msecsperday);
91 result.Time := Round(MSecs);
96 function TimeStampToMSecs(const TimeStamp: TTimeStamp): comp;
98 result := TimeStamp.Time + timestamp.date*msecsperday;
101 { EncodeDate packs three variables Year, Month and Day into a
102 TDateTime value the result is the number of days since 12/30/1899 }
104 function EncodeDate(Year, Month, Day: word): TDateTime;
106 result := DoEncodeDate(Year, Month, Day);
109 { EncodeTime packs four variables Hour, Minute, Second and MilliSecond into
112 function EncodeTime(Hour, Minute, Second, MilliSecond:word):TDateTime;
114 Result := DoEncodeTime(hour, minute, second, millisecond) / MSecsPerDay;
117 { DecodeDate unpacks the value Date into three values:
118 Year, Month and Day }
120 procedure DecodeDate(Date: TDateTime; var Year, Month, Day: word);
124 j := pred((Trunc(System.Int(Date)) + 693900) SHL 2);
126 j:= j - 146097 * cardinal(Year);
128 j:=(Day SHL 2 + 3) DIV 1461;
129 Day:= (cardinal(Day) SHL 2 + 7 - 1461*j) SHR 2;
130 Month:=(5 * Day-3) DIV 153;
131 Day:= (5 * Day +2 - 153*Month) DIV 5;
132 Year:= 100 * cardinal(Year) + j;
142 { DecodeTime unpacks Time into four values:
143 Hour, Minute, Second and MilliSecond }
145 procedure DecodeTime(Time: TDateTime; var Hour, Minute, Second, MilliSecond: word);
149 l := Round(Frac(time) * MSecsPerDay);
150 Hour := l div 3600000;
152 Minute := l div 60000;
154 Second := l div 1000;
159 { DateTimeToSystemTime converts DateTime value to SystemTime }
161 procedure DateTimeToSystemTime(DateTime: TDateTime; var SystemTime: TSystemTime);
163 DecodeDate(DateTime, SystemTime.Year, SystemTime.Month, SystemTime.Day);
164 DecodeTime(DateTime, SystemTime.Hour, SystemTime.Minute, SystemTime.Second, SystemTime.MilliSecond);
167 { SystemTimeToDateTime converts SystemTime to a TDateTime value }
169 function SystemTimeToDateTime(const SystemTime: TSystemTime): TDateTime;
171 result := DoEncodeDate(SystemTime.Year, SystemTime.Month, SystemTime.Day) +
172 DoEncodeTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second, SystemTime.MilliSecond) / MSecsPerDay;
175 { DayOfWeek returns the Day of the week (sunday is day 1) }
177 function DayOfWeek(DateTime: TDateTime): integer;
179 Result := 1 + (Abs(Trunc(DateTime) - 1) mod 7);
182 { Date returns the current Date }
184 function Date: TDateTime;
186 SystemTime: TSystemTime;
188 GetLocalTime(SystemTime);
189 result := DoEncodeDate(SystemTime.Year, SystemTime.Month, SystemTime.Day);
192 { Time returns the current Time }
194 function Time: TDateTime;
196 SystemTime: TSystemTime;
198 GetLocalTime(SystemTime);
199 Result := DoEncodeTime(SystemTime.Hour,SystemTime.Minute,SystemTime.Second,SystemTime.MilliSecond) / MSecsPerDay;
202 { Now returns the current Date and Time }
204 function Now: TDateTime;
206 SystemTime: TSystemTime;
208 GetLocalTime(SystemTime);
209 result := DoEncodeDate(SystemTime.Year,SystemTime.Month,SystemTime.Day) +
210 DoEncodeTime(SystemTime.Hour,SystemTime.Minute,SystemTime.Second,SystemTime.MilliSecond) / MSecsPerDay;
213 { IncMonth increments DateTime with NumberOfMonths months,
214 NumberOfMonths can be less than zero }
216 function IncMonth(const DateTime: TDateTime; NumberOfMonths: integer): TDateTime;
218 Year, Month, Day: word;
221 If NumberOfMonths>=0 then
225 DecodeDate(DateTime, Year, Month, Day);
226 inc(Year,(NumberOfMonths div 12));
227 inc(Month,(NumberOfMonths mod 12)-1); // Mod result always positive
233 Inc(Month); { Months from 1 to 12 }
234 if (Month = 2) and (IsLeapYear(Year)) and (Day > 28) then
236 result := Frac(DateTime) + DoEncodeDate(Year, Month, Day);
239 { IsLeapYear returns true if Year is a leap year }
241 function IsLeapYear(Year: Word): boolean;
243 Result := (Year mod 4 = 0) and ((Year mod 100 <> 0) or (Year mod 400 = 0));
246 { DateToStr returns a string representation of Date using ShortDateFormat }
248 function DateToStr(Date: TDateTime): string;
250 result := FormatDateTime('ddddd', Date);
253 { TimeToStr returns a string representation of Time using ShortTimeFormat }
255 function TimeToStr(Time: TDateTime): string;
257 result := FormatDateTime('t', Time);
260 { DateTimeToStr returns a string representation of DateTime using ShortDateTimeFormat }
262 function DateTimeToStr(DateTime: TDateTime): string;
264 result := FormatDateTime('c', DateTime);
267 { StrToDate converts the string S to a TDateTime value
268 if S does not represent a valid date value
269 an EConvertError will be raised }
271 function StrToDate(const S: string): TDateTime;
277 dp,mp,yp,which : Byte;
279 values:array[1..3] of longint;
280 LocalTime:tsystemtime;
282 df := UpperCase(ShortDateFormat);
283 { Determine order of D,M,Y }
289 while (i<Length(df)) and (Which<3) do
314 Raise EConvertError.Create('Illegal format string');
315 { Get actual values }
320 for i := 1 to length(s) do
322 if (s[i] in ['0'..'9']) then
324 if (s[i] in [dateseparator,' ']) or (i = length(s)) then
328 Raise EConvertError.Create('Invalid date format');
329 val(s1, values[n], c);
331 Raise EConvertError.Create('Invalid date format');
344 getLocalTime(LocalTime);
349 m := LocalTime.Month;
363 if (y >= 0) and (y < 100) then
365 Result := DoEncodeDate(y, m, d);
369 { StrToTime converts the string S to a TDateTime value
370 if S does not represent a valid time value an
371 EConvertError will be raised }
373 function StrToTime(const s: string): TDateTime;
375 Len, Current: integer; PM: boolean;
377 function GetElement: integer;
383 while (result = -1) and (Current < Len) do begin
384 if S[Current] in ['0'..'9'] then begin
386 while (Current < Len) and (s[Current + 1] in ['0'..'9']) do
388 val(copy(S, j, 1 + Current - j), result, c);
390 else if (S[Current] = TimeAMString[1]) or (S[Current] in ['a', 'A']) then begin
393 else if (S[Current] = TimePMString[1]) or (S[Current] in ['p', 'P']) then begin
397 else if (S[Current] = TimeSeparator) or (S[Current] = ' ') then
400 raise EConvertError.Create('Invalid Time format');
406 TimeValues: array[0..4] of integer;
415 TimeValues[i] := GetElement;
416 while (i < 5) and (TimeValues[i] <> -1) do begin
418 TimeValues[i] := GetElement;
420 If (i<5) and (TimeValues[I]=-1) then
422 if PM then Inc(TimeValues[0], 12);
423 result := EncodeTime(TimeValues[0], TimeValues[1], TimeValues[2], TimeValues[3]);
426 { StrToDateTime converts the string S to a TDateTime value
427 if S does not represent a valid date and time value
428 an EConvertError will be raised }
430 function StrToDateTime(const s: string): TDateTime;
434 if i > 0 then result := StrToDate(Copy(S, 1, i - 1)) + StrToTime(Copy(S, i + 1, length(S)))
435 else result := StrToDate(S);
438 { FormatDateTime formats DateTime to the given format string FormatStr }
440 function FormatDateTime(FormatStr: string; DateTime: TDateTime): string;
443 ResultBuffer: array[0..255] of char;
444 ResultCurrent: pchar;
446 procedure StoreStr(Str: pchar; Len: integer);
448 if ResultLen + Len < SizeOf(ResultBuffer) then begin
449 StrMove(ResultCurrent, Str, Len);
450 ResultCurrent := ResultCurrent + Len;
451 ResultLen := ResultLen + Len;
455 procedure StoreString(const Str: string);
459 if ResultLen + Len < SizeOf(ResultBuffer) then begin
460 StrMove(ResultCurrent, pchar(Str), Len);
461 ResultCurrent := ResultCurrent + Len;
462 ResultLen := ResultLen + Len;
466 procedure StoreInt(Value, Digits: integer);
467 var S: string; Len: integer;
469 S := IntToStr(Value);
471 if Len < Digits then begin
472 S := copy('0000', 1, Digits - Len) + S;
475 StoreStr(pchar(@S[1]), Len);
478 Function TimeReFormat(Const S : string) : string;
479 // Change m into n for time formatting.
484 For I:=1 to Length(Result) do
485 If Result[i]='m' then
490 Year, Month, Day, DayOfWeek, Hour, Minute, Second, MilliSecond: word;
492 procedure StoreFormat(const FormatStr: string);
495 FormatCurrent: pchar;
502 FormatCurrent := Pchar(FormatStr);
503 FormatEnd := FormatCurrent + Length(FormatStr);
506 while P < FormatEnd do begin
508 if Token in ['"', ''''] then begin
510 while (P < FormatEnd) and (P^ <> Token) do
513 else if Token = 'A' then begin
514 if (StrLIComp(P, 'A/P', 3) = 0) or
515 (StrLIComp(P, 'AMPM', 4) = 0) or
516 (StrLIComp(P, 'AM/PM', 5) = 0) then begin
523 while FormatCurrent < FormatEnd do begin
524 Token := UpCase(FormatCurrent^);
526 P := FormatCurrent + 1;
529 while (P < FormatEnd) and (p^ <> Token) do
532 Count := P - FormatCurrent;
533 StoreStr(FormatCurrent + 1, Count - 2);
536 if StrLIComp(FormatCurrent, 'AMPM', 4) = 0 then begin
538 if Hour < 12 then StoreString(TimeAMString)
539 else StoreString(TimePMString);
541 else if StrLIComp(FormatCurrent, 'AM/PM', 5) = 0 then begin
543 if Hour < 12 then StoreStr('am', 2)
544 else StoreStr('pm', 2);
546 else if StrLIComp(FormatCurrent, 'A/P', 3) = 0 then begin
548 if Hour < 12 then StoreStr('a', 1)
549 else StoreStr('p', 1);
552 Raise EConvertError.Create('Illegal character in format string');
554 '/': StoreStr(@DateSeparator, 1);
555 ':': StoreStr(@TimeSeparator, 1);
556 ' ', 'C', 'D', 'H', 'M', 'N', 'S', 'T', 'Y': begin
557 while (P < FormatEnd) and (UpCase(P^) = Token) do
559 Count := P - FormatCurrent;
561 ' ': StoreStr(FormatCurrent, Count);
564 1: StoreInt(Year, 0);
565 2: StoreInt(Year mod 100, 2);
566 4: StoreInt(Year, 4);
571 1: StoreInt(Month, 0);
572 2: StoreInt(Month, 2);
573 3: StoreString(ShortMonthNames[Month]);
574 4: StoreString(LongMonthNames[Month]);
581 3: StoreString(ShortDayNames[DayOfWeek]);
582 4: StoreString(LongDayNames[DayOfWeek]);
583 5: StoreFormat(ShortDateFormat);
584 6: StoreFormat(LongDateFormat);
588 if Clock12 then begin
589 if Count = 1 then StoreInt(Hour mod 12, 0)
590 else StoreInt(Hour mod 12, 2);
593 if Count = 1 then StoreInt(Hour, 0)
594 else StoreInt(Hour, 2);
598 if Count = 1 then StoreInt(Minute, 0)
599 else StoreInt(Minute, 2);
602 if Count = 1 then StoreInt(Second, 0)
603 else StoreInt(Second, 2);
606 if Count = 1 then StoreFormat(timereformat(ShortTimeFormat))
607 else StoreFormat(TimeReformat(LongTimeFormat));
611 StoreFormat(ShortDateFormat);
612 if (Hour<>0) or (Minute<>0) or (Second<>0) then
615 StoreFormat(TimeReformat(ShortTimeFormat));
623 FormatCurrent := FormatCurrent + Count;
628 DecodeDate(DateTime, Year, Month, Day);
629 DecodeTime(DateTime, Hour, Minute, Second, MilliSecond);
630 DayOfWeek := SysUtils.DayOfWeek(DateTime);
632 ResultCurrent := @ResultBuffer;
633 StoreFormat(FormatStr);
634 ResultBuffer[ResultLen] := #0;
635 result := StrPas(@ResultBuffer);
638 { DateTimeToString formats DateTime to the given format in FormatStr }
640 procedure DateTimeToString(var Result: string; const FormatStr: string; const DateTime: TDateTime);
642 Result := FormatDateTime(FormatStr, DateTime);
646 Function DateTimeToFileDate(DateTime : TDateTime) : Longint;
648 Var YY,MM,DD,H,m,s,msec : Word;
651 Decodedate (DateTime,YY,MM,DD);
652 If (YY<1980) or (YY>2099) then
656 DecodeTime (DateTime,h,m,s,msec);
657 Result:=(s shr 1) or (m shl 5) or (h shl 11);
658 Result:=Result or DD shl 16 or (MM shl 21) or ((YY-1980) shl 25);
663 Function FileDateToDateTime (Filedate : Longint) : TDateTime;
665 Var Date,Time : Word;
668 Date:=FileDate shr 16;
669 Time:=FileDate and $ffff;
670 Result:=EncodeDate((Date shr 9) + 1980,(Date shr 5) and 15, Date and 31) +
671 EncodeTime(Time shr 11, (Time shr 5) and 63, (Time and 31) shl 1,0);
676 Revision 1.1 2002/02/19 08:25:44 sasu
679 Revision 1.1.2.1 2000/12/16 15:57:15 jonas
680 * removed 64bit evaluations when range checking is on
682 Revision 1.1 2000/07/13 06:30:58 michael
685 Revision 1.22 2000/06/18 18:02:54 peter
686 * fixed decodetime which used trunc instead of round
688 Revision 1.21 2000/02/27 14:41:25 peter
689 * removed warnings/notes
691 Revision 1.20 2000/02/09 16:59:32 peter
694 Revision 1.19 1999/11/29 16:59:27 pierre
695 * fix for form bug 719
697 Revision 1.18 1999/11/06 14:41:30 peter
700 Revision 1.17 1999/10/28 09:52:29 peter
703 Revision 1.16 1999/08/11 21:53:04 peter
704 * fixed formatdatetime('c',...)
706 * dateencode/decode is now delphi compatible
708 Revision 1.15 1999/07/24 11:21:14 peter
709 * fixed encode/decode date/time