如何在不添加然后减去偏移量的情况下将字符串+偏移值转换为 DateTimeOffset?

How do I convert a string+offset value to a DateTimeOffset without adding-then-subtracting the offset?

提问人:Jacob Stamm 提问时间:11/9/2023 最后编辑:DaiJacob Stamm 更新时间:11/13/2023 访问量:49

问:

我们的应用程序与一个 API 交互,该 API 以以下格式返回本地日期时间字符串,该字符串带有一个辅助数字字段,指示以小时为单位的 UTC 偏移量。yyyyMMdd HH:mm

我们通过以下代码成功处理了此问题。

DateTimeOffset ParseWeirdDateTime(string dateTimeString, double utcOffset)
{
    DateTimeOffset dateTimeOffset = DateTimeOffset.ParseExact(
        dateTimeString,
        "yyyyMMdd HH:mm",
        CultureInfo.InvariantCulture,
        DateTimeStyles.AssumeUniversal
    );

    return dateTimeOffset.AddHours(-utcOffset).ToOffset(TimeSpan.FromHours(utcOffset));
}

string localDateTimeString = "20231108 14:30";
double utcOffset = -4;
DateTimeOffset dateTimeParsed = ParseWeirdDateTime(localDateTimeString, utcOffset);
// comes out to 11/8/2023 2:30:00 PM -04:00

我的问题是,有没有更好的方法来解决这个问题?尽管这可行,但解析为 UTC DateTimeOffset 感觉很笨拙,只是应用偏移量的倒数并最终转换为偏移量。

. .net-core

评论


答:

1赞 Dai 11/9/2023 #1
  • 你说你的输入字符串代表一个“本地”(或者更确切地说:非UTC)时刻,但是......yyyyMMdd HH:mm
    • 即使输入字符串不表示元组,您仍在使用:字符串仅表示元组。DateTimeOffset.ParseExactDate+Time+OffsetDate+Time+Undefined-Offset
      • 因此,请改用,并确保它有(因为此时没有指定偏移数据)。DateTime.ParseExactDateTimeKind.Unspecified
      • (顺便说一句,从不使用:它特指本地计算机的时间,这在业务应用程序中几乎总是无用的,因为它不像真正的UTC那样是不变的:考虑本地时区,政治时区变化,夏令时,机器配置错误等)。DateTimeKind.Local
    • 此外,您错误地使用了 ,这在这里不适用,因为您传入的字符串不表示 UTC 值。正如文档所述,“如果在解析的字符串中未指定时区,则假定该字符串表示 UTC。DateTimeStyles.AssumeUniversal"

我会这样做:

  • 由于该值仅表示没有偏移量的日期+时间值,因此我使用而不是 .dateTimeStringDateTime.ParseExactDateTimeOffset.ParseExact
  • 此处使用方式不正确。DateTimeStyles.NoneAssumeUniversal
  • 然后我通过 ctor 将值调整 a。DateTimeDateTimeOffset

/// <summary><see href="https://stackoverflow.com/a/77449580/159145" /></summary>
static DateTimeOffset ParseWeirdDateTime( String dateTimeString, Double utcOffsetInHours /* Always specify units in names when using dimensionless types */ )
{
    DateTime instantInTimeWithUndefinedOffset = DateTime.ParseExact(
        s       : dateTimeString,
        format  : "yyyyMMdd HH:mm",
        provider: CultureInfo.InvariantCulture,
        style   : DateTimeStyles.None
    );
    
    Debug.Assert( instantInTimeWithUndefinedOffset.Kind == DateTimeKind.Unspecified );

    return new DateTimeOffset( instantInTimeWithUndefinedOffset, offset: TimeSpan.FromHours( utcOffsetInHours ) );
}

评论

0赞 Jacob Stamm 11/14/2023
我喜欢。这与我的方法类似,但意图要明确得多。