我正在尝试编写一个函数,它将(1)在任何时区的机器上运行,(2)计算两个日期之间的小时数,以及(3)将给定时区的DST设置转换为帐户...
看起来很容易,但我似乎无法弄明白。
我正在其他时区生成工作时间表。因此,例如,昨天(2016年11月6日)在纽约,我需要产生25个小时的时间表。今天(2016年11月7日)我只需要生成24小时的时间表。明年3月,将有一天需要23个小时。
我看着这是我的签名,但我想我可能需要一个string TimeZoneId
参数。
public double GetScheduledHours(DateTime begin, DateTime end) {}
我从这里开始:
// incorrectly outputs 24
Console.WriteLine((new DateTime(2016, 11, 7) - new DateTime(2016, 11, 6)).TotalHours);
我接下来尝试了这个,并取得了短暂的成功:
// correctly outputs 25 on a machine whose local time zone is "Eastern Standard Time"
// incorrectly outputs 24 on dotnetfiddle whose local time zone is "Coordinated Universal Time"
var ticks = (new DateTime(2016, 11, 7).ToUniversalTime().Ticks - new DateTime(2016, 11, 6).ToUniversalTime().Ticks;
Console.WriteLine(ticks / 10000 / 1000 / 60 / 60 + " hours");
我尝试使用DateTimeOffset无济于事,并发现了一些奇怪的行为......
// on a machine whose local time zone is Easter Standard Time,
// if you store the DateTime inside of a DateTimeOffset, simple subtraction works fine
var pacificTz = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
DateTime pst6thAsDateTime = pst6th.DateTime;
DateTime pst7thAsDateTime = pst7th.DateTime;
DateTimeOffset pst6thAsDateTimeOffset = pst6th.DateTime;
DateTimeOffset pst7thAsDateTimeOffset = pst7th.DateTime;
// incorrectly outputs 24
Console.WriteLine((pst7thAsDateTime - pst6thAsDateTime).TotalHours);
// correctly outputs 25
// also incorrectly outputs 24 on a machine whose local time zone is not "Eastern Standard Time"
Console.WriteLine((pst7thAsDateTimeOffset - pst6thAsDateTimeOffset).TotalHours);
一些代码的小提示......如果您在本地时区为“东部标准时间”的机器上运行此代码,则只有2个代码失败。
答案 0 :(得分:2)
如果您只想使用本机的本地时区,那么答案非常简单:
var start = new DateTimeOffset(new DateTime(2016, 11, 6));
var end = new DateTimeOffset(new DateTime( 2016, 11, 7));
var hours = (end - start).TotalHours; // 25
但是,如果您感兴趣的时区不是本地时区,那么事情会变得复杂一些。 Jon Skeet's answer here显示了在特定时区找到午夜的解决方案,这应该会有所帮助。
var pacificTz = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
var startLocal = new DateTime(2016, 11, 6);
var startOffset = new DateTimeOffset(startLocal, pacificTz.GetUtcOffset(startLocal));
var endLocal = new DateTime(2016, 11, 7);
var endOffset = new DateTimeOffset(endLocal, pacificTz.GetUtcOffset(endLocal));
var hours = (endOffset - startOffset).TotalHours; // 25
在这种情况下,正如参考答案指出的那样,你应该注意创造不存在的时间!
答案 1 :(得分:-1)
您可以使用IsDaylightSavingTime并使用XOR操作来添加或减去一小时。在我的测试中,我使用德国时区进行测试。也许你必须适应测试日期。我正在使用fluentassertions断言。
[TestFixture]
public class DateTimeScheduleTests
{
public double GetScheduledHours(DateTime begin, DateTime end)
{
var beginIsDaylight = begin.IsDaylightSavingTime();
var endIsDayLight = end.IsDaylightSavingTime();
var diff = 0;
if (beginIsDaylight ^ endIsDayLight)
diff = beginIsDaylight ? -1 : 1;
return (begin - end).TotalHours + diff;
}
[Test]
public void TestDate()
{
var begin = new DateTime(2016, 10, 30);
var end = new DateTime(2016, 10, 29);
GetScheduledHours(begin, end).Should().Be(24);
begin = new DateTime(2016, 10, 31);
end = new DateTime(2016, 10, 30);
GetScheduledHours(begin, end).Should().Be(25);
begin = new DateTime(2017, 3, 26);
end = new DateTime(2017, 3, 25);
GetScheduledHours(begin, end).Should().Be(24);
begin = new DateTime(2017, 3, 27);
end = new DateTime(2017, 3, 26);
GetScheduledHours(begin, end).Should().Be(23);
}
}