Browse Source

* Added ISO8601ToDate and inverse (Bug ID 35307)

git-svn-id: trunk@41954 -
michael 6 years ago
parent
commit
74455d0720
1 changed files with 88 additions and 0 deletions
  1. 88 0
      packages/rtl-objpas/src/inc/dateutil.inc

+ 88 - 0
packages/rtl-objpas/src/inc/dateutil.inc

@@ -440,6 +440,14 @@ Function LocalTimeToUniversal(LT: TDateTime; TZOffset: Integer): TDateTime;
 function ScanDateTime(const Pattern:string;const s:string;const fmt:TFormatSettings;startpos:integer=1) : tdatetime; overload;
 function ScanDateTime(const Pattern:string;const s:string;startpos:integer=1) : tdatetime; overload;
 
+// ISO 8601 Date/Time formatting
+
+function DateToISO8601(const ADate: TDateTime; AInputIsUTC: Boolean = True): string;
+Function ISO8601ToDate(const DateString: string; ReturnUTC : Boolean): TDateTime;
+Function ISO8601ToDateDef(const DateString: string; ReturnUTC : Boolean; aDefault : TDateTime): TDateTime;
+Function TryISO8601ToDate(const DateString: string; ReturnUTC : Boolean;out ADateTime: TDateTime) : Boolean;
+
+
 implementation
 
 uses sysconst;
@@ -2678,6 +2686,86 @@ begin
     Result := LT;
 end;
 
+Const
+  FmtUTC = 'yyyy"-"mm"-"dd"T"hh":"nn":"ss"."zzz';
+  FmtUTCTZ = 'hh":"mm';
+
+function DateToISO8601(const ADate: TDateTime; AInputIsUTC: Boolean = True): string;
+
+const
+  FmtOffset: string = '%.02d:%.02d';
+  Sign: array[Boolean] of Char = ('+', '-');
+
+var
+  Offset: Integer;
+begin
+  Result := FormatDateTime(FmtUTC, ADate);
+  Offset := GetLocalTimeOffset;
+  if AInputIsUTC or (Offset=0) then
+    Result:=Result+'Z'
+  else
+    begin
+    Result:=Result+Sign[Offset>0];
+    Offset := Abs(Offset);
+    Result:= Result+Format(FmtOffset, [Offset div MinsPerHour, Offset mod MinsPerHour]);
+    end;
+end;
+
+Function TryISO8601ToDate(const DateString: string; ReturnUTC : Boolean;out ADateTime: TDateTime) : Boolean;
+
+
+Var
+  S,TZ : String;
+  Offset,TZOffset : Integer;
+  DTTZ : TDateTime;
+
+begin
+  S:=DateString;
+  If Length(S)>23 then
+    begin
+    S:=Copy(S,1,14);
+    TZ:=Copy(DateString,24);
+    end;
+  aDateTime:=ScanDatetime(fmtUTC,DateString);
+  Result:=aDateTime<>0;
+  if (not Result)  then
+    Exit;
+  // Determine TZ offset. We're forgiving if no TZ info was present.
+  if (TZ='Z') or (TZ='') then
+    TZOffset:=0
+  else
+    begin
+    Result:=TZ[1] in ['+','-'];
+    if Not Result then
+      Exit;
+    DTTZ:=ScanDateTime(FmtUTCTZ,Copy(TZ,2,5));
+    TZOffset:=MinutesBetween(DTTZ,0);
+    if (TZ[1]='+') then
+      TZOffset:=-TZOffset;
+    end;
+  aDateTime:=IncMinute(aDateTime,TZOffSet);
+  // offset for UTC or not
+  if ReturnUTC then
+    Offset:=0
+  else
+    OffSet:=-GetLocalTimeOffset;
+  aDateTime:=IncMinute(aDateTime,Offset);
+end;
+
+Function ISO8601ToDate(const DateString: string; ReturnUTC : Boolean): TDateTime;
+
+begin
+  if not TryISO8601ToDate(DateString,ReturnUTC,Result) then
+    Raise EConvertError.CreateFmt(SErrInvalidTimeStamp,[DateString]);
+end;
+
+Function ISO8601ToDateDef(const DateString: string; ReturnUTC : Boolean; aDefault : TDateTime): TDateTime;
+
+begin
+  if not TryISO8601ToDate(DateString,ReturnUTC,Result) then
+    Result:=aDefault;
+end;
+
 {$else}
 implementation
 {$endif FPUNONE}