home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 September
/
Chip_2001-09_cd1.bin
/
zkuste
/
delphi
/
kolekce
/
d6
/
RX275D6.ZIP
/
Units
/
DATEUTIL.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
2001-06-24
|
17KB
|
632 lines
{*******************************************************}
{ }
{ Delphi VCL Extensions (RX) }
{ }
{ Copyright (c) 1995, 1996 AO ROSNO }
{ Copyright (c) 1997, 1998 Master-Bank }
{ }
{*******************************************************}
unit DateUtil;
{$I RX.INC}
{$B-,V-,R-,Q-}
interface
uses RTLConsts;
function CurrentYear: Word;
function IsLeapYear(AYear: Integer): Boolean;
function DaysPerMonth(AYear, AMonth: Integer): Integer;
function FirstDayOfPrevMonth: TDateTime;
function LastDayOfPrevMonth: TDateTime;
function FirstDayOfNextMonth: TDateTime;
function ExtractDay(ADate: TDateTime): Word;
function ExtractMonth(ADate: TDateTime): Word;
function ExtractYear(ADate: TDateTime): Word;
function IncDate(ADate: TDateTime; Days, Months, Years: Integer): TDateTime;
function IncDay(ADate: TDateTime; Delta: Integer): TDateTime;
function IncMonth(ADate: TDateTime; Delta: Integer): TDateTime;
function IncYear(ADate: TDateTime; Delta: Integer): TDateTime;
function ValidDate(ADate: TDateTime): Boolean;
procedure DateDiff(Date1, Date2: TDateTime; var Days, Months, Years: Word);
function MonthsBetween(Date1, Date2: TDateTime): Double;
function DaysInPeriod(Date1, Date2: TDateTime): Longint;
{ Count days between Date1 and Date2 + 1, so if Date1 = Date2 result = 1 }
function DaysBetween(Date1, Date2: TDateTime): Longint;
{ The same as previous but if Date2 < Date1 result = 0 }
function IncTime(ATime: TDateTime; Hours, Minutes, Seconds, MSecs: Integer): TDateTime;
function IncHour(ATime: TDateTime; Delta: Integer): TDateTime;
function IncMinute(ATime: TDateTime; Delta: Integer): TDateTime;
function IncSecond(ATime: TDateTime; Delta: Integer): TDateTime;
function IncMSec(ATime: TDateTime; Delta: Integer): TDateTime;
function CutTime(ADate: TDateTime): TDateTime; { Set time to 00:00:00:00 }
type
TDateOrder = (doMDY, doDMY, doYMD);
TDayOfWeekName = (Sun, Mon, Tue, Wed, Thu, Fri, Sat);
TDaysOfWeek = set of TDayOfWeekName;
{ String to date conversions }
function GetDateOrder(const DateFormat: string): TDateOrder;
function MonthFromName(const S: string; MaxLen: Byte): Byte;
function StrToDateDef(const S: string; Default: TDateTime): TDateTime;
function StrToDateFmt(const DateFormat, S: string): TDateTime;
function StrToDateFmtDef(const DateFormat, S: string; Default: TDateTime): TDateTime;
function DefDateFormat(FourDigitYear: Boolean): string;
function DefDateMask(BlanksChar: Char; FourDigitYear: Boolean): string;
{$IFDEF WIN32}
function FormatLongDate(Value: TDateTime): string;
function FormatLongDateTime(Value: TDateTime): string;
{$ENDIF}
const
DefaultDateOrder = doDMY;
{$IFDEF USE_FOUR_DIGIT_YEAR}
var
FourDigitYear: Boolean;
{$ELSE}
function FourDigitYear: Boolean;
{$ENDIF USE_FOUR_DIGIT_YEAR}
const
CenturyOffset: Byte = 60;
{$IFDEF WIN32}
NullDate: TDateTime = {-693594} 0;
{$ELSE}
NullDate: TDateTime = 0;
{$ENDIF}
implementation
uses SysUtils, {$IFDEF WIN32} Windows, {$ENDIF} Consts, rxStrUtils;
function IsLeapYear(AYear: Integer): Boolean;
begin
Result := (AYear mod 4 = 0) and ((AYear mod 100 <> 0) or (AYear mod 400 = 0));
end;
function DaysPerMonth(AYear, AMonth: Integer): Integer;
const
DaysInMonth: array[1..12] of Integer =
(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
begin
Result := DaysInMonth[AMonth];
if (AMonth = 2) and IsLeapYear(AYear) then Inc(Result); { leap-year Feb is special }
end;
function FirstDayOfNextMonth: TDateTime;
var
Year, Month, Day: Word;
begin
DecodeDate(Date, Year, Month, Day);
Day := 1;
if Month < 12 then Inc(Month)
else begin
Inc(Year);
Month := 1;
end;
Result := EncodeDate(Year, Month, Day);
end;
function FirstDayOfPrevMonth: TDateTime;
var
Year, Month, Day: Word;
begin
DecodeDate(Date, Year, Month, Day);
Day := 1;
if Month > 1 then Dec(Month)
else begin
Dec(Year);
Month := 12;
end;
Result := EncodeDate(Year, Month, Day);
end;
function LastDayOfPrevMonth: TDateTime;
var
D: TDateTime;
Year, Month, Day: Word;
begin
D := FirstDayOfPrevMonth;
DecodeDate(D, Year, Month, Day);
Day := DaysPerMonth(Year, Month);
Result := EncodeDate(Year, Month, Day);
end;
function ExtractDay(ADate: TDateTime): Word;
var
M, Y: Word;
begin
DecodeDate(ADate, Y, M, Result);
end;
function ExtractMonth(ADate: TDateTime): Word;
var
D, Y: Word;
begin
DecodeDate(ADate, Y, Result, D);
end;
function ExtractYear(ADate: TDateTime): Word;
var
D, M: Word;
begin
DecodeDate(ADate, Result, M, D);
end;
function IncDate(ADate: TDateTime; Days, Months, Years: Integer): TDateTime;
var
D, M, Y: Word;
Day, Month, Year: Longint;
begin
DecodeDate(ADate, Y, M, D);
Year := Y; Month := M; Day := D;
Inc(Year, Years);
Inc(Year, Months div 12);
Inc(Month, Months mod 12);
if Month < 1 then begin
Inc(Month, 12);
Dec(Year);
end
else if Month > 12 then begin
Dec(Month, 12);
Inc(Year);
end;
if Day > DaysPerMonth(Year, Month) then Day := DaysPerMonth(Year, Month);
Result := EncodeDate(Year, Month, Day) + Days + Frac(ADate);
end;
procedure DateDiff(Date1, Date2: TDateTime; var Days, Months, Years: Word);
{ Corrected by Anatoly A. Sanko (2:450/73) }
var
DtSwap: TDateTime;
Day1, Day2, Month1, Month2, Year1, Year2: Word;
begin
if Date1 > Date2 then begin
DtSwap := Date1;
Date1 := Date2;
Date2 := DtSwap;
end;
DecodeDate(Date1, Year1, Month1, Day1);
DecodeDate(Date2, Year2, Month2, Day2);
Years := Year2 - Year1;
Months := 0;
Days := 0;
if Month2 < Month1 then begin
Inc(Months, 12);
Dec(Years);
end;
Inc(Months, Month2 - Month1);
if Day2 < Day1 then begin
Inc(Days, DaysPerMonth(Year1, Month1));
if Months = 0 then begin
Dec(Years);
Months := 11;
end
else Dec(Months);
end;
Inc(Days, Day2 - Day1);
end;
function IncDay(ADate: TDateTime; Delta: Integer): TDateTime;
begin
Result := ADate + Delta;
end;
function IncMonth(ADate: TDateTime; Delta: Integer): TDateTime;
begin
Result := IncDate(ADate, 0, Delta, 0);
end;
function IncYear(ADate: TDateTime; Delta: Integer): TDateTime;
begin
Result := IncDate(ADate, 0, 0, Delta);
end;
function MonthsBetween(Date1, Date2: TDateTime): Double;
var
D, M, Y: Word;
begin
DateDiff(Date1, Date2, D, M, Y);
Result := 12 * Y + M;
if (D > 1) and (D < 7) then Result := Result + 0.25
else if (D >= 7) and (D < 15) then Result := Result + 0.5
else if (D >= 15) and (D < 21) then Result := Result + 0.75
else if (D >= 21) then Result := Result + 1;
end;
function IsValidDate(Y, M, D: Word): Boolean;
begin
Result := (Y >= 1) and (Y <= 9999) and (M >= 1) and (M <= 12) and
(D >= 1) and (D <= DaysPerMonth(Y, M));
end;
function ValidDate(ADate: TDateTime): Boolean;
var
Year, Month, Day: Word;
begin
try
DecodeDate(ADate, Year, Month, Day);
Result := IsValidDate(Year, Month, Day);
except
Result := False;
end;
end;
function DaysInPeriod(Date1, Date2: TDateTime): Longint;
begin
if ValidDate(Date1) and ValidDate(Date2) then
Result := Abs(Trunc(Date2) - Trunc(Date1)) + 1
else Result := 0;
end;
function DaysBetween(Date1, Date2: TDateTime): Longint;
begin
Result := Trunc(Date2) - Trunc(Date1) + 1;
if Result < 0 then Result := 0;
end;
function IncTime(ATime: TDateTime; Hours, Minutes, Seconds,
MSecs: Integer): TDateTime;
begin
Result := ATime + (Hours div 24) + (((Hours mod 24) * 3600000 +
Minutes * 60000 + Seconds * 1000 + MSecs) / MSecsPerDay);
if Result < 0 then Result := Result + 1;
end;
function IncHour(ATime: TDateTime; Delta: Integer): TDateTime;
begin
Result := IncTime(ATime, Delta, 0, 0, 0);
end;
function IncMinute(ATime: TDateTime; Delta: Integer): TDateTime;
begin
Result := IncTime(ATime, 0, Delta, 0, 0);
end;
function IncSecond(ATime: TDateTime; Delta: Integer): TDateTime;
begin
Result := IncTime(ATime, 0, 0, Delta, 0);
end;
function IncMSec(ATime: TDateTime; Delta: Integer): TDateTime;
begin
Result := IncTime(ATime, 0, 0, 0, Delta);
end;
function CutTime(ADate: TDateTime): TDateTime;
begin
Result := Trunc(ADate);
end;
function CurrentYear: Word; {$IFNDEF WIN32} assembler; {$ENDIF}
{$IFDEF WIN32}
var
SystemTime: TSystemTime;
begin
GetLocalTime(SystemTime);
Result := SystemTime.wYear;
end;
{$ELSE}
asm
MOV AH,2AH
INT 21H
MOV AX,CX
end;
{$ENDIF}
{ String to date conversions. Copied from SYSUTILS.PAS unit. }
procedure ScanBlanks(const S: string; var Pos: Integer);
var
I: Integer;
begin
I := Pos;
while (I <= Length(S)) and (S[I] = ' ') do Inc(I);
Pos := I;
end;
function ScanNumber(const S: string; MaxLength: Integer; var Pos: Integer;
var Number: Longint): Boolean;
var
I: Integer;
N: Word;
begin
Result := False;
ScanBlanks(S, Pos);
I := Pos;
N := 0;
while (I <= Length(S)) and (Longint(I - Pos) < MaxLength) and
(S[I] in ['0'..'9']) and (N < 1000) do
begin
N := N * 10 + (Ord(S[I]) - Ord('0'));
Inc(I);
end;
if I > Pos then begin
Pos := I;
Number := N;
Result := True;
end;
end;
function ScanChar(const S: string; var Pos: Integer; Ch: Char): Boolean;
begin
Result := False;
ScanBlanks(S, Pos);
if (Pos <= Length(S)) and (S[Pos] = Ch) then begin
Inc(Pos);
Result := True;
end;
end;
{$IFDEF RX_D3}
procedure ScanToNumber(const S: string; var Pos: Integer);
begin
while (Pos <= Length(S)) and not (S[Pos] in ['0'..'9']) do begin
if S[Pos] in LeadBytes then Inc(Pos);
Inc(Pos);
end;
end;
{$ENDIF}
function GetDateOrder(const DateFormat: string): TDateOrder;
var
I: Integer;
begin
Result := DefaultDateOrder;
I := 1;
while I <= Length(DateFormat) do begin
case Chr(Ord(DateFormat[I]) and $DF) of
{$IFDEF RX_D3}
'E': Result := doYMD;
{$ENDIF}
'Y': Result := doYMD;
'M': Result := doMDY;
'D': Result := doDMY;
else
Inc(I);
Continue;
end;
Exit;
end;
Result := DefaultDateOrder; { default }
end;
function ExpandYear(Year: Integer): Integer;
var
N: Longint;
begin
Result := Year;
if Result < 100 then begin
N := CurrentYear - CenturyOffset;
Inc(Result, N div 100 * 100);
if (CenturyOffset > 0) and (Result < N) then
Inc(Result, 100);
end;
end;
function ScanDate(const S, DateFormat: string; var Pos: Integer;
var Y, M, D: Integer): Boolean;
var
DateOrder: TDateOrder;
N1, N2, N3: Longint;
begin
Result := False;
Y := 0; M := 0; D := 0;
DateOrder := GetDateOrder(DateFormat);
{$IFDEF RX_D3}
if ShortDateFormat[1] = 'g' then { skip over prefix text }
ScanToNumber(S, Pos);
{$ENDIF RX_D3}
if not (ScanNumber(S, MaxInt, Pos, N1) and ScanChar(S, Pos, DateSeparator) and
ScanNumber(S, MaxInt, Pos, N2)) then Exit;
if ScanChar(S, Pos, DateSeparator) then begin
if not ScanNumber(S, MaxInt, Pos, N3) then Exit;
case DateOrder of
doMDY: begin Y := N3; M := N1; D := N2; end;
doDMY: begin Y := N3; M := N2; D := N1; end;
doYMD: begin Y := N1; M := N2; D := N3; end;
end;
Y := ExpandYear(Y);
end
else begin
Y := CurrentYear;
if DateOrder = doDMY then begin
D := N1; M := N2;
end
else begin
M := N1; D := N2;
end;
end;
ScanChar(S, Pos, DateSeparator);
ScanBlanks(S, Pos);
{$IFDEF RX_D3}
if SysLocale.FarEast and (System.Pos('ddd', ShortDateFormat) <> 0) then
begin { ignore trailing text }
if ShortTimeFormat[1] in ['0'..'9'] then { stop at time digit }
ScanToNumber(S, Pos)
else { stop at time prefix }
repeat
while (Pos <= Length(S)) and (S[Pos] <> ' ') do Inc(Pos);
ScanBlanks(S, Pos);
until (Pos > Length(S)) or
(AnsiCompareText(TimeAMString, Copy(S, Pos, Length(TimeAMString))) = 0) or
(AnsiCompareText(TimePMString, Copy(S, Pos, Length(TimePMString))) = 0);
end;
{$ENDIF RX_D3}
Result := IsValidDate(Y, M, D) and (Pos > Length(S));
end;
function MonthFromName(const S: string; MaxLen: Byte): Byte;
begin
if Length(S) > 0 then
for Result := 1 to 12 do begin
if (Length(LongMonthNames[Result]) > 0) and
(AnsiCompareText(Copy(S, 1, MaxLen),
Copy(LongMonthNames[Result], 1, MaxLen)) = 0) then Exit;
end;
Result := 0;
end;
procedure ExtractMask(const Format, S: string; Ch: Char; Cnt: Integer;
var I: Integer; Blank, Default: Integer);
var
Tmp: string[20];
J, L: Integer;
begin
I := Default;
Ch := UpCase(Ch);
L := Length(Format);
if Length(S) < L then L := Length(S)
else if Length(S) > L then Exit;
J := Pos(MakeStr(Ch, Cnt), AnsiUpperCase(Format));
if J <= 0 then Exit;
Tmp := '';
while (UpCase(Format[J]) = Ch) and (J <= L) do begin
if S[J] <> ' ' then Tmp := Tmp + S[J];
Inc(J);
end;
if Tmp = '' then I := Blank
else if Cnt > 1 then begin
I := MonthFromName(Tmp, Length(Tmp));
if I = 0 then I := -1;
end
else I := StrToIntDef(Tmp, -1);
end;
function ScanDateStr(const Format, S: string; var D, M, Y: Integer): Boolean;
var
Pos: Integer;
begin
ExtractMask(Format, S, 'm', 3, M, -1, 0); { short month name? }
if M = 0 then ExtractMask(Format, S, 'm', 1, M, -1, 0);
ExtractMask(Format, S, 'd', 1, D, -1, 1);
ExtractMask(Format, S, 'y', 1, Y, -1, CurrentYear);
Y := ExpandYear(Y);
Result := IsValidDate(Y, M, D);
if not Result then begin
Pos := 1;
Result := ScanDate(S, Format, Pos, Y, M, D);
end;
end;
function InternalStrToDate(const DateFormat, S: string;
var Date: TDateTime): Boolean;
var
D, M, Y: Integer;
begin
if S = '' then begin
Date := NullDate;
Result := True;
end
else begin
Result := ScanDateStr(DateFormat, S, D, M, Y);
if Result then
try
Date := EncodeDate(Y, M, D);
except
Result := False;
end;
end;
end;
function StrToDateFmt(const DateFormat, S: string): TDateTime;
begin
if not InternalStrToDate(DateFormat, S, Result) then
raise EConvertError.CreateFmt({$IFDEF RX_D3} SInvalidDate {$ELSE}
LoadStr(SInvalidDate) {$ENDIF}, [S]);
end;
function StrToDateDef(const S: string; Default: TDateTime): TDateTime;
begin
if not InternalStrToDate(ShortDateFormat, S, Result) then
Result := Trunc(Default);
end;
function StrToDateFmtDef(const DateFormat, S: string; Default: TDateTime): TDateTime;
begin
if not InternalStrToDate(DateFormat, S, Result) then
Result := Trunc(Default);
end;
function DefDateFormat(FourDigitYear: Boolean): string;
begin
if FourDigitYear then begin
case GetDateOrder(ShortDateFormat) of
doMDY: Result := 'MM/DD/YYYY';
doDMY: Result := 'DD/MM/YYYY';
doYMD: Result := 'YYYY/MM/DD';
end;
end
else begin
case GetDateOrder(ShortDateFormat) of
doMDY: Result := 'MM/DD/YY';
doDMY: Result := 'DD/MM/YY';
doYMD: Result := 'YY/MM/DD';
end;
end;
end;
function DefDateMask(BlanksChar: Char; FourDigitYear: Boolean): string;
begin
if FourDigitYear then begin
case GetDateOrder(ShortDateFormat) of
doMDY, doDMY: Result := '!99/99/9999;1;';
doYMD: Result := '!9999/99/99;1;';
end;
end
else begin
case GetDateOrder(ShortDateFormat) of
doMDY, doDMY: Result := '!99/99/99;1;';
doYMD: Result := '!99/99/99;1;';
end;
end;
if Result <> '' then Result := Result + BlanksChar;
end;
{$IFDEF WIN32}
function FormatLongDate(Value: TDateTime): string;
var
Buffer: array[0..1023] of Char;
SystemTime: TSystemTime;
begin
{$IFDEF RX_D3}
DateTimeToSystemTime(Value, SystemTime);
{$ELSE}
with SystemTime do begin
DecodeDate(Value, wYear, wMonth, wDay);
DecodeTime(Value, wHour, wMinute, wSecond, wMilliseconds);
end;
{$ENDIF}
SetString(Result, Buffer, GetDateFormat(GetThreadLocale, DATE_LONGDATE,
@SystemTime, nil, Buffer, SizeOf(Buffer) - 1));
Result := TrimRight(Result);
end;
function FormatLongDateTime(Value: TDateTime): string;
begin
if Value <> NullDate then
Result := FormatLongDate(Value) + FormatDateTime(' tt', Value)
else Result := '';
end;
{$ENDIF WIN32}
{$IFNDEF USE_FOUR_DIGIT_YEAR}
function FourDigitYear: Boolean;
begin
Result := Pos('YYYY', AnsiUpperCase(ShortDateFormat)) > 0;
end;
{$ENDIF}
{$IFDEF USE_FOUR_DIGIT_YEAR}
initialization
FourDigitYear := Pos('YYYY', AnsiUpperCase(ShortDateFormat)) > 0;
{$ENDIF}
end.