首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >TXSDateTime错误“位于DST之前缺失期间内的本地时间”

TXSDateTime错误“位于DST之前缺失期间内的本地时间”
EN

Stack Overflow用户
提问于 2017-03-30 13:37:35
回答 2查看 2.5K关注 0票数 1

通过将TTimeZone.Local.UTCOffset (现在为2小时)添加到TDateTime中,我们将本地日期(没有时间部分)转换为期望UTC日期时间字符串的外部系统。

在我们切换到DST的晚上( 02:00),此操作失败。

来自System.RTLConst的错误

代码语言:javascript
运行
复制
SLocalTimeInvalid = 'The given "%s" local time is invalid (situated within the missing period prior to DST).';

发生在System.DateUtils

代码语言:javascript
运行
复制
function TTimeZone.GetUtcOffsetInSeconds(const ADateTime: TDateTime; const ForceDaylight: Boolean): Int64;
var
  LOffset, LDSTSave: Int64;
  LType: TLocalTimeType;
begin
  { Obtain the information we require }
  DoGetOffsetsAndType(ADateTime, LOffset, LDSTSave, LType);

  { Select the proper offset }
  if (LType = lttInvalid) then
    raise ELocalTimeInvalid.CreateResFmt(@SLocalTimeInvalid, [DateTimeToStr(ADateTime)])
  else if (LType = lttDaylight) or ((LType = lttAmbiguous) and ForceDaylight) then
    Result := LOffset + LDSTSave
  else
    Result := LOffset;
end;

代码复制

代码语言:javascript
运行
复制
function DateTime2UTCString(ADateTime: TDateTime): String;
var XSD: TXSDateTime;
begin
  XSD := TXSDateTime.Create;
  try
    try
      XSD.AsDateTime := ADateTime;
      Result := XSD.NativeToXS;
    except
      on E:Exception do
        Result := E.Message;
    end;
  finally
     XSD.Free;
  end;
end;

function Date2UTCString(ADateTime: TDateTime): String;
// Input is guaranteed to have no time fraction
begin
  ADateTime := ADateTime + TTimeZone.Local.UTCOffset;
  Result := DateTime2UTCString(ADateTime);
end;

procedure TFrmUTCandDST.Button1Click(Sender: TObject);
var
  lDT: TDateTime;
  l  : integer;
begin
  lDT := EncodeDate(2016,3,25);
  for l := 0 to 2 do
  begin
    lDT := lDT +1;
    Memo1.Lines.Add(DateToStr(lDT) + ' -> ' + Date2UTCString(lDT));
  end;
end;

(不要忘记使用SOAP.XSBuiltIns, System.DateUtils, System.TimeSpan)。

输出:

代码语言:javascript
运行
复制
26-3-2016 -> 2016-03-26T02:00:00.000+01:00
27-3-2016 -> The given "27-3-2016 2:00:00" local time is invalid (situated within the missing period prior to DST).
28-3-2016 -> 2016-03-28T02:00:00.000+02:00

我怎么才能宽宏大量地避开这一切呢?我可以使用TTimeZone.Local.IsInvalidTime(ADateTime)来检测无效的日期,,但是 26-3-2016 2:00:00可能是错误的(这正是我们移到DST的时间),而不是 27-3-2016 2:00:00,所以我不知道如何在“无效”日期的情况下进行调整。

EN

回答 2

Stack Overflow用户

发布于 2017-03-30 15:30:30

还有单元System.DateUtils.pas中的错误 (afaik仍然存在于10.1中)。

函数AdjustDateTime首先将处理它的日期和时间作为本地时间,然后尝试将偏移量放入其中。因为在夏令期间有一个“失踪时间”(如果是中欧,是26.03.2017),所以在凌晨1:59:59之后,你有凌晨3:00的时间。

如果您意外地使用了这个句点(比如2:17:35),您将得到一个异常。

这也存在于其他职能中。

复制异常(C++)的简单代码:

代码语言:javascript
运行
复制
ShowMessage(ISO8601ToDate("2017-03-26T02:22:50.000Z",false));

但这个还行:

代码语言:javascript
运行
复制
ShowMessage(ISO8601ToDate("2017-03-26T02:22:50.000Z",true));`

现在要避免异常,请使用XSD.AsUTCDateTime,然后应用本地偏移量。c++中的示例:

代码语言:javascript
运行
复制
 TTimeZone * localTz = TTimeZone::Local;
 TDateTime TimeSomething = localTz->ToLocalTime(XSD->AsUTCDateTime);

在您的情况下,要么本地时间确实无效(没有"2:00"),要么您试图将UTC时间视为本地时间,这当然是无效的。解决这个问题,你就能解决你的问题。

我怎么才能宽宏大量地避开这一切呢?我可以使用TTimeZone.Local.IsInvalidTime(ADateTime)检测无效日期,但26-3-2016 2:00:00将是错误的(这正是我们搬到DST的时间),而不是27-3-2016 2:00--所以我不知道如何调整以防止“无效”日期。

另外,我想你错过了2016年我们在2:00的时候搬到DST,而今年的26-03,所以27-3-2016 2:00是完全无效的日期:)

票数 2
EN

Stack Overflow用户

发布于 2020-03-06 21:57:32

正如@Vancalar所说,当ISO8601ToDate从UTC转换到当地时间时,在DST转换过程中出现了一个错误。这个错误在里约10.3.3.中仍然存在。

一个简单的解决方法是避免ISO8601ToDate的时区转换,让微软来完成它。也就是说,用true替换false值,然后调用UTCToTZLocalTime,如下所示:

代码语言:javascript
运行
复制
// Get UTC datetime from ISO8601 string
datetime := ISO8601ToDate(ISO8601UTCstring, true);
// Convert to local time w/DST conversion
datetime := UTCToTZLocalTime(zoneinfo,datetime);  
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43119566

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档