2008-11-24 15:39:35 +00:00
|
|
|
{ This file is part of the Web Service Toolkit
|
|
|
|
Copyright (c) 2008 by Inoussa OUEDRAOGO
|
|
|
|
|
|
|
|
This file is provide under modified LGPL licence
|
|
|
|
( the files COPYING.modifiedLGPL and COPYING.LGPL).
|
|
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
}
|
|
|
|
{$INCLUDE wst_global.inc}
|
|
|
|
unit date_utils;
|
|
|
|
|
|
|
|
interface
|
|
|
|
uses
|
2009-07-07 10:45:45 +00:00
|
|
|
SysUtils, wst_types;
|
2008-11-24 15:39:35 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
|
|
|
|
TDateTimeRec = packed record
|
|
|
|
Date : TDateTime;
|
|
|
|
HourOffset : Shortint;
|
|
|
|
MinuteOffset : Shortint;
|
|
|
|
end;
|
|
|
|
|
2009-07-06 16:21:25 +00:00
|
|
|
TTimeRec = packed record
|
|
|
|
Hour : Byte;
|
|
|
|
Minute : Byte;
|
|
|
|
Second : Byte;
|
|
|
|
MilliSecond : Word;
|
|
|
|
HourOffset : Shortint;
|
|
|
|
MinuteOffset : Shortint;
|
|
|
|
end;
|
|
|
|
|
2009-07-07 10:45:45 +00:00
|
|
|
TDurationRec = packed record
|
|
|
|
Year : PtrUInt;
|
|
|
|
Month : PtrUInt;
|
|
|
|
Day : PtrUInt;
|
|
|
|
Hour : PtrUInt;
|
|
|
|
Minute : PtrUInt;
|
|
|
|
Second : PtrUInt;
|
|
|
|
FractionalSecond : PtrUInt;
|
|
|
|
Negative : Boolean;
|
|
|
|
end;
|
|
|
|
|
2009-01-19 17:51:35 +00:00
|
|
|
const
|
|
|
|
ZERO_DATE : TDateTimeRec = ( Date : 0; HourOffset : 0; MinuteOffset : 0; );
|
2009-07-06 16:21:25 +00:00
|
|
|
ZERO_TIME : TTimeRec = (
|
|
|
|
Hour : 0;
|
|
|
|
Minute : 0;
|
|
|
|
Second : 0;
|
|
|
|
MilliSecond : 0;
|
|
|
|
HourOffset : 0;
|
|
|
|
MinuteOffset : 0;
|
|
|
|
);
|
2009-07-07 10:45:45 +00:00
|
|
|
ZERO_DURATION : TDurationRec = (
|
|
|
|
Year : 0;
|
|
|
|
Month : 0;
|
|
|
|
Day : 0;
|
|
|
|
Hour : 0;
|
|
|
|
Minute : 0;
|
|
|
|
Second : 0;
|
|
|
|
FractionalSecond : 0;
|
|
|
|
Negative : False;
|
|
|
|
);
|
2009-01-19 17:51:35 +00:00
|
|
|
|
2009-07-08 18:52:13 +00:00
|
|
|
type
|
|
|
|
TXsdDateKind = ( xdkDateTime, xdkDate );
|
2009-09-02 12:24:19 +00:00
|
|
|
TValueCompareKind = (
|
|
|
|
vckEqual, vckLessThan, vckGreaterThan, vckNotEqual,
|
|
|
|
vckEqualOrLessThan, vckEqualOrGreaterThan
|
|
|
|
);
|
2008-11-24 15:39:35 +00:00
|
|
|
|
2009-07-08 18:52:13 +00:00
|
|
|
function xsd_TryStrToDate(
|
|
|
|
const AStr : string;
|
|
|
|
out ADate : TDateTimeRec;
|
|
|
|
const ADateKind : TXsdDateKind
|
|
|
|
) : Boolean;
|
|
|
|
function xsd_StrToDate(
|
|
|
|
const AStr : string;
|
|
|
|
const ADateKind : TXsdDateKind
|
|
|
|
) : TDateTimeRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
|
|
|
|
|
|
function xsd_DateTimeToStr(
|
|
|
|
const ADate : TDateTimeRec;
|
|
|
|
const ADateKind : TXsdDateKind
|
|
|
|
) : string; overload;
|
|
|
|
function xsd_DateTimeToStr(
|
|
|
|
const ADate : TDateTime;
|
|
|
|
const ADateKind : TXsdDateKind
|
|
|
|
) : string;overload;
|
2008-11-24 15:39:35 +00:00
|
|
|
|
2009-07-06 16:21:25 +00:00
|
|
|
function xsd_TimeToStr(const ATime : TTimeRec) : string;
|
|
|
|
function xsd_TryStrToTime(const AStr : string; out ADate : TTimeRec) : Boolean;
|
|
|
|
function xsd_StrToTime(const AStr : string) : TTimeRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
|
|
function xsd_EncodeTime(
|
|
|
|
const AHour,
|
|
|
|
AMin,
|
|
|
|
ASec : Byte;
|
|
|
|
const AMiliSec : Word
|
|
|
|
) : TTimeRec; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
|
|
function xsd_EncodeTime(
|
|
|
|
const AHour,
|
|
|
|
AMin,
|
|
|
|
ASec : Byte;
|
|
|
|
const AMiliSec : Word;
|
|
|
|
const AHourOffset : Shortint;
|
|
|
|
const AMinuteOffset : Shortint
|
|
|
|
) : TTimeRec; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
|
|
function DateTimeToTimeRec(const ADateTime : TDateTime) : TTimeRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
|
|
function TimeRecToDateTime(const ATime : TTimeRec) : TDateTime; {$IFDEF USE_INLINE}inline;{$ENDIF}
|
2009-11-09 09:44:12 +00:00
|
|
|
function DateTimeToDateTimeRec(const ADateTime : TDateTime) : TDateTimeRec;
|
2009-07-06 16:21:25 +00:00
|
|
|
|
2009-07-07 10:45:45 +00:00
|
|
|
function xsd_TryStrToDuration(
|
|
|
|
const ABuffer : string;
|
|
|
|
out AResult : TDurationRec
|
|
|
|
) : Boolean;
|
|
|
|
function xsd_StrToDuration(const ABuffer : string) : TDurationRec;
|
|
|
|
function xsd_DurationToStr(const AValue : TDurationRec) : string;
|
2009-07-06 16:21:25 +00:00
|
|
|
|
2008-11-24 15:39:35 +00:00
|
|
|
function IncHour(const AValue: TDateTime; const ANumberOfHours: Int64): TDateTime;{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
|
|
function IncMinute(const AValue: TDateTime; const ANumberOfMinutes: Int64): TDateTime;{$IFDEF USE_INLINE}inline;{$ENDIF}
|
|
|
|
|
2009-07-06 16:21:25 +00:00
|
|
|
function NormalizeToUTC(const ADate : TDateTimeRec) : TDateTime; overload;
|
|
|
|
function NormalizeToUTC(const ATime : TTimeRec) : TTimeRec; overload;
|
2009-07-07 10:45:45 +00:00
|
|
|
function ValueEquals(const AA,AB: TDateTimeRec) : Boolean; overload;
|
|
|
|
function ValueEquals(const AA,AB: TTimeRec) : Boolean; overload;
|
|
|
|
function ValueEquals(const AA,AB: TDurationRec) : Boolean; overload;
|
2009-01-19 17:51:35 +00:00
|
|
|
|
2009-09-02 12:24:19 +00:00
|
|
|
function CompareValue(
|
|
|
|
const AA,AB : TDateTimeRec;
|
|
|
|
const ACompareKind : TValueCompareKind
|
|
|
|
) : Boolean;
|
|
|
|
|
2008-11-24 15:39:35 +00:00
|
|
|
resourcestring
|
|
|
|
SERR_InvalidDate = '"%s" is not a valid date.';
|
2009-07-06 16:21:25 +00:00
|
|
|
SERR_InvalidTime = '"%s" is not a valid time.';
|
2009-07-07 10:45:45 +00:00
|
|
|
SERR_InvalidDuration = '"%s" is not a valid duration.';
|
2008-11-24 15:39:35 +00:00
|
|
|
|
|
|
|
implementation
|
|
|
|
|
2009-07-07 11:19:25 +00:00
|
|
|
uses DateUtils;
|
2008-11-24 15:39:35 +00:00
|
|
|
|
|
|
|
function IncHour(const AValue: TDateTime; const ANumberOfHours: Int64): TDateTime;
|
|
|
|
begin
|
|
|
|
Result := DateOf(AValue) + DateUtils.IncHour(TimeOf(AValue),ANumberOfHours);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function IncMinute(const AValue: TDateTime; const ANumberOfMinutes: Int64): TDateTime;
|
|
|
|
begin
|
|
|
|
Result := DateOf(AValue) + DateUtils.IncMinute(TimeOf(AValue),ANumberOfMinutes);
|
|
|
|
end;
|
|
|
|
|
2009-01-19 17:51:35 +00:00
|
|
|
function NormalizeToUTC(const ADate : TDateTimeRec) : TDateTime;
|
|
|
|
begin
|
|
|
|
Result := ADate.Date;
|
|
|
|
if ( ADate.HourOffset <> 0 ) then
|
|
|
|
Result := IncHour(Result,-ADate.HourOffset);
|
|
|
|
if ( ADate.MinuteOffset <> 0 ) then
|
|
|
|
Result := IncMinute(Result,-ADate.MinuteOffset);
|
|
|
|
end;
|
|
|
|
|
2009-07-06 16:21:25 +00:00
|
|
|
function NormalizeToUTC(const ATime : TTimeRec) : TTimeRec;
|
|
|
|
var
|
|
|
|
locDate : TDateTime;
|
|
|
|
e_h, e_mn, e_ss, e_ms : Word;
|
|
|
|
begin
|
|
|
|
locDate := TimeRecToDateTime(ATime);
|
|
|
|
if ( ATime.HourOffset <> 0 ) then
|
|
|
|
locDate := IncHour(locDate,ATime.HourOffset);
|
|
|
|
if ( ATime.MinuteOffset <> 0 ) then
|
|
|
|
locDate := IncMinute(locDate,ATime.MinuteOffset);
|
|
|
|
DecodeTime(locDate,e_h,e_mn,e_ss,e_ms);
|
|
|
|
Result.Hour := e_h;
|
|
|
|
Result.Minute := e_mn;
|
|
|
|
Result.Second := e_ss;
|
|
|
|
Result.MilliSecond := e_ms;
|
|
|
|
Result.HourOffset := 0;
|
|
|
|
Result.MinuteOffset := 0;
|
|
|
|
end;
|
|
|
|
|
2009-06-27 22:34:35 +00:00
|
|
|
{$HINTS OFF}
|
2009-07-07 10:45:45 +00:00
|
|
|
function ValueEquals(const AA,AB: TDateTimeRec) : Boolean;
|
2009-01-19 17:51:35 +00:00
|
|
|
var
|
|
|
|
e, a : TDateTime;
|
|
|
|
e_y, e_m, e_d, e_h, e_mn, e_ss, e_ms : Word;
|
|
|
|
a_y, a_m, a_d, a_h, a_mn, a_ss, a_ms : Word;
|
|
|
|
begin
|
|
|
|
e := NormalizeToUTC(AA);
|
|
|
|
a := NormalizeToUTC(AB);
|
|
|
|
DecodeDateTime(e, e_y, e_m, e_d, e_h, e_mn, e_ss, e_ms);
|
|
|
|
DecodeDateTime(a, a_y, a_m, a_d, a_h, a_mn, a_ss, a_ms);
|
|
|
|
Result := ( e_y = a_y ) and ( e_m = a_m ) and ( e_d = a_d ) and
|
|
|
|
(e_h = a_h ) and ( e_mn = a_mn ) and ( e_ss = a_ss ) and ( e_ms = a_ms );
|
|
|
|
end;
|
2009-06-27 22:34:35 +00:00
|
|
|
{$HINTS ON}
|
2009-01-19 17:51:35 +00:00
|
|
|
|
2009-07-07 10:45:45 +00:00
|
|
|
function ValueEquals(const AA,AB: TTimeRec) : Boolean;
|
2009-07-06 16:21:25 +00:00
|
|
|
var
|
|
|
|
a, b : TTimeRec;
|
|
|
|
begin
|
|
|
|
a := NormalizeToUTC(AA);
|
|
|
|
b := NormalizeToUTC(AB);
|
|
|
|
Result := ( a.Hour = b.Hour ) and
|
|
|
|
( a.Minute = b.Minute ) and
|
|
|
|
( a.Second = b.Second ) and
|
|
|
|
( a.MilliSecond = b.MilliSecond ) and
|
|
|
|
( a.HourOffset = b.HourOffset ) and
|
|
|
|
( a.MinuteOffset = b.MinuteOffset );
|
|
|
|
end;
|
|
|
|
|
2009-09-02 12:24:19 +00:00
|
|
|
function CompareValue(
|
|
|
|
const AA,AB : TDateTimeRec;
|
|
|
|
const ACompareKind : TValueCompareKind
|
|
|
|
) : Boolean;
|
|
|
|
begin
|
|
|
|
case ACompareKind of
|
|
|
|
vckEqual : Result := ValueEquals(AA,AB);
|
|
|
|
vckLessThan : Result := ( NormalizeToUTC(AA) < NormalizeToUTC(AB) );
|
|
|
|
vckGreaterThan : Result := ( NormalizeToUTC(AA) > NormalizeToUTC(AB) );
|
|
|
|
vckNotEqual : Result := not ValueEquals(AA,AB);
|
|
|
|
vckEqualOrLessThan : Result := ValueEquals(AA,AB) or ( NormalizeToUTC(AA) < NormalizeToUTC(AB) );
|
|
|
|
vckEqualOrGreaterThan : Result := ValueEquals(AA,AB) or ( NormalizeToUTC(AA) > NormalizeToUTC(AB) );
|
|
|
|
else begin
|
|
|
|
Assert(False); // To suppress the warning
|
|
|
|
Result := False;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2009-07-08 18:52:13 +00:00
|
|
|
function xsd_TryStrToDate(
|
|
|
|
const AStr : string;
|
|
|
|
out ADate : TDateTimeRec;
|
|
|
|
const ADateKind : TXsdDateKind
|
|
|
|
) : Boolean;
|
2008-11-24 15:39:35 +00:00
|
|
|
const
|
|
|
|
DATE_SEP_CHAR = '-'; TIME_MARKER_CHAR = 'T'; TIME_SEP_CHAR = ':';
|
|
|
|
var
|
|
|
|
buffer : string;
|
|
|
|
bufferPos, bufferLen : Integer;
|
|
|
|
|
|
|
|
function ReadInt(out AValue : Integer; const ASeparatorAtEnd : Char) : Boolean;
|
|
|
|
var
|
|
|
|
locStartPos : Integer;
|
|
|
|
begin
|
|
|
|
while ( bufferPos <= bufferLen ) and ( buffer[bufferPos] < #33 ) do begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
end;
|
|
|
|
locStartPos := bufferPos;
|
|
|
|
if ( bufferPos <= bufferLen ) and ( buffer[bufferPos] in ['-','+'] ) then
|
|
|
|
Inc(bufferPos);
|
|
|
|
while ( bufferPos <= bufferLen ) and ( buffer[bufferPos] in ['0'..'9'] ) do begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
end;
|
|
|
|
Result := ( bufferPos > locStartPos ) and
|
|
|
|
( ( ASeparatorAtEnd = #0 ) or
|
|
|
|
( ( bufferPos <= bufferLen ) and
|
|
|
|
( buffer[bufferPos] = ASeparatorAtEnd )
|
|
|
|
)
|
|
|
|
);
|
|
|
|
if Result then
|
|
|
|
Result := TryStrToInt(Copy(buffer,locStartPos,(bufferPos-locStartPos)),AValue);
|
|
|
|
end;
|
2009-01-19 17:51:35 +00:00
|
|
|
|
2009-07-07 11:19:25 +00:00
|
|
|
function ReadMiliSeconds(out AValue : Integer) : Boolean;
|
2009-01-19 17:51:35 +00:00
|
|
|
var
|
|
|
|
locDigitCount, locRes, itemp, locErcode : Integer;
|
|
|
|
begin
|
|
|
|
while ( bufferPos <= bufferLen ) and ( buffer[bufferPos] < #33 ) do begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
end;
|
|
|
|
locRes := 0;
|
|
|
|
locDigitCount := 0;
|
|
|
|
while ( locDigitCount < 3 ) and ( bufferPos <= bufferLen ) and ( buffer[bufferPos] in ['0'..'9'] ) do begin
|
|
|
|
Val(buffer[bufferPos],itemp,locErcode);
|
|
|
|
locRes := ( locRes * 10 ) + itemp;
|
|
|
|
Inc(bufferPos);
|
|
|
|
Inc(locDigitCount);
|
|
|
|
end;
|
2010-01-06 10:16:10 +00:00
|
|
|
if ( locDigitCount >= 3 ) then begin
|
|
|
|
//Skip the remaining fractional part
|
|
|
|
while ( bufferPos <= bufferLen ) and ( buffer[bufferPos] in ['0'..'9'] ) do begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
end;
|
|
|
|
end;
|
2009-01-19 17:51:35 +00:00
|
|
|
Result := ( locDigitCount > 0 );
|
|
|
|
if Result then begin
|
|
|
|
if ( locDigitCount < 3 ) and ( locRes > 0 ) then begin
|
|
|
|
while ( locDigitCount < 3 ) do begin
|
|
|
|
locRes := locRes * 10;
|
|
|
|
Inc(locDigitCount);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
AValue := locRes;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2008-11-24 15:39:35 +00:00
|
|
|
var
|
|
|
|
d, m, y : Integer;
|
2009-01-19 17:51:35 +00:00
|
|
|
hh, mn, ss, ssss : Integer;
|
2008-11-24 15:39:35 +00:00
|
|
|
tz_hh, tz_mn : Integer;
|
|
|
|
tz_negative : Boolean;
|
|
|
|
ok : Boolean;
|
|
|
|
begin
|
|
|
|
//'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)?
|
|
|
|
|
|
|
|
buffer := Trim(AStr);
|
|
|
|
bufferPos := 1;
|
|
|
|
bufferLen := Length(buffer);
|
|
|
|
if ( bufferLen > 0 ) then begin
|
|
|
|
Result := False;
|
|
|
|
FillChar(ADate,SizeOf(ADate),#0);
|
|
|
|
|
|
|
|
if ReadInt(y,DATE_SEP_CHAR) then begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
if ReadInt(m,DATE_SEP_CHAR) then begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
if ReadInt(d,#0) then begin
|
|
|
|
tz_hh := 0;
|
|
|
|
tz_mn := 0;
|
2009-07-08 18:52:13 +00:00
|
|
|
hh := 0;
|
|
|
|
mn := 0;
|
|
|
|
ss := 0;
|
|
|
|
ssss := 0;
|
2011-12-08 14:18:59 +00:00
|
|
|
if (bufferPos >= bufferLen) {or (ADateKind = xdkDate)} then begin
|
2008-11-24 15:39:35 +00:00
|
|
|
ok := True;
|
|
|
|
end else begin
|
2009-07-08 18:52:13 +00:00
|
|
|
ok := ( buffer[bufferPos] in [TIME_MARKER_CHAR,'-','+'] );
|
2008-11-24 15:39:35 +00:00
|
|
|
if ok then begin
|
2009-07-08 18:52:13 +00:00
|
|
|
if ( buffer[bufferPos] = TIME_MARKER_CHAR ) then begin
|
2008-11-24 15:39:35 +00:00
|
|
|
Inc(bufferPos);
|
2011-12-08 14:18:59 +00:00
|
|
|
ok := //( ADateKind = xdkDateTime ) and
|
|
|
|
ReadInt(hh,TIME_SEP_CHAR);
|
2009-07-08 18:52:13 +00:00
|
|
|
if ok then begin
|
2009-01-19 17:51:35 +00:00
|
|
|
Inc(bufferPos);
|
2009-07-08 18:52:13 +00:00
|
|
|
ok := ReadInt(mn,TIME_SEP_CHAR);
|
|
|
|
if ok then begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
ok := ReadInt(ss,#0);
|
|
|
|
if ok and ( bufferPos < bufferLen ) and ( buffer[bufferPos] = '.' ) then begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
ok := ReadMiliSeconds(ssss);
|
|
|
|
end else begin
|
|
|
|
ssss := 0;
|
|
|
|
end;
|
|
|
|
end;
|
2009-01-19 17:51:35 +00:00
|
|
|
end;
|
2009-07-08 18:52:13 +00:00
|
|
|
end;
|
|
|
|
if ok and ( bufferPos < bufferLen ) then begin
|
|
|
|
ok := ( buffer[bufferPos] in ['-','+'] );
|
|
|
|
if ok then begin
|
2008-11-24 15:39:35 +00:00
|
|
|
tz_negative := ( buffer[bufferPos] = '-' );
|
|
|
|
Inc(bufferPos);
|
|
|
|
ok := ReadInt(tz_hh,TIME_SEP_CHAR);
|
|
|
|
if ok then begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
ok := ReadInt(tz_mn,#0);
|
|
|
|
if ok and tz_negative then begin
|
|
|
|
tz_hh := -tz_hh;
|
|
|
|
tz_mn := -tz_mn;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
if ok then begin
|
2009-01-19 17:51:35 +00:00
|
|
|
if ( ( y + m + d + hh + mn + ss + ssss ) = 0 ) then
|
2008-11-24 15:39:35 +00:00
|
|
|
ADate.Date := 0
|
|
|
|
else
|
2011-12-08 14:18:59 +00:00
|
|
|
begin
|
|
|
|
if (ADateKind = xdkDate) then
|
|
|
|
ADate.Date := EncodeDate(y,m,d)
|
|
|
|
else
|
|
|
|
ADate.Date := EncodeDate(y,m,d) + EncodeTime(hh,mn,ss,ssss);
|
|
|
|
end;
|
2008-11-24 15:39:35 +00:00
|
|
|
ADate.HourOffset := tz_hh;
|
|
|
|
ADate.MinuteOffset := tz_mn;
|
|
|
|
Result := True;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end else begin
|
|
|
|
FillChar(ADate,SizeOf(ADate),#0);
|
|
|
|
Result := True;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2009-07-08 18:52:13 +00:00
|
|
|
function xsd_StrToDate(
|
|
|
|
const AStr : string;
|
|
|
|
const ADateKind : TXsdDateKind
|
|
|
|
) : TDateTimeRec;
|
2008-11-24 15:39:35 +00:00
|
|
|
begin
|
2009-07-08 18:52:13 +00:00
|
|
|
if not xsd_TryStrToDate(AStr,Result,ADateKind) then
|
2008-11-24 15:39:35 +00:00
|
|
|
raise EConvertError.CreateFmt(SERR_InvalidDate,[AStr]);
|
|
|
|
end;
|
|
|
|
|
2009-07-07 11:19:25 +00:00
|
|
|
{$HINTS OFF}
|
2009-07-08 18:52:13 +00:00
|
|
|
function xsd_DateTimeToStr(
|
|
|
|
const ADate : TDateTimeRec;
|
|
|
|
const ADateKind : TXsdDateKind
|
|
|
|
) : string;
|
2008-11-24 15:39:35 +00:00
|
|
|
var
|
|
|
|
locDate : TDateTime;
|
|
|
|
d, m, y : Word;
|
|
|
|
hh, mn, ss, ssss : Word;
|
2009-07-08 18:52:13 +00:00
|
|
|
locRes : string;
|
2008-11-24 15:39:35 +00:00
|
|
|
begin
|
|
|
|
//'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)?
|
|
|
|
locDate := ADate.Date;
|
|
|
|
if ( ADate.HourOffset <> 0 ) then
|
|
|
|
locDate := IncHour(locDate,-ADate.HourOffset);
|
|
|
|
if ( ADate.MinuteOffset <> 0 ) then
|
|
|
|
locDate := IncMinute(locDate,-ADate.MinuteOffset);
|
2009-07-08 18:52:13 +00:00
|
|
|
if ( ADateKind = xdkDate ) then begin
|
|
|
|
DecodeDate(locDate,y,m,d);
|
|
|
|
locRes := Format('%.4d-%.2d-%.2d',[y,m,d]);
|
|
|
|
end else begin
|
|
|
|
DecodeDateTime(locDate,y,m,d,hh,mn,ss,ssss);
|
|
|
|
if ( ssss = 0 ) then
|
|
|
|
locRes := Format('%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ',[y,m,d, hh,mn,ss])
|
|
|
|
else
|
|
|
|
locRes := Format('%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ',[y,m,d, hh,mn,ss,ssss]);
|
|
|
|
end;
|
|
|
|
Result := locRes;
|
2008-11-24 15:39:35 +00:00
|
|
|
end;
|
2009-07-07 11:19:25 +00:00
|
|
|
{$HINTS ON}
|
2008-11-24 15:39:35 +00:00
|
|
|
|
2009-07-08 18:52:13 +00:00
|
|
|
function xsd_DateTimeToStr(
|
|
|
|
const ADate : TDateTime;
|
|
|
|
const ADateKind : TXsdDateKind
|
|
|
|
) : string;
|
2008-11-24 15:39:35 +00:00
|
|
|
var
|
|
|
|
tmpDate : TDateTimeRec;
|
|
|
|
begin
|
|
|
|
FillChar(tmpDate,SizeOf(TDateTimeRec),#0);
|
|
|
|
tmpDate.Date := ADate;
|
2009-07-08 18:52:13 +00:00
|
|
|
Result := xsd_DateTimeToStr(tmpDate,ADateKind);
|
2008-11-24 15:39:35 +00:00
|
|
|
end;
|
|
|
|
|
2009-07-06 16:21:25 +00:00
|
|
|
function xsd_TimeToStr(const ATime : TTimeRec) : string;
|
|
|
|
var
|
|
|
|
buffer : string;
|
|
|
|
begin
|
|
|
|
//hh ':' mm ':' ss ('.' s+)? (zzzzzz)?
|
2009-11-10 10:52:11 +00:00
|
|
|
if ( {( ATime.Hour < 0 ) or} ( ATime.Hour > 23 ) ) or
|
|
|
|
( {( ATime.Minute < 0 ) or} ( ATime.Minute > 59 ) ) or
|
|
|
|
( {( ATime.Second < 0 ) or} ( ATime.Second > 59 ) ) {or
|
|
|
|
( ATime.MilliSecond < 0 )}
|
2009-07-06 16:21:25 +00:00
|
|
|
then begin
|
|
|
|
buffer := Format('{ Hour : %d; Minute : %d; Second : %d; SecondFractional : %d}',[ATime.Hour,ATime.Minute,ATime.Second,ATime.MilliSecond]);
|
|
|
|
raise EConvertError.CreateFmt(SERR_InvalidTime,[buffer]);
|
|
|
|
end;
|
|
|
|
if ( ATime.MilliSecond = 0 ) then
|
|
|
|
buffer := Format('%.2d:%.2d:%.2d',[ATime.Hour,ATime.Minute,ATime.Second])
|
|
|
|
else
|
|
|
|
buffer := Format('%.2d:%.2d:%.2d.%.3d',[ATime.Hour,ATime.Minute,ATime.Second,ATime.MilliSecond]);
|
|
|
|
if ( ATime.HourOffset <> 0 ) then begin
|
|
|
|
if ( ATime.HourOffset > 0 ) then
|
|
|
|
buffer := Format('%s+%.2d',[buffer,ATime.HourOffset])
|
|
|
|
else
|
|
|
|
buffer := Format('%s-%.2d',[buffer,-ATime.HourOffset]);
|
|
|
|
if ( ATime.MinuteOffset > 0 ) then
|
|
|
|
buffer := Format('%s:%.2d',[buffer,ATime.MinuteOffset])
|
|
|
|
else if ( ATime.MinuteOffset < 0 ) then
|
|
|
|
buffer := Format('%s:%.2d',[buffer,-ATime.MinuteOffset]);
|
|
|
|
end else if ( ATime.MinuteOffset <> 0 ) then begin
|
|
|
|
if ( ATime.MinuteOffset > 0 ) then
|
|
|
|
buffer := Format('%s+00:%.2d',[buffer,ATime.MinuteOffset])
|
|
|
|
else if ( ATime.MinuteOffset < 0 ) then
|
|
|
|
buffer := Format('%s-00:%.2d',[buffer,-ATime.MinuteOffset]);
|
|
|
|
end;
|
|
|
|
if ( ATime.HourOffset = 0 ) and ( ATime.MinuteOffset = 0 ) then
|
|
|
|
buffer := buffer + 'Z';
|
|
|
|
Result := buffer;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function xsd_TryStrToTime(const AStr : string; out ADate : TTimeRec) : Boolean;
|
|
|
|
const
|
|
|
|
TIME_SEP_CHAR = ':';
|
|
|
|
var
|
|
|
|
buffer : string;
|
|
|
|
bufferPos, bufferLen : Integer;
|
|
|
|
|
|
|
|
function ReadInt(out AValue : Integer; const ASeparatorAtEnd : Char) : Boolean;
|
|
|
|
var
|
|
|
|
locStartPos : Integer;
|
|
|
|
begin
|
|
|
|
while ( bufferPos <= bufferLen ) and ( buffer[bufferPos] < #33 ) do begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
end;
|
|
|
|
locStartPos := bufferPos;
|
|
|
|
if ( bufferPos <= bufferLen ) and ( buffer[bufferPos] in ['-','+'] ) then
|
|
|
|
Inc(bufferPos);
|
|
|
|
while ( bufferPos <= bufferLen ) and ( buffer[bufferPos] in ['0'..'9'] ) do begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
end;
|
|
|
|
Result := ( bufferPos > locStartPos ) and
|
|
|
|
( ( ASeparatorAtEnd = #0 ) or
|
|
|
|
( ( bufferPos <= bufferLen ) and
|
|
|
|
( buffer[bufferPos] = ASeparatorAtEnd )
|
|
|
|
)
|
|
|
|
);
|
|
|
|
if Result then
|
|
|
|
Result := TryStrToInt(Copy(buffer,locStartPos,(bufferPos-locStartPos)),AValue);
|
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
|
|
|
hh, mn, ss, ssss : Integer;
|
|
|
|
tz_hh, tz_mn : Integer;
|
|
|
|
tz_negative : Boolean;
|
|
|
|
ok : Boolean;
|
|
|
|
begin
|
|
|
|
//hh ':' mm ':' ss ('.' s+)? (zzzzzz)?
|
|
|
|
buffer := Trim(AStr);
|
|
|
|
bufferPos := 1;
|
|
|
|
bufferLen := Length(buffer);
|
|
|
|
ok := False;
|
|
|
|
if ( bufferLen > 0 ) then begin
|
|
|
|
if ReadInt(hh,#0) then begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
mn := 0;
|
|
|
|
ss := 0;
|
|
|
|
ssss := 0;
|
|
|
|
tz_hh := 0;
|
|
|
|
tz_mn := 0;
|
|
|
|
ok := True;
|
|
|
|
if ( bufferPos < bufferLen ) then begin
|
|
|
|
ok := ( buffer[bufferPos -1] = TIME_SEP_CHAR ) and ReadInt(mn,#0);
|
|
|
|
if ok then begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
if ( bufferPos < bufferLen ) then begin
|
|
|
|
ok := ReadInt(ss,#0);
|
|
|
|
if ok then begin
|
|
|
|
if ( bufferPos < bufferLen ) then begin
|
|
|
|
if ( buffer[bufferPos] = '.' ) then begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
ok := ReadInt(ssss,#0);
|
|
|
|
end else begin
|
|
|
|
ssss := 0;
|
|
|
|
end;
|
|
|
|
if ok and ( bufferPos < bufferLen ) then begin
|
|
|
|
ok := ( buffer[bufferPos] in ['+','-'] );
|
|
|
|
if ok then begin
|
|
|
|
tz_negative := ( buffer[bufferPos] = '-' );
|
|
|
|
Inc(bufferPos);
|
|
|
|
ok := ReadInt(tz_hh,#0);
|
|
|
|
if ok then begin
|
|
|
|
Inc(bufferPos);
|
|
|
|
if ( bufferPos < bufferLen ) then
|
|
|
|
ok := ReadInt(tz_mn,#0)
|
|
|
|
else
|
|
|
|
tz_mn := 0;
|
|
|
|
if ok and tz_negative then begin
|
|
|
|
tz_hh := -tz_hh;
|
|
|
|
tz_mn := -tz_mn;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
if ok then begin
|
|
|
|
ok := ( ( hh = 24 ) and ( mn = 0 ) and ( ss = 0 ) and ( ssss = 0 )
|
|
|
|
) or
|
|
|
|
( ( hh >= 0 ) and ( hh < 24 ) and
|
|
|
|
( mn >= 0 ) and ( mn < 60 ) and
|
|
|
|
( ss >= 0 ) and ( ss < 60 ) and
|
|
|
|
( ssss >= 0 ) and ( ssss < 1000 )
|
|
|
|
);
|
|
|
|
ok := ok and
|
|
|
|
( tz_hh > -60 ) and ( tz_hh < 60 ) and
|
|
|
|
( tz_mn > -60 ) and ( tz_mn < 60 );
|
|
|
|
end;
|
|
|
|
if ok then begin
|
|
|
|
ADate.Hour := hh;
|
|
|
|
ADate.Minute := mn;
|
|
|
|
ADate.Second := ss;
|
|
|
|
ADate.MilliSecond := ssss;
|
|
|
|
ADate.HourOffset := tz_hh;
|
|
|
|
ADate.MinuteOffset := tz_mn;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
Result := ok;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function xsd_StrToTime(const AStr : string) : TTimeRec;
|
|
|
|
begin
|
|
|
|
if not xsd_TryStrToTime(AStr,Result) then
|
|
|
|
raise EConvertError.CreateFmt(SERR_InvalidTime,[AStr]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function xsd_EncodeTime(
|
|
|
|
const AHour,
|
|
|
|
AMin,
|
|
|
|
ASec : Byte;
|
|
|
|
const AMiliSec : Word
|
|
|
|
) : TTimeRec;
|
|
|
|
begin
|
|
|
|
Result := xsd_EncodeTime(AHour,AMin,ASec,AMiliSec,0,0);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function xsd_EncodeTime(
|
|
|
|
const AHour,
|
|
|
|
AMin,
|
|
|
|
ASec : Byte;
|
|
|
|
const AMiliSec : Word;
|
|
|
|
const AHourOffset : Shortint;
|
|
|
|
const AMinuteOffset : Shortint
|
|
|
|
) : TTimeRec;
|
|
|
|
begin
|
|
|
|
Result.Hour := AHour;
|
|
|
|
Result.Minute := AMin;
|
|
|
|
Result.Second := ASec;
|
|
|
|
Result.MilliSecond := AMiliSec;
|
|
|
|
Result.HourOffset := AHourOffset;
|
|
|
|
Result.MinuteOffset := AMinuteOffset;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function DateTimeToTimeRec(const ADateTime : TDateTime) : TTimeRec;
|
|
|
|
var
|
|
|
|
hh, mn, ss, ssss : Word;
|
|
|
|
begin
|
|
|
|
DecodeTime(ADateTime,hh,mn,ss,ssss);
|
|
|
|
Result.Hour := hh;
|
|
|
|
Result.Minute := mn;
|
|
|
|
Result.Second := ss;
|
|
|
|
Result.MilliSecond := ssss;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TimeRecToDateTime(const ATime : TTimeRec) : TDateTime;
|
|
|
|
begin
|
|
|
|
Result := EncodeTime(ATime.Hour,ATime.Minute,ATime.Second,ATime.MilliSecond);
|
|
|
|
end;
|
|
|
|
|
2009-11-09 09:44:12 +00:00
|
|
|
function DateTimeToDateTimeRec(const ADateTime : TDateTime) : TDateTimeRec;
|
|
|
|
begin
|
|
|
|
Result.Date := ADateTime;
|
|
|
|
Result.HourOffset := 0;
|
|
|
|
Result.MinuteOffset := 0;
|
|
|
|
end;
|
|
|
|
|
2009-07-07 10:45:45 +00:00
|
|
|
type TDatePart = ( dpNone, dpYear, dpMonth, dpDay, dpHour, dpMinute, dpSecond, dpFractionalSecond );
|
|
|
|
function xsd_TryStrToDuration(
|
|
|
|
const ABuffer : string;
|
|
|
|
out AResult : TDurationRec
|
|
|
|
) : Boolean;
|
|
|
|
var
|
|
|
|
pc : PChar;
|
|
|
|
locIntBuffer : array[dpYear..dpFractionalSecond] of PtrUInt;
|
|
|
|
i, bufferLength, lastPos : PtrInt;
|
|
|
|
localBuffer : string;
|
|
|
|
part, oldPart : TDatePart;
|
|
|
|
inTimePart : Boolean;
|
|
|
|
isNeg : Boolean;
|
|
|
|
begin
|
|
|
|
Result := False;
|
|
|
|
bufferLength := Length(ABuffer);
|
|
|
|
if ( bufferLength < 3 ) then
|
|
|
|
Exit;
|
|
|
|
pc := PChar(ABuffer);
|
|
|
|
i := 1;
|
|
|
|
isNeg := False;
|
|
|
|
if ( pc^ = '-' ) then begin
|
|
|
|
Inc(pc); Inc(i);
|
|
|
|
isNeg := True;
|
|
|
|
end;
|
|
|
|
if ( pc^ <> 'P' ) then
|
|
|
|
Exit;
|
|
|
|
Inc(pc); Inc(i); //eat 'P'
|
|
|
|
FillChar(locIntBuffer,SizeOf(locIntBuffer),#0);
|
|
|
|
part := dpNone;
|
|
|
|
inTimePart := False;
|
|
|
|
|
|
|
|
if ( pc^ = 'T' ) then begin
|
|
|
|
inTimePart := True;
|
|
|
|
Inc(pc); Inc(i);
|
|
|
|
end;
|
|
|
|
repeat
|
|
|
|
lastPos := i;
|
|
|
|
while ( i < bufferLength ) and ( pc^ in ['0'..'9'] ) do begin
|
|
|
|
Inc(pc); Inc(i);
|
|
|
|
end;
|
|
|
|
if ( ( lastPos = i ) and ( pc^ <> 'T' ) ) then
|
|
|
|
Exit;
|
|
|
|
localBuffer := Copy(ABuffer,lastPos,( i - lastPos ));
|
|
|
|
oldPart := part;
|
|
|
|
case pc^ of
|
|
|
|
'Y' : part := dpYear;
|
|
|
|
'M' :
|
|
|
|
begin
|
|
|
|
if inTimePart then
|
|
|
|
part := dpMinute
|
|
|
|
else
|
|
|
|
part := dpMonth;
|
|
|
|
end;
|
|
|
|
'D' : part := dpDay;
|
|
|
|
'H' : part := dpHour;
|
|
|
|
'S', '.' :
|
|
|
|
begin
|
|
|
|
if ( part < dpSecond ) then
|
|
|
|
part := dpSecond
|
|
|
|
else
|
|
|
|
part := dpFractionalSecond;
|
|
|
|
end;
|
|
|
|
'T' :
|
|
|
|
begin
|
|
|
|
inTimePart := True;
|
|
|
|
oldPart := dpNone;
|
|
|
|
part := dpNone;
|
|
|
|
end;
|
|
|
|
else
|
|
|
|
Exit;
|
|
|
|
end;
|
|
|
|
if inTimePart and ( part in [dpYear..dpDay] ) then
|
|
|
|
Exit;
|
|
|
|
if ( part > dpNone ) then begin
|
|
|
|
if ( part < oldPart ) then
|
|
|
|
Exit;
|
|
|
|
locIntBuffer[part] := StrToInt(localBuffer);
|
|
|
|
end;
|
|
|
|
Inc(pc); Inc(i);
|
|
|
|
until ( i >= bufferLength );
|
|
|
|
if ( i = bufferLength ) then
|
|
|
|
Exit;
|
|
|
|
AResult.Negative := isNeg;
|
|
|
|
AResult.Year := locIntBuffer[dpYear];
|
|
|
|
AResult.Month := locIntBuffer[dpMonth];
|
|
|
|
AResult.Day := locIntBuffer[dpDay];
|
|
|
|
AResult.Hour := locIntBuffer[dpHour];
|
|
|
|
AResult.Minute := locIntBuffer[dpMinute];
|
|
|
|
AResult.Second := locIntBuffer[dpSecond];
|
|
|
|
AResult.FractionalSecond := locIntBuffer[dpFractionalSecond];
|
|
|
|
|
|
|
|
Result := True;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function xsd_StrToDuration(const ABuffer : string) : TDurationRec;
|
|
|
|
begin
|
|
|
|
if not xsd_TryStrToDuration(ABuffer,Result) then
|
|
|
|
raise EConvertError.CreateFmt(SERR_InvalidDuration,[ABuffer]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function xsd_DurationToStr(const AValue : TDurationRec) : string;
|
|
|
|
var
|
|
|
|
strTime, strDate : string;
|
|
|
|
begin
|
2012-10-29 19:15:58 +00:00
|
|
|
Result := '';
|
2009-07-07 10:45:45 +00:00
|
|
|
if ( AValue.FractionalSecond > 0 ) then begin
|
|
|
|
strTime := IntToStr(AValue.Second) + '.' + IntToStr(AValue.FractionalSecond) + 'S';
|
|
|
|
end else begin
|
|
|
|
if ( AValue.Second > 0 ) then
|
|
|
|
strTime := IntToStr(AValue.Second) + 'S';
|
|
|
|
end;
|
|
|
|
if ( AValue.Minute > 0 ) then
|
|
|
|
strTime := IntToStr(AValue.Minute) + 'M' + strTime;
|
|
|
|
if ( AValue.Hour > 0 ) then
|
|
|
|
strTime := IntToStr(AValue.Hour) + 'H' + strTime;
|
|
|
|
if ( AValue.Day > 0 ) then
|
|
|
|
strDate := IntToStr(AValue.Day) + 'D';
|
|
|
|
if ( AValue.Month > 0 ) then
|
|
|
|
strDate := IntToStr(AValue.Month) + 'M' + strDate;
|
|
|
|
if ( AValue.Year > 0 ) then
|
|
|
|
strDate := IntToStr(AValue.Year) + 'Y' + strDate;
|
|
|
|
if ( strTime <> '' ) then
|
|
|
|
Result := 'T' + strTime;
|
|
|
|
Result := strDate + Result;
|
|
|
|
if ( Result = '' ) then
|
|
|
|
Result := '0Y';
|
|
|
|
Result := 'P' + Result;
|
|
|
|
if AValue.Negative and ( ( strDate <> '' ) or ( strTime <> '' ) ) then
|
|
|
|
Result := '-' + Result;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function ValueEquals(const AA,AB: TDurationRec) : Boolean;
|
|
|
|
begin
|
|
|
|
Result := ( AA.Negative = AB.Negative ) and
|
|
|
|
( AA.Year = AB.Year ) and
|
|
|
|
( AA.Month = AB.Month ) and
|
|
|
|
( AA.Day = AB.Day ) and
|
|
|
|
( AA.Hour = AB.Hour ) and
|
|
|
|
( AA.Minute = AB.Minute ) and
|
|
|
|
( AA.Second = AB.Second ) and
|
|
|
|
( AA.FractionalSecond = AB.FractionalSecond );
|
|
|
|
end;
|
|
|
|
|
2008-11-24 15:39:35 +00:00
|
|
|
end.
|