从 DateTimeOffset 中删除时区偏移量?

Remove Time Zone Offset from DateTimeOffset?

此代码:

DateTimeOffset testDateAndTime =
    new DateTimeOffset(2008, 5, 1, 8, 6, 32, new TimeSpan(1, 0, 0));

//CLEAN TIME AND DATE 
testDateAndTime = testDateAndTime.DateTime.Date; 

var datesTableEntry = db.DatesTable.First(dt => dt.Id == someTestId);
datesTableEntry.test= testDateAndTime;

db.SaveChangesAsync(); 

...在我的数据库中产生这个结果:2008-05-01 00:00:00.0000000 -04:00

我应该如何修改我的代码,以便它在 testDateAndTime 中将时区偏移量从 -4:00 更改为 +00:00

我也试过:

public Task<DateTimeOffset> SetTimeZoneOffsetToZero(DateTimeOffset dateTimeOffSetObj)
{
    TimeSpan zeroOffsetTimeSpan = new TimeSpan(0, 0, 0, 0, 0);
    return dateTimeOffSetObj.ToOffset(zeroOffsetTimeSpan);
}

...但是该代码没有任何作用。

我的最终目标只是有一个没有时间或时区偏移的日期。我想要将时间转换为另一个时区。 (也就是说,我不想从00:00:00.0000000时间中减去4小时并删除设置时间偏移量到+00:00。我只是想要设置偏移量到 +00:00.)

这是我在其他地方遇到的另一种方法:

DateTimeOffset testDateAndTime =
    new DateTimeOffset(2008, 5, 1, 8, 6, 32, new TimeSpan(1, 0, 0));

testDateAndTime = testDateAndTime.DateTime.Date; //Zero out time portion

testDateAndTime = DateTime.SpecifyKind(
    testDateAndTime.Date, DateTimeKind.Utc); //"Zero out" offset portion

我确信 SpecifyKind 转换 我的 DateTimeOffset。即,同时更改时间时区偏移。但是,我的测试表明此代码 只是 更改了时区偏移量,这正是我想要的。这样做有问题吗?

这个问题实际上与数据库没有任何关系。如果您设置断点或在某处记录输出,您应该能够在这段代码后不久看到偏移量:

testDateAndTime = testDateAndTime.DateTime.Date;

让我们分解一下:

  • 您的 DateTimeOffset 值为 2008-05-01T08:06:32+01:00
  • 然后您调用了 .DateTime,结果 DateTime 值为 2008-05-01T08:06:32DateTimeKind.Unspecified
  • 然后您调用了 .Date,结果 DateTime 值为 2008-05-01T00:00:00DateTimeKind.Unspecified
  • 您将结果分配回 testDateAndTime,其类型为 DateTimeOffset。这会调用从 DateTimeDateTimeOffset - 的隐式转换,它应用 local 时区 。在您的情况下,该值在您当地时区的偏移量似乎是 -04:00,因此结果值是 2008-05-01T00:00:00-04:00DateTimeOffset,如您所述。

你说:

End goal is just to have a date without time or time zone offset.

好吧,目前 没有本机 C# 数据类型只是没有时间的日期。 corefxlab, but that's not quite ready for the typical production application. There's LocalDate in the Noda Time 库中的 System.Time 包中有一个纯 Date 类型,您今天可以使用,但您仍然需要转换回来在保存到数据库之前转换为本机类型。所以与此同时,你能做的最好的事情是:

  • 更改您的 SQL 服务器以在字段中使用 date 类型。
  • 在您的 .NET 代码中,使用时间为 00:00:00DateTimeKind.UnspecifiedDateTime。您必须记住忽略时间部分(因为在某些时区确实有没有当地午夜的日期)。
  • 将您的 test 道具更改为 DateTime,而不是 DateTimeOffset

一般来说,虽然 DateTimeOffset 适合大量场景(例如 timestamping 事件),但它不适用于仅日期值。

I want the current date, with zero offset.

如果你真的想要这个作为DateTimeOffset,你会这样做:

testDateAndTime = new DateTimeOffset(testDateAndTime.Date, TimeSpan.Zero);

但是,我反对这样做。通过这样做,您将获取原始值的 local 日期并断言它采用 UTC。如果原始偏移量不是零,那将是一个错误的断言。以后肯定会导致其他错误,因为您实际上谈论的是与您创建的时间点不同的时间点(可能有不同的日期)。

关于您在编辑中提出的其他问题 - 指定 DateTimeKind.Utc 会更改隐式转换的行为。它不使用本地时区,而是使用 UTC 时间,它的偏移量始终为零。结果与我上面给出的更明确的形式相同。出于同样的原因,我仍然反对这样做。

考虑一个以 2016-12-31T22:00:00-04:00 开头的例子。通过您的方法,您将保存到数据库 2016-12-31T00:00:00+00:00。然而,这是两个截然不同的时间点。第一个标准化为 UTC 的是 2017-01-01T02:00:00+00:00,第二个转换为其他时区的是 2016-12-30T20:00:00-04:00。注意转换中日期的变化。这可能不是您希望潜入您的应用程序的行为。