如何计算 C# 中两个日期之间我所在时区的实际经过时间?

How can I calculate the acutal elapsed time in my timezone between two dates in C#?

我如何计算两个 DateTime/DateTimeOffset 之间的 实际经过 时间,都在我的时区,采用夏令时,闰年,等等,考虑在内?

例如,以下代码比较 2020 年 3 月 29 日的 00:00 和 05:00 之间的差异,将输出 6 小时的时间跨度(05:00 变为 06:00转换为当地时间,因为夏令时在我的时区开始 02:00,将时钟从 02:00 向前更改为 03:00)。

var timezone = TimeZoneInfo.Local;

var start = new DateTimeOffset(2020, 03, 29, 00, 00, 00, timezone.BaseUtcOffset).LocalDateTime;
var end   = new DateTimeOffset(2020, 03, 29, 05, 00, 00, timezone.BaseUtcOffset).LocalDateTime;

var diff1 = end.Subtract(start);
var diff2 = end - start;

Console.WriteLine(diff1); // 06:00:00
Console.WriteLine(diff2); // 06:00:00

我试图在上面的示例中获得 4 小时 的输出,因为这是 00:00 和 05:00 之间经过的时间。

00:00 -> 01:00 (+ 1 hr)
01:00 -> 02:00 (+ 1 hr)
02:00 -> 03:00 (0)
03:00 -> 04:00 (+ 1 hr)
04:00 -> 05:00 (+ 1 hr)

= 4 hrs

我显然在这里遗漏了一些东西。我读过 Comparisons and arithmetic operations with DateTimeOffset values 但无法理解如何进行此计算。

我知道 NodaTime 可能可以做到这一点,但肯定有一种方法可以在没有外部库的情况下做到这一点?

正如Panagiotis Kanavos指出的那样,

So the offset is wrong. It's no longer the BaseUtcOffset, it's a different one

我找到了 TimeZoneInfo.GetUtcOffset 并使用了它。我认为它可以满足我的要求?时区令人困惑,但至少我现在得到了 4 小时的输出。

var timezone = TimeZoneInfo.Local;

var startTime = new DateTime(2020, 03, 29, 00, 00, 00);
var endTime   = new DateTime(2020, 03, 29, 05, 00, 00);

var startTimeOffset = timezone.GetUtcOffset(startTime);
var endTimeOffset   = timezone.GetUtcOffset(endTime);

var start = new DateTimeOffset(2020, 03, 29, 00, 00, 00, startTimeOffset);
var end   = new DateTimeOffset(2020, 03, 29, 05, 00, 00, endTimeOffset);

var diff1 = end.Subtract(start);
var diff2 = end - start;

Console.WriteLine(diff1); // 04:00:00
Console.WriteLine(diff2); // 04:00:00

很好,如果时区没有提供偏移量,这是正确的方法,假设它可以是任意时区。

但是,如果你使用本地系统时区,你可以简化代码如下:

var start = new DateTimeOffset(new DateTime(2020, 3, 29, 0, 0, 0, DateTimeKind.Local));
var end   = new DateTimeOffset(new DateTime(2020, 3, 29, 5, 0, 0, DateTimeKind.Local));
TimeSpan diff = end - start;

这是有效的,因为 DateTime.Kind 属性 在传递到采用单个 DateTime 参数的 DateTimeOffset 构造函数时被评估。如果是 DateTimeKind.LocalDateTimeKind.Utc,则偏移设置正确。只有在 DateTimeKind.Unspecified 的情况下,偏移量可能不正确(因为它将假定为本地,即使情况并非如此)。 See the remarks in the docs here.