diff --git a/src/Horse.Commons.pas b/src/Horse.Commons.pas index bd3ec1d..ab7a560 100644 --- a/src/Horse.Commons.pas +++ b/src/Horse.Commons.pas @@ -12,10 +12,13 @@ interface Classes, SysUtils, StrUtils, + DateUtils, RegExpr; {$ELSE} System.Classes, System.SysUtils, + System.StrUtils, + System.DateUtils, System.RegularExpressions; {$ENDIF} @@ -134,9 +137,80 @@ function StringCommandToMethodType(const ACommand: string): TMethodType; {$ENDIF} function MatchRoute(const AText: string; const AValues: array of string): Boolean; +function IsDateTime(const AText: string): Boolean; overload; +function IsDateTime(const AText: string; out AParsedValue: TDateTime): Boolean; overload; implementation +function IsDateTime(const AText: string): Boolean; +var + LDateTime: TDateTime; +begin + Result := IsDateTime(AText, LDateTime); +end; + +function IsDateTime(const AText: string; out AParsedValue: TDateTime): Boolean; +const + C_DATE_FORMATS: array of string = [ + 'dd/MM/yyyy', 'dd-MM-yyyy', 'dd.MM.yyyy', + 'dd/MM/yy', 'dd-MM-yy', 'dd.MM.yy', + 'yyyy/MM/dd', 'yyyy-MM-dd', 'yyyy.MM.dd', + 'yy/MM/dd', 'yy-MM-dd', 'yy.MM.dd', + 'MM/dd/yyyy', 'MM-dd-yyyy', 'MM.dd.yyyy', + 'MM/dd/yy', 'MM-dd-yy', 'MM.dd.yy', + 'yyyy-MM-dd"T"', 'yyyy-MM-dd' + ]; + + C_TIME_FORMATS: array of string = [ + 'hh:nn', 'hh:nn AM/PM', + 'hh:nn:ss', 'hh:nn:ss AM/PM', + 'hh:nn:ss.zzz', 'hh:nn:ss.zzz AM/PM', + '"T"hh:nn:ss', + '"T"hh:nn:ss"Z"', + '"T"hh:nn:sszzz', + '"T"hh:nn:ss.zzz"Z"', + '"T"hh:nn:ss' + ]; +var + LText: string; + LDateFormat: string; + LTimeFormat: string; + LFormatSettings: TFormatSettings; +begin + Result := False; + AParsedValue := 0; + LText := AText.Trim.TrimLeft(['"']).TrimRight(['"']); + + if (Length(LText) >= 5) and ((Length(LText) - LastDelimiter('-', LText)) in [5, 6]) then + LText := Copy(LText, 1, LastDelimiter('-', LText) - 1); + + LFormatSettings := {$IF DEFINED(FPC)}DefaultFormatSettings{$ELSE}TFormatSettings.Create{$ENDIF}; + for LDateFormat in C_DATE_FORMATS do + begin + LFormatSettings.ShortDateFormat := LDateFormat; + for LTimeFormat in C_TIME_FORMATS do + begin + LFormatSettings.ShortTimeFormat := LTimeFormat; + AParsedValue := StrToDateTimeDef(LText, 0, LFormatSettings); + if (AParsedValue > 0) then Exit(True); + end; + end; + + for LDateFormat in C_DATE_FORMATS do + begin + LFormatSettings.ShortDateFormat := LDateFormat; + AParsedValue := {$IF DEFINED(FPC)}StrToDateTimeDef{$ELSE}StrToDateDef{$ENDIF}(LText, 0, LFormatSettings); + if (AParsedValue > 0) then Exit(True); + end; + + for LTimeFormat in C_TIME_FORMATS do + begin + LFormatSettings.ShortTimeFormat := LTimeFormat; + AParsedValue := {$IF DEFINED(FPC)}StrToDateTimeDef{$ELSE}StrToTimeDef{$ENDIF}(LText, 0, LFormatSettings); + if (AParsedValue > 0) then Exit(True); + end; +end; + {$IF DEFINED(FPC)} function StringCommandToMethodType(const ACommand: string): TMethodType; begin diff --git a/src/Horse.Core.Param.Field.pas b/src/Horse.Core.Param.Field.pas index 0b34c47..62a84fa 100644 --- a/src/Horse.Core.Param.Field.pas +++ b/src/Horse.Core.Param.Field.pas @@ -41,7 +41,6 @@ THorseCoreParamField = class FStream: TStream; FLhsBrackets: THorseCoreParamFieldLhsBrackets; - function GetFormatSettings: TFormatSettings; procedure RaiseHorseException(const AMessage: string); overload; procedure RaiseHorseException(const AMessage: string; const Args: array of const); overload; function TryISO8601ToDate(const AValue: string; out Value: TDateTime): Boolean; @@ -97,16 +96,27 @@ function THorseCoreParamField.AsCurrency: Currency; function THorseCoreParamField.AsDate: TDateTime; var + {$IF DEFINED(FPC)} + LDay: Word; + LMonth: Word; + LYear: Word; + {$ENDIF} LStrParam: string; - LFormat: TFormatSettings; + LDateTime: TDateTime; begin Result := 0; LStrParam := Trim(AsString); try if LStrParam = EmptyStr then Exit; - LFormat := GetFormatSettings; - Result := StrToDate(Copy(LStrParam, 1, Length(FDateFormat)), LFormat); + if not IsDateTime(LStrParam, LDateTime) then + raise EConvertError.Create(''); + {$IF DEFINED(FPC)} + DecodeDate(LDateTime, LYear, LMonth, LDay); + Result := EncodeDate(LYear, LMonth, LDay); + {$ELSE} + Result.SetDate(LDateTime.Year, LDateTime.Month, LDateTime.Day); + {$ENDIF} except on E: EConvertError do RaiseHorseException(FInvalidFormatMessage, [FFieldName, LStrParam, 'date']); @@ -116,15 +126,14 @@ function THorseCoreParamField.AsDate: TDateTime; function THorseCoreParamField.AsDateTime: TDateTime; var LStrParam: string; - LFormat: TFormatSettings; begin Result := 0; LStrParam := Trim(AsString); try if LStrParam = EmptyStr then Exit; - LFormat := GetFormatSettings; - Result := StrToDateTime(LStrParam, LFormat); + if not IsDateTime(LStrParam, Result) then + raise EConvertError.Create(''); except on E: EConvertError do RaiseHorseException(FInvalidFormatMessage, [FFieldName, LStrParam, 'datetime']); @@ -280,16 +289,28 @@ function THorseCoreParamField.AsString: string; function THorseCoreParamField.AsTime: TTime; var + {$IF DEFINED(FPC)} + LHour: Word; + LMinute: Word; + LSecond: Word; + LMilliSecond: Word; + {$ENDIF} LStrParam: string; - LFormat: TFormatSettings; + LDateTime: TDateTime; begin Result := 0; LStrParam := Trim(AsString); try if LStrParam = EmptyStr then Exit; - LFormat := GetFormatSettings; - Result := StrToTime(Copy(LStrParam, 1, Length(FTimeFormat)), LFormat); + if not IsDateTime(LStrParam, LDateTime) then + raise EConvertError.Create(''); + {$IF DEFINED(FPC)} + DecodeTime(LDateTime, LHour, LMinute, LSecond, LMilliSecond); + Result := EncodeTime(LHour, LMinute, LSecond, LMilliSecond); + {$ELSE} + TDateTime(Result).SetTime(LDateTime.Hour, LDateTime.Minute, LDateTime.Second, 0); + {$ENDIF} except on E: EConvertError do RaiseHorseException(FInvalidFormatMessage, [FFieldName, LStrParam, 'time']); @@ -341,19 +362,6 @@ function THorseCoreParamField.DateFormat(const AValue: string): THorseCoreParamF FDateFormat := AValue; end; -function THorseCoreParamField.GetFormatSettings: TFormatSettings; -begin -{$IF DEFINED(FPC)} - Result := DefaultFormatSettings; -{$ELSE} - Result := TFormatSettings.Create; -{$ENDIF} - if FDateFormat.IndexOf('-') > 0 then - Result.DateSeparator := '-'; - Result.ShortDateFormat := FDateFormat; - Result.ShortTimeFormat := FTimeFormat; -end; - procedure THorseCoreParamField.InitializeLhsBrackets(const AParams: TDictionary; const AFieldName: string); var LLhsBracketType: TLhsBracketsType;