【问题标题】:Lose milliseconds on DateToISO8601在 DateToISO8601 上丢失毫秒
【发布时间】:2023-01-03 22:34:25
【问题描述】:

许多 API 都希望 ISO8601 没有这样的毫秒数:

仅获取在此时间戳之后放置的订单。应采用 YYYY-MM-ddTHH:mm:ssZ 格式

我想主要的“问题”是秒后的点(秒和毫秒之间),必须对点进行 url 编码(http GET 说话),对吗?

SDateFormat: string = 'yyyy''-''mm''-''dd''T''hh'':''nn'':''ss''.''zzz''Z'''; { Do not localize }

我不能失去毫秒。

DateToISO8601(TTimeZone.Local.ToUniversalTime(RecodeMilliSecond(now, 0), false), true)

这是我目前的方法:

var
  utc: TDateTime;
...
  utc := TTimeZone.Local.ToUniversalTime(now);
  utc := RecodeMilliSecond(utc, 0);
  ... Format('/orders?storefront=de&ts_created_from_iso=%sT%sZ', [FormatDateTime('yyyy-mm-dd', utc), FormatDateTime('hh:nn:ss', utc)])

还有其他想法吗?

【问题讨论】:

  • 您提到“URL Encoding the dot”,但这不是需要 URL 编码的字符……这表明您可能正在以不同的方式思考这个问题,这对您的问题的读者来说并不明显。

标签: delphi delphi-10-seattle


【解决方案1】:

如果我没有正确理解你的问题,你想知道如何让DateToISO8601()不输出毫秒,对吗?答案是,你不能。但是,使用 System.Delete()TStringHelper.Remove() 可以很容易地去除毫秒数,因为您知道结果字符串中毫秒的确切偏移量和长度。

var
  utc: TDateTime;
  iso: string;
... 
  utc := TTimeZone.Local.ToUniversalTime(Now);
  iso := DateToISO8601(utc, true);
  Delete(iso, 20, 4);
  ... '/orders?storefront=de&ts_created_from_iso=' + iso;

否则,请坚持使用您的手动方法。但是,您不需要 RecodeMilliseconds(),只需调用 1 次 FormatDateTime() 就足够了:

const
  cISOFormat: string = 'yyyy''-''mm''-''dd''T''hh'':''nn'':''ss''Z''';
var
  utc: TDateTime;
...
  utc := TTimeZone.Local.ToUniversalTime(Now);
  ... '/orders?storefront=de&ts_created_from_iso=' + FormatDateTime(cISOFormat, utc);

【讨论】:

  • RecodeMilliseconds() 是试图丢失毫秒。我想如果没有“真正”的价值,它可能会“消失”。
【解决方案2】:

这是我们使用的例程:

  function DateTimeToXML(dtInput: TDateTime): String;
  var
    fmt: TFormatSettings;
  begin
    // If this will be used in a multithreaded environment then
    // you should use your own TFormatSettings to be thread safe
    fmt:=TFormatSettings.Create();      // initialize, it's on the stack so MUST NOT be freed
    DateTimeToString(Result, 'yyyy-mm-dd''T''hh:nn:ss''Z''',
                     TTimeZone.Local.ToUniversalTime(dtInput), fmt);
  end;

【讨论】:

  • 如果将 -: 字符视为带引号的文字而不是格式占位符,则可以去掉 TFormatSettings,这样格式中的任何内容都不会依赖于区域设置。
【解决方案3】:

您可以从 System.DateUtils 复制函数 DateToISO8601 并将其更改为:

function [MyClassName].DateToISO8601(const ADate: TDateTime; AInputIsUTC: Boolean = true): string;
const
  SDateFormat: string = '%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ'; { Do not localize }
  SOffsetFormat: string = '%s%s%.02d:%.02d'; { Do not localize }
  Neg: array[Boolean] of string = ('+', '-'); { Do not localize }
var
  y, mo, d, h, mi, se, ms: Word;
  Bias: Integer;
  TimeZone: TTimeZone;
begin
  DecodeDate(ADate, y, mo, d);
  DecodeTime(ADate, h, mi, se, ms);
  Result := Format(SDateFormat, [y, mo, d, h, mi, se]);
  if not AInputIsUTC then
  begin
    TimeZone := TTimeZone.Local;
    Bias := Trunc(TimeZone.GetUTCOffset(ADate).Negate.TotalMinutes);
    if Bias <> 0 then
    begin
      // Remove the Z, in order to add the UTC_Offset to the string.
      SetLength(Result, Result.Length - 1);
      Result := Format(SOffsetFormat, [Result, Neg[Bias > 0], Abs(Bias) div 
MinsPerHour,
        Abs(Bias) mod MinsPerHour]);
    end
  end;
end;

【讨论】:

    猜你喜欢
    • 2015-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多