diff --git a/wst/trunk/base_service_intf.pas b/wst/trunk/base_service_intf.pas index c613e1bd3..d297b879d 100644 --- a/wst/trunk/base_service_intf.pas +++ b/wst/trunk/base_service_intf.pas @@ -22,7 +22,7 @@ uses {$IFDEF WST_DELPHI} ,Windows {$ENDIF} - ; + , date_utils; const stBase = 0; @@ -323,12 +323,14 @@ type TBaseDateRemotable = class(TAbstractSimpleRemotable) private - FDate : TDateTime; - FYear : Integer; - FMonth : Integer; - FDay : Integer; + FDate : TDateTimeRec; + private + function GetOffset(const Index: Integer): Shortint; + procedure SetOffset(const Index: Integer; const Value: Shortint); + function GetDate(const AIndex : Integer) : TDateTime; protected - procedure SetDate(const AValue: TDateTime);virtual; + function GetDatepart(const AIndex : Integer) : Integer;virtual; + procedure SetDate(const AIndex : Integer; const AValue: TDateTime);virtual; public class procedure Save( AObject : TBaseRemotable; @@ -342,33 +344,33 @@ type var AName : string; const ATypeInfo : PTypeInfo );override; - class function FormatDate(const ADate : TDateTime):string;virtual;abstract; + class function FormatDate(const ADate : TDateTime):string;overload; + class function FormatDate(const ADate : TDateTimeRec):string;overload;virtual;abstract; class function ParseDate(const ABuffer : string):TDateTime;virtual;abstract; procedure Assign(Source: TPersistent); override; function Equal(const ACompareTo : TBaseRemotable) : Boolean;override; - property AsDate : TDateTime read FDate write SetDate; - property Year : Integer read FYear; - property Month : Integer read FMonth; - property Day : Integer read FDay; + property AsDate : TDateTime index 0 read GetDate write SetDate; + property AsUTCDate : TDateTime index 1 read GetDate write SetDate; + property Year : Integer index 0 read GetDatepart; + property Month : Integer index 1 read GetDatepart; + property Day : Integer index 2 read GetDatepart; + property HourOffset : Shortint index 0 read GetOffset write SetOffset; + property MinuteOffset : Shortint index 1 read GetOffset write SetOffset; end; { TDateRemotable } TDateRemotable = class(TBaseDateRemotable) - private - FHour: Integer; - FMinute: Integer; - FSecond: Integer; protected - procedure SetDate(const AValue: TDateTime);override; + function GetDatepart(const AIndex : Integer) : Integer;override; public - class function FormatDate(const ADate : TDateTime):string;override; + class function FormatDate(const ADate : TDateTimeRec):string;override; class function ParseDate(const ABuffer : string):TDateTime;override; - property Hour : Integer read FHour; - property Minute : Integer read FMinute; - property Second : Integer read FSecond; + property Hour : Integer index 3 read GetDatepart; + property Minute : Integer index 4 read GetDatepart; + property Second : Integer index 5 read GetDatepart; end; { TDurationRemotable } @@ -1501,9 +1503,13 @@ var wst_FormatSettings : TFormatSettings; {$ENDIF HAS_FORMAT_SETTINGS} +resourcestring + SERR_InvalidHourOffetValue = '"%d" is not a valid hour offset value.'; + SERR_InvalidMinuteOffetValue = '"%d" is not a valid minute offset value.'; + implementation uses - imp_utils, record_rtti, basex_encode, object_serializer; + imp_utils, record_rtti, basex_encode, object_serializer, DateUtils; type @@ -3006,7 +3012,7 @@ begin i := IndexOf(ADataType); if ( i = -1 ) then begin Result := GetItemClassFor(ADataType).Create(Self,ANameSpace,ADataType,ADeclaredName); - i := Add(Result); + Add(Result); {$IFDEF TRemotableTypeInitializer_Initialize} InitializeItem(Result); {$ENDIF TRemotableTypeInitializer_Initialize} @@ -5210,56 +5216,9 @@ end; { TDateRemotable } -procedure TDateRemotable.SetDate(const AValue: TDateTime); -var - hh, mn, ss, ssss : Word; +class function TDateRemotable.FormatDate(const ADate: TDateTimeRec): string; begin - inherited SetDate(AValue); - DecodeTime(AsDate,hh,mn,ss,ssss); - FHour := hh; - FMinute := mn; - FSecond := ss; -end; - -class function TDateRemotable.FormatDate(const ADate: TDateTime): string; -var - s, buffer : string; - d, m, y : Word; - hh, mn, ss, ssss : Word; -begin - //'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)? - - DecodeDate(ADate,y,m,d); - s := IntToStr(y); - buffer := IntToStr(m); - if ( Length(s) < 4 ) then - s := StringOfChar('0', ( 4 - Length(s) ) ) + s; - if ( m < 10 ) then - buffer := '0' + buffer; - s := Format('%s-%s',[s,buffer]); - - buffer := IntToStr(d); - if ( d < 10 ) then - buffer := '0' + buffer; - s := Format('%s-%s',[s,buffer]); - - DecodeTime(ADate,hh,mn,ss,ssss); - buffer := IntToStr(hh); - if ( hh < 10 ) then - buffer := '0' + buffer; - s := Format('%sT%s',[s,buffer]); - - buffer := IntToStr(mn); - if ( mn < 10 ) then - buffer := '0' + buffer; - s := Format('%s:%s',[s,buffer]); - - buffer := IntToStr(ss); - if ( ss < 10 ) then - buffer := '0' + buffer; - s := Format('%s:%s',[s,buffer]); - - Result := s; + Result := xsd_DateTimeToStr(ADate); end; class function TDateRemotable.ParseDate(const ABuffer: string): TDateTime; @@ -5333,17 +5292,28 @@ begin end; end; +function TDateRemotable.GetDatepart(const AIndex: Integer): Integer; +begin + case AIndex of + 3 : Result := HourOf(AsDate); + 4 : Result := MinuteOf(AsDate); + 5 : Result := SecondOf(AsDate); + else + Result := inherited GetDatepart(AIndex); + end; +end; + { TBaseDateRemotable } -procedure TBaseDateRemotable.SetDate(const AValue: TDateTime); -var - y, m, d : Word; +procedure TBaseDateRemotable.SetDate(const AIndex : Integer; const AValue: TDateTime); begin - DecodeDate(AValue,y,m,d); - FDate := AValue; - FYear := y; - FMonth := m; - FDay := d; + FDate.Date := AValue; + if ( AIndex = 1 ) then begin + if ( FDate.HourOffset <> 0 ) then + FDate.Date := date_utils.IncHour(FDate.Date,FDate.HourOffset); + if ( FDate.MinuteOffset <> 0 ) then + FDate.Date := IncMinute(FDate.Date,FDate.MinuteOffset); + end; end; class procedure TBaseDateRemotable.Save( @@ -5387,7 +5357,7 @@ end; procedure TBaseDateRemotable.Assign(Source: TPersistent); begin if Source.InheritsFrom(TDateRemotable) then begin - FDate := TDateRemotable(Source).AsDate; + FDate := TDateRemotable(Source).FDate; end else begin inherited Assign(Source); end; @@ -5402,6 +5372,61 @@ begin ); end; +function TBaseDateRemotable.GetDate(const AIndex : Integer) : TDateTime; +begin + Result := FDate.Date; + if ( AIndex = 1 ) then begin + if ( FDate.HourOffset <> 0 ) then + Result := date_utils.IncHour(Result,-FDate.HourOffset); + if ( FDate.MinuteOffset <> 0 ) then + Result := date_utils.IncMinute(Result,-FDate.MinuteOffset); + end; +end; + +function TBaseDateRemotable.GetDatepart(const AIndex: Integer): Integer; +begin + case AIndex of + 0 : Result := YearOf(AsDate); + 1 : Result := MonthOf(AsDate); + 2 : Result := DayOf(AsDate); + else + Result := 0; + end; +end; + +function TBaseDateRemotable.GetOffset(const Index: Integer): Shortint; +begin + if ( Index = 0 ) then + Result := FDate.HourOffset + else + Result := FDate.MinuteOffset; +end; + +procedure TBaseDateRemotable.SetOffset(const Index: Integer; const Value: Shortint); +begin + if ( Index = 0 ) then begin + if ( Value >= -14 ) and ( Value <= 14 ) then + FDate.HourOffset := Value + else + raise Exception.CreateFmt(SERR_InvalidHourOffetValue,[Value]); + end else begin + if ( Value >= -59 ) and ( Value <= 59 ) then + FDate.MinuteOffset := Value + else + raise Exception.CreateFmt(SERR_InvalidMinuteOffetValue,[Value]); + end; +end; + +class function TBaseDateRemotable.FormatDate(const ADate: TDateTime): string; +var + locTemp : TDateTimeRec; +begin + locTemp.Date := ADate; + locTemp.HourOffset := 0; + locTemp.MinuteOffset := 0; + Result := FormatDate(locTemp); +end; + { TComplexInt8SContentRemotable } class procedure TComplexInt8SContentRemotable.SaveValue( diff --git a/wst/trunk/date_utils.pas b/wst/trunk/date_utils.pas new file mode 100644 index 000000000..7e62b5974 --- /dev/null +++ b/wst/trunk/date_utils.pas @@ -0,0 +1,215 @@ +{ 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 + SysUtils; + +type + + TDateTimeRec = packed record + Date : TDateTime; + HourOffset : Shortint; + MinuteOffset : Shortint; + end; + + function xsd_TryStrToDate(const AStr : string; out ADate : TDateTimeRec) : Boolean; + function xsd_StrToDate(const AStr : string) : TDateTimeRec; + + function xsd_DateTimeToStr(const ADate : TDateTimeRec) : string;overload; + function xsd_DateTimeToStr(const ADate : TDateTime) : string;overload; + + 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} + +resourcestring + SERR_InvalidDate = '"%s" is not a valid date.'; + +implementation + +uses Math, DateUtils; + +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; + +function xsd_TryStrToDate(const AStr : string; out ADate : TDateTimeRec) : Boolean; +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; + +var + d, m, y : Integer; + hh, mn, ss : Integer; + 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 + Inc(bufferPos); + tz_hh := 0; + tz_mn := 0; + if ( bufferPos > bufferLen ) then begin + hh := 0; + mn := 0; + ss := 0; + ok := True; + end else begin + ok := ( buffer[bufferPos -1] = TIME_MARKER_CHAR ) and ReadInt(hh,TIME_SEP_CHAR); + if ok then begin + Inc(bufferPos); + ok := ReadInt(mn,TIME_SEP_CHAR); + if ok then begin + Inc(bufferPos); + ok := ReadInt(ss,#0); + if ok and ( bufferPos < bufferLen ) then begin + 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 + if ( ( y + m + d + hh + mn + ss ) = 0 ) then + ADate.Date := 0 + else + ADate.Date := EncodeDate(y,m,d) + EncodeTime(hh,mn,ss,0); + 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; + +function xsd_StrToDate(const AStr : string) : TDateTimeRec; +begin + if not xsd_TryStrToDate(AStr,Result) then + raise EConvertError.CreateFmt(SERR_InvalidDate,[AStr]); +end; + +function xsd_DateTimeToStr(const ADate : TDateTimeRec) : string; +var + locDate : TDateTime; + s, buffer : string; + d, m, y : Word; + hh, mn, ss, ssss : Word; +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); + DecodeDate(locDate,y,m,d); + s := IntToStr(y); + buffer := IntToStr(m); + if ( Length(s) < 4 ) then + s := StringOfChar('0', ( 4 - Length(s) ) ) + s; + if ( m < 10 ) then + buffer := '0' + buffer; + s := Format('%s-%s',[s,buffer]); + + buffer := IntToStr(d); + if ( d < 10 ) then + buffer := '0' + buffer; + s := Format('%s-%s',[s,buffer]); + + DecodeTime(locDate,hh,mn,ss,ssss); + buffer := IntToStr(hh); + if ( hh < 10 ) then + buffer := '0' + buffer; + s := Format('%sT%s',[s,buffer]); + + buffer := IntToStr(mn); + if ( mn < 10 ) then + buffer := '0' + buffer; + s := Format('%s:%s',[s,buffer]); + + buffer := IntToStr(ss); + if ( ss < 10 ) then + buffer := '0' + buffer; + s := Format('%s:%s',[s,buffer]); + + Result := s + 'Z'; +end; + +function xsd_DateTimeToStr(const ADate : TDateTime) : string; +var + tmpDate : TDateTimeRec; +begin + FillChar(tmpDate,SizeOf(TDateTimeRec),#0); + tmpDate.Date := ADate; + Result := xsd_DateTimeToStr(tmpDate); +end; + +end. diff --git a/wst/trunk/tests/test_suite/test_date_utils.pas b/wst/trunk/tests/test_suite/test_date_utils.pas new file mode 100644 index 000000000..75364b73a --- /dev/null +++ b/wst/trunk/tests/test_suite/test_date_utils.pas @@ -0,0 +1,256 @@ +{ 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 test_date_utils; + +interface +uses + SysUtils, +{$IFDEF FPC} + fpcunit, testregistry, +{$ELSE} + TestFrameWork, +{$ENDIF} + date_utils; + +type + + TTest_DateUtils = class(TTestCase) + published + procedure xsd_TryStrToDate_date_only(); + procedure xsd_TryStrToDate_date_time(); + procedure xsd_TryStrToDate_date_bad_separator(); + procedure xsd_TryStrToDate_date_time_bad_separator(); + procedure xsd_TryStrToDate_date_time_timezone_z(); + procedure xsd_TryStrToDate_date_time_timezone_zero(); + procedure xsd_TryStrToDate_date_time_timezone_1(); + procedure xsd_TryStrToDate_date_time_timezone_2(); + + procedure xsd_DateTimeToStr_1(); + procedure xsd_DateTimeToStr_2(); + procedure xsd_DateTimeToStr_timezone_1(); + end; + +implementation + +{ TTest_DateUtils } + +procedure TTest_DateUtils.xsd_DateTimeToStr_1(); +const + sDATE_1 = '1976-10-12T23:34:56Z'; + sDATE_2 = '0987-06-12T20:34:56Z'; +var + d : TDateTimeRec; +begin + //'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)? + FillChar(d,SizeOf(d),#0); + d.Date := EncodeDate(1976,10,12) + EncodeTime(23,34,56,0); + CheckEquals(sDATE_1, xsd_DateTimeToStr(d)); + + FillChar(d,SizeOf(d),#0); + d.Date := EncodeDate(987,06,12) - EncodeTime(20,34,56,0); + CheckEquals(sDATE_2, xsd_DateTimeToStr(d)); +end; + +procedure TTest_DateUtils.xsd_DateTimeToStr_2(); +const + sDATE_1 = '1976-10-12T23:34:56Z'; + sDATE_2 = '0987-06-12T20:34:56Z'; +var + d : TDateTime; +begin + d := EncodeDate(1976,10,12) + EncodeTime(23,34,56,0); + CheckEquals(sDATE_1, xsd_DateTimeToStr(d)); + + d := EncodeDate(987,06,12) - EncodeTime(20,34,56,0); + CheckEquals(sDATE_2, xsd_DateTimeToStr(d)); +end; + +procedure TTest_DateUtils.xsd_DateTimeToStr_timezone_1(); + //2002-10-10T12:00:00+05:00 is 2002-10-10T07:00:00Z +var + d : TDateTimeRec; +begin + //'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)? + FillChar(d,SizeOf(d),#0); + d.Date := EncodeDate(2002,10,10) + EncodeTime(12,0,0,0); + d.HourOffset := 5; + CheckEquals('2002-10-10T07:00:00Z', xsd_DateTimeToStr(d)); +end; + +procedure TTest_DateUtils.xsd_TryStrToDate_date_bad_separator(); +const + DATE_STR = '1976;10;12'; +var + d : TDateTimeRec; +begin + CheckEquals(False,xsd_TryStrToDate(DATE_STR,d),Format('"%s" is not a valid date.',[DATE_STR])); +end; + +procedure TTest_DateUtils.xsd_TryStrToDate_date_only(); +var + s : string; + d : TDateTimeRec; + y,m,dy : Word; + hh,mn,ss, ssss : Word; +begin + //'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)? + s := '1976-10-12'; + d := xsd_StrToDate(s); + DecodeDate(d.Date,y,m,dy); + CheckEquals(y,1976,'Year'); + CheckEquals(m,10,'Month'); + CheckEquals(dy,12,'Day'); + DecodeTime(d.Date,hh,mn,ss,ssss); + CheckEquals(hh,0,'Hour'); + CheckEquals(mn,0,'Minute'); + CheckEquals(ss,0,'Second'); + CheckEquals(0,d.HourOffset,'HourOffset'); + CheckEquals(0,d.MinuteOffset,'MinuteOffset'); +end; + +procedure TTest_DateUtils.xsd_TryStrToDate_date_time(); +var + s : string; + d : TDateTimeRec; + y,m,dy : Word; + hh,mn,ss, ssss : Word; +begin + //'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)? + s := '1976-10-12T23:34:56'; + d := xsd_StrToDate(s); + DecodeDate(d.Date,y,m,dy); + CheckEquals(y,1976,'Year'); + CheckEquals(m,10,'Month'); + CheckEquals(dy,12,'Day'); + DecodeTime(d.Date,hh,mn,ss,ssss); + CheckEquals(hh,23,'Hour'); + CheckEquals(mn,34,'Minute'); + CheckEquals(ss,56,'Second'); + CheckEquals(0,d.HourOffset,'HourOffset'); + CheckEquals(0,d.MinuteOffset,'MinuteOffset'); +end; + +procedure TTest_DateUtils.xsd_TryStrToDate_date_time_bad_separator(); +const + DATE_STR = '1976-10-12T23/34:56'; +var + d : TDateTimeRec; +begin + CheckEquals(False,xsd_TryStrToDate(DATE_STR,d),Format('"%s" is not a valid date.',[DATE_STR])); +end; + +procedure TTest_DateUtils.xsd_TryStrToDate_date_time_timezone_1(); +var + s : string; + d : TDateTimeRec; + y,m,dy : Word; + hh,mn,ss, ssss : Word; +begin + //'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)? + s := '1976-10-12T23:34:56+12:34'; + d := xsd_StrToDate(s); + DecodeDate(d.Date,y,m,dy); + CheckEquals(y,1976,'Year'); + CheckEquals(m,10,'Month'); + CheckEquals(dy,12,'Day'); + DecodeTime(d.Date,hh,mn,ss,ssss); + CheckEquals(hh,23,'Hour'); + CheckEquals(mn,34,'Minute'); + CheckEquals(ss,56,'Second'); + CheckEquals(12,d.HourOffset,'HourOffset'); + CheckEquals(34,d.MinuteOffset,'MinuteOffset'); +end; + +procedure TTest_DateUtils.xsd_TryStrToDate_date_time_timezone_2(); +var + s : string; + d : TDateTimeRec; + y,m,dy : Word; + hh,mn,ss, ssss : Word; +begin + //'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)? + s := '1976-10-12T23:34:56-01:23'; + d := xsd_StrToDate(s); + DecodeDate(d.Date,y,m,dy); + CheckEquals(y,1976,'Year'); + CheckEquals(m,10,'Month'); + CheckEquals(dy,12,'Day'); + DecodeTime(d.Date,hh,mn,ss,ssss); + CheckEquals(hh,23,'Hour'); + CheckEquals(mn,34,'Minute'); + CheckEquals(ss,56,'Second'); + CheckEquals(-1,d.HourOffset,'HourOffset'); + CheckEquals(-23,d.MinuteOffset,'MinuteOffset'); +end; + +procedure TTest_DateUtils.xsd_TryStrToDate_date_time_timezone_z(); +var + s : string; + d : TDateTimeRec; + y,m,dy : Word; + hh,mn,ss, ssss : Word; +begin + //'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)? + s := '1976-10-12T23:34:56Z'; + d := xsd_StrToDate(s); + DecodeDate(d.Date,y,m,dy); + CheckEquals(y,1976,'Year'); + CheckEquals(m,10,'Month'); + CheckEquals(dy,12,'Day'); + DecodeTime(d.Date,hh,mn,ss,ssss); + CheckEquals(hh,23,'Hour'); + CheckEquals(mn,34,'Minute'); + CheckEquals(ss,56,'Second'); + CheckEquals(0,d.HourOffset,'HourOffset'); + CheckEquals(0,d.MinuteOffset,'MinuteOffset'); +end; + +procedure TTest_DateUtils.xsd_TryStrToDate_date_time_timezone_zero(); +var + s : string; + d : TDateTimeRec; + y,m,dy : Word; + hh,mn,ss, ssss : Word; +begin + //'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)? + s := '1976-10-12T23:34:56+00:00'; + d := xsd_StrToDate(s); + DecodeDate(d.Date,y,m,dy); + CheckEquals(y,1976,'Year'); + CheckEquals(m,10,'Month'); + CheckEquals(dy,12,'Day'); + DecodeTime(d.Date,hh,mn,ss,ssss); + CheckEquals(hh,23,'Hour'); + CheckEquals(mn,34,'Minute'); + CheckEquals(ss,56,'Second'); + CheckEquals(0,d.HourOffset,'HourOffset'); + CheckEquals(0,d.MinuteOffset,'MinuteOffset'); + + s := '1976-10-12T23:34:56-00:00'; + d := xsd_StrToDate(s); + DecodeDate(d.Date,y,m,dy); + CheckEquals(y,1976,'Year'); + CheckEquals(m,10,'Month'); + CheckEquals(dy,12,'Day'); + DecodeTime(d.Date,hh,mn,ss,ssss); + CheckEquals(hh,23,'Hour'); + CheckEquals(mn,34,'Minute'); + CheckEquals(ss,56,'Second'); + CheckEquals(0,d.HourOffset,'HourOffset'); + CheckEquals(0,d.MinuteOffset,'MinuteOffset'); +end; + +initialization + RegisterTest('Support',TTest_DateUtils.Suite); + +end. diff --git a/wst/trunk/tests/test_suite/test_suite_utils.pas b/wst/trunk/tests/test_suite/test_suite_utils.pas index bb0202ea5..e80762a7b 100644 --- a/wst/trunk/tests/test_suite/test_suite_utils.pas +++ b/wst/trunk/tests/test_suite/test_suite_utils.pas @@ -20,7 +20,7 @@ uses {$ELSE} ,TestFrameWork, xmldom, wst_delphi_xml {$ENDIF} - ,wst_types; + ,wst_types, dateutils; const TestFilesPath = {$IFDEF WST_DELPHI}'.' +{$ENDIF WST_DELPHI}'.' + PathDelim + 'files' + PathDelim; diff --git a/wst/trunk/tests/test_suite/test_support.pas b/wst/trunk/tests/test_suite/test_support.pas index 1908927cf..1ba7193d0 100644 --- a/wst/trunk/tests/test_suite/test_support.pas +++ b/wst/trunk/tests/test_suite/test_support.pas @@ -305,6 +305,13 @@ type procedure ParseDate(); procedure Assign(); procedure Equal(); + procedure AsDate(); + procedure AsUTCDate(); + procedure HourOffset(); + procedure HourOffset_invalid_values(); + procedure MinuteOffset(); + procedure MinuteOffset_invalid_values(); + procedure Year(); end; { TTest_TDurationRemotable } @@ -406,7 +413,7 @@ type end; implementation -uses Math, basex_encode; +uses Math, basex_encode, DateUtils, date_utils; function RandomValue(const AMaxlen: Integer): ansistring; var @@ -2284,6 +2291,173 @@ begin CheckEquals(sDATE, Copy(TDateRemotable.FormatDate(d),1,Length(sDATE))); end; +procedure TTest_TDateRemotable.AsDate(); +var + d : TDateTime; + locObj : TDateRemotable; +begin + d := EncodeDateTime(1976,10,12,13,14,15,0); + locObj := TDateRemotable.Create(); + try + locObj.AsDate := d; + CheckEquals(d, locObj.AsDate); + locObj.HourOffset := 4; + locObj.MinuteOffset := 5; + CheckEquals(d, locObj.AsDate); + + // test while (Hour|Minute)Offset is not null + locObj.HourOffset := 4; + locObj.MinuteOffset := 5; + locObj.AsDate := d; + CheckEquals(d, locObj.AsDate); + finally + locObj.Free(); + end; +end; + +procedure TTest_TDateRemotable.AsUTCDate(); +var + d, dd : TDateTime; + locObj : TDateRemotable; +begin + d := EncodeDateTime(1976,10,12,13,14,15,0); + locObj := TDateRemotable.Create(); + try + locObj.AsUTCDate := d; + CheckEquals(d, locObj.AsUTCDate); + locObj.HourOffset := 4; + locObj.MinuteOffset := 5; + dd := date_utils.IncHour(d,-locObj.HourOffset); + dd := date_utils.IncMinute(dd,-locObj.MinuteOffset); + CheckEquals(dd, locObj.AsUTCDate); + + // test while (Hour|Minute)Offset is not null + locObj.AsUTCDate := dd; + CheckEquals(dd, locObj.AsUTCDate); + finally + locObj.Free(); + end; +end; + +procedure TTest_TDateRemotable.HourOffset(); +var + locObj : TDateRemotable; +begin + locObj := TDateRemotable.Create(); + try + locObj.HourOffset := -5; + CheckEquals(-5, locObj.HourOffset); + locObj.HourOffset := 0; + CheckEquals(0, locObj.HourOffset); + locObj.HourOffset := 1; + CheckEquals(1, locObj.HourOffset); + locObj.HourOffset := 2; + CheckEquals(2, locObj.HourOffset); + finally + locObj.Free(); + end; +end; + +procedure TTest_TDateRemotable.MinuteOffset(); +var + locObj : TDateRemotable; +begin + locObj := TDateRemotable.Create(); + try + locObj.MinuteOffset := -54; + CheckEquals(-54, locObj.MinuteOffset); + locObj.MinuteOffset := 0; + CheckEquals(0, locObj.MinuteOffset); + locObj.MinuteOffset := 20; + CheckEquals(20, locObj.MinuteOffset); + locObj.MinuteOffset := 56; + CheckEquals(56, locObj.MinuteOffset); + finally + locObj.Free(); + end; +end; + +procedure TTest_TDateRemotable.HourOffset_invalid_values(); +var + locObj : TDateRemotable; + + procedure check_invalid_value(const AValue : ShortInt); + var + ok : Boolean; + begin + try + locObj.HourOffset := AValue; + ok := False; + except + ok := True; + end; + Check(ok, Format('"%d" is not a valid hour offset',[AValue])); + end; + +begin + locObj := TDateRemotable.Create(); + try + check_invalid_value(-50); + check_invalid_value(-24); + check_invalid_value(-15); + check_invalid_value(15); + check_invalid_value(24); + check_invalid_value(50); + finally + locObj.Free(); + end; +end; + +procedure TTest_TDateRemotable.MinuteOffset_invalid_values(); +var + locObj : TDateRemotable; + + procedure check_invalid_value(const AValue : ShortInt); + var + ok : Boolean; + begin + try + locObj.MinuteOffset := AValue; + ok := False; + except + ok := True; + end; + Check(ok, Format('"%d" is not a valid minute offset',[AValue])); + end; + +begin + locObj := TDateRemotable.Create(); + try + check_invalid_value(-60); + check_invalid_value(-74); + check_invalid_value(-85); + check_invalid_value(65); + check_invalid_value(74); + check_invalid_value(80); + finally + locObj.Free(); + end; +end; + +procedure TTest_TDateRemotable.Year(); +var + locObj : TDateRemotable; +begin + locObj := TDateRemotable.Create(); + try + locObj.AsDate := EncodeDate(1976,10,12); + CheckEquals(1976, locObj.Year); + locObj.AsDate := EncodeDate(2000,10,12); + CheckEquals(2000, locObj.Year); + locObj.AsDate := EncodeDate(2,10,12); + CheckEquals(2, locObj.Year); + {locObj.AsDate := EncodeDate(-1976,10,12); + CheckEquals(-1976, locObj.Year);} + finally + locObj.Free(); + end; +end; + { TTest_TDurationRemotable } procedure TTest_TDurationRemotable.Clear(); @@ -3361,11 +3535,11 @@ begin end; Check(ok); - aa := ls.Add(); + ls.Add(); ls.Delete(0); CheckEquals(0,ls.Length); - aa := ls.Add(); + ls.Add(); ab := ls.Add(); ls.Delete(0); CheckEquals(1,ls.Length); @@ -3374,7 +3548,7 @@ begin FreeAndNil(ls); ls := TClass_A_CollectionRemotable.Create(); aa := ls.Add(); - ab := ls.Add(); + ls.Add(); ls.Delete(1); CheckEquals(1,ls.Length); CheckSame(aa,ls[0]); diff --git a/wst/trunk/tests/test_suite/wst_test_suite_gui.lpi b/wst/trunk/tests/test_suite/wst_test_suite_gui.lpi index cc270e7c5..578b7f5f0 100644 --- a/wst/trunk/tests/test_suite/wst_test_suite_gui.lpi +++ b/wst/trunk/tests/test_suite/wst_test_suite_gui.lpi @@ -35,7 +35,7 @@ - + @@ -126,6 +126,11 @@ + + + + + diff --git a/wst/trunk/tests/test_suite/wst_test_suite_gui.lpr b/wst/trunk/tests/test_suite/wst_test_suite_gui.lpr index 5f5a7cde3..368e0be83 100644 --- a/wst/trunk/tests/test_suite/wst_test_suite_gui.lpr +++ b/wst/trunk/tests/test_suite/wst_test_suite_gui.lpr @@ -18,7 +18,7 @@ uses test_basex_encode, json_formatter, server_service_json, test_json, test_suite_utils, test_generators, fpcunittestrunner, test_std_cursors, test_rtti_filter, rtti_filters, wst_cursors, test_wst_cursors, test_registry, test_soap_specific, - test_generators_runtime; + test_generators_runtime, test_date_utils; begin Application.Initialize;