📄 jvdateutil.pas
字号:
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 COMPILER3_UP}
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 COMPILER3_UP}
'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 CurrentMonth: Word;
var
SystemTime: TSystemTime;
begin
GetLocalTime(SystemTime);
Result := SystemTime.wMonth;
end;
{Modified}
function ExpandYear(Year: Integer): Integer;
var
N: Longint;
begin
if Year = -1 then
Result := CurrentYear
else
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;
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 COMPILER3_UP}
if ShortDateFormat[1] = 'g' then { skip over prefix text }
ScanToNumber(S, Pos);
{$ENDIF COMPILER3_UP}
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 COMPILER3_UP}
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 COMPILER3_UP}
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);
if M = -1 then
M := CurrentMonth;
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
{$IFDEF COMPILER3_UP}
raise EConvertError.CreateFmt(SInvalidDate, [S]);
{$ELSE}
raise EConvertError.CreateFmt(LoadStr(SInvalidDate), [S]);
{$ENDIF}
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 COMPILER3_UP}
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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -