Переглянути джерело

* Fixed bug #20522, adapted patch from Bart Broersma

git-svn-id: trunk@27775 -
michael 11 роки тому
батько
коміт
042e6243a3
2 змінених файлів з 91 додано та 42 видалено
  1. 90 41
      rtl/objpas/sysutils/dati.inc
  2. 1 1
      rtl/objpas/sysutils/datih.inc

+ 90 - 41
rtl/objpas/sysutils/dati.inc

@@ -760,60 +760,109 @@ end;
     if S does not represent a valid date and/or time value
     an EConvertError will be raised   }
 
-function StrToDateTime(const s: string): TDateTime;
+function SplitDateTimeStr(DateTimeStr: AnsiString; const FS: TFormatSettings; out DateStr, TimeStr: AnsiString): Integer;
+
+{ Helper function for StrToDateTime
+  Pre-condition
+    Date is before Time
+    If either Date or Time is omitted then see what fits best, a time or a date (issue #0020522)
+    Date and Time are separated by whitespace (space Tab, Linefeed or carriage return)
+    FS.DateSeparator can be the same as FS.TimeSeparator (issue #0020522)
+    If they are both #32 and TrimWhite(DateTimeStr) contains a #32 a date is assumed.
+  Post-condition
+    DateStr holds date as string or is empty
+    TimeStr holds time as string or is empty
+    Result = number of strings returned, 0 = error
+}
+const
+  WhiteSpace = [#9,#10,#13,#32];
+
 var
-  I: integer;
-begin
-  I:=Pos(DefaultFormatSettings.TimeSeparator,S);
-  If (I>0) then
+  p: Integer;
+  DummyDT: TDateTime;
+begin
+  Result := 0;
+  DateStr := '';
+  TimeStr := '';
+  DateTimeStr := Trim(DateTimeStr);
+  if Length(DateTimeStr) = 0 then exit;
+  if (FS.DateSeparator = #32) and (FS.TimeSeparator = #32) and (Pos(#32, DateTimeStr) > 0) then 
     begin
-    While (I>0) and (S[I]<>' ') do
-      Dec(I);
-    If I>0 then
-      result:=ComposeDateTime(StrToDate(Copy(S,1,I-1)),StrToTime(Copy(S,i+1, Length(S)-i)))
-    else
-      result:=StrToTime(S)
+    DateStr:=DateTimeStr;
+    {
+      Assume a date: dd [mm [yy]]. 
+      Really fancy would be counting the number of whitespace occurrences and decide 
+      and split accordingly
+    }
+    Exit(1); 
+    end;
+  p:=1;
+  //find separator
+  if (FS.DateSeparator<>#32) then
+    begin  
+    while (p<Length(DateTimeStr)) and (not (DateTimeStr[p+1] in WhiteSpace)) do 
+      Inc(p);
     end
   else
-    Result:=StrToDate(S);
-end;
+    begin
+    p:=Pos(FS.TimeSeparator, DateTimeStr);
+    if (p<>0) then 
+      repeat
+        Dec(p);
+      until (p=0) or (DateTimeStr[p] in WhiteSpace);
+    end;
+  //Always fill DateStr, it eases the algorithm later
+  if (p=0) then 
+    p:=Length(DateTimeStr);
+  DateStr:=Copy(DateTimeStr,1,p);
+  TimeStr:=Trim(Copy(DateTimeStr,p+1,MaxInt));
+  if (Length(TimeStr)<>0) then
+    Result:=2
+  else
+    begin
+    Result:=1; //found 1 string
+    // 2 cases when DateTimeStr only contains a time:
+    // Date/time separator differ, and string contains a timeseparator
+    // Date/time separators are equal, but transformation to date fails.
+    if ((FS.DateSeparator<>FS.TimeSeparator) and (Pos(FS.TimeSeparator,DateStr) > 0))
+       or ((FS.DateSeparator=FS.TimeSeparator) and (not TryStrToDate(DateStr, DummyDT, FS)))  then
+      begin
+      TimeStr := DateStr;
+      DateStr := '';
+      end;
+    end;
+end; 
+
 
 function StrToDateTime(const s: AnsiString; const FormatSettings : TFormatSettings): TDateTime;
 var
-  I: integer;
+  TimeStr, DateStr: AnsiString;
+  PartsFound: Integer;
+begin
+  PartsFound := SplitDateTimeStr(S, FormatSettings, DateStr, TimeStr);
+  case PartsFound of  
+    0: Result:=StrToDate('');
+    1: if (Length(DateStr) > 0) then
+         Result := StrToDate(DateStr, FormatSettings.ShortDateFormat,FormatSettings.DateSeparator)
+       else
+         Result := StrToTime(TimeStr, FormatSettings);
+    2: Result := ComposeDateTime(StrTodate(DateStr,FormatSettings.ShortDateFormat,FormatSettings.DateSeparator),
+                                  StrToTime(TimeStr,FormatSettings));
+  end;
+end;
+
+function StrToDateTime(const s: AnsiString): TDateTime;
 begin
-  I:=Pos(FormatSettings.TimeSeparator,S);
-  If (I>0) then
-    begin
-    While (I>0) and (S[I]<>' ') do
-      Dec(I);
-    If I>0 then
-      result:=ComposeDateTime(StrToDate(Copy(S,1,I-1),FormatSettings.ShortDateFormat,FormatSettings.DateSeparator),
-                              StrToTime(Copy(S,i+1, Length(S)-i),FormatSettings))
-    else
-      result:=StrToTime(S,FormatSettings)
-    end
-  else
-    Result:=StrToDate(S,FormatSettings.ShortDateFormat,FormatSettings.DateSeparator);
+  Result:=StrToDateTime(S,DefaultFormatSettings);
 end;
 
 function StrToDateTime(const s: ShortString; const FormatSettings : TFormatSettings): TDateTime;
+
 var
-  I: integer;
+  A : AnsiString;
 begin
-  I:=Pos(FormatSettings.TimeSeparator,S);
-  If (I>0) then
-    begin
-    While (I>0) and (S[I]<>' ') do
-      Dec(I);
-    If I>0 then
-      result:=ComposeDateTime(StrToDate(Copy(S,1,I-1),FormatSettings.ShortDateFormat,FormatSettings.DateSeparator),
-                              StrToTime(Copy(S,i+1, Length(S)-i),FormatSettings.TimeSeparator))
-    else
-      result:=StrToTime(S,FormatSettings.TimeSeparator)
-    end
-  else
-    Result:=StrToDate(S,FormatSettings.ShortDateFormat,FormatSettings.DateSeparator);
+  A:=S;
+  Result:=StrToDateTime(A,FormatSettings);
 end;
 
 {   FormatDateTime formats DateTime to the given format string FormatStr   }

+ 1 - 1
rtl/objpas/sysutils/datih.inc

@@ -135,7 +135,7 @@ function StrToDate(const S: ShortString; const useformat : string; separator : c
 function StrToDate(const S: AnsiString; const useformat : string; separator : char = #0): TDateTime;{$ifdef SYSUTILSINLINE}inline;{$endif}
 function StrToTime(const S: PChar; Len : integer; separator : char = #0): TDateTime;
 function StrToDate(const S: PChar; Len : integer; const useformat : string; separator : char = #0): TDateTime;
-function StrToDateTime(const S: string): TDateTime;
+function StrToDateTime(const S: AnsiString): TDateTime;
 function StrToDateTime(const s: ShortString; const FormatSettings : TFormatSettings): TDateTime;
 function StrToDateTime(const s: AnsiString; const FormatSettings : TFormatSettings): TDateTime;
 function FormatDateTime(const FormatStr: string; DateTime: TDateTime):string;