如何从 UTC 获取日期时间的偏移量?
How to get a datetime's offset from UTC?
给定 “本地” 的日期时间(即没有时区信息),例如:
| Datetime |
|---------------------|
| 2019-01-21 09:00:00 |
| 2019-02-21 09:00:00 |
| 2019-03-21 09:00:00 |
| 2019-04-21 09:00:00 |
| 2019-05-21 09:00:00 |
| 2019-06-21 09:00:00 |
| 2019-07-21 09:00:00 |
| 2019-08-21 09:00:00 |
| 2019-09-21 09:00:00 |
| 2019-10-21 09:00:00 |
| 2019-11-21 09:00:00 |
| 2019-12-21 09:00:00 |
我怎样才能得到该日期与 UTC 的偏移量? (假设机器本地时区信息)
例如,我的本地 PC 处于 东部 时区。 东部时区是:
- 300 分钟(5 小时)落后于 UTC
- 240 分钟(4 小时)落后于 UTC
取决于“夏令时”是否在该日期时间生效。
这意味着上面的列表:
| Datetime | Offset from UTC (minutes) |
|---------------------|----------------------------|
| 2019-01-21 09:00:00 | -300 (-5 hours) |
| 2019-02-21 09:00:00 | -300 (-5 hours) |
| 2019-03-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-04-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-05-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-06-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-07-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-08-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-09-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-10-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-11-21 09:00:00 | -300 (-5 hours) |
| 2019-12-21 09:00:00 | -300 (-5 hours) |
当然,如果日期 are from before 2007,这些偏移量也会改变,答案也会改变:
| Datetime | Offset from UTC (minutes) |
|---------------------|----------------------------|
| 2006-01-21 09:00:00 | -300 (-5 hours) |
| 2006-02-21 09:00:00 | -300 (-5 hours) |
| 2006-03-21 09:00:00 | -240 (-5 hours) |
| 2006-04-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-05-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-06-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-07-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-08-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-09-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-10-21 09:00:00 | -240 (-5 hours) |
| 2006-11-21 09:00:00 | -300 (-5 hours) |
| 2006-12-21 09:00:00 | -300 (-5 hours) |
在 1977 年的能源危机期间,答案又会有所不同,因为国家 运行 全年实行夏令时:
| Datetime | Offset from UTC (minutes) |
|---------------------|----------------------------|
| 1977-01-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-02-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-03-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-04-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-05-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-06-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-07-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-08-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-09-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-10-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-11-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-12-21 09:00:00 | -240 (-4 hours) | Daylight savings
并且 before 1966 答案有一些变化。
Windows 知道所有这些事情。
所以问题是:
- 给定
FILETIME
格式的日期时间
- 假定为当前PC的时区
- 我怎样才能得到日期时间与 UTC 的偏移量
- 在日期时间
换句话说:
//Pesudocode. It may look like C#, but i'm using the native Win32 api
Int32 GetDateTimeMinutesOffsetFromUTC(DateTime value)
{
//2006-03-21 09:00:00 ==> -300
//2007-03-21 09:00:00 ==> -240
return -1; //todo
}
或
function GetDateTimeMinutesOffsetFromUtc(Value: TDateTime): Integer;
begin
//2006-03-21 09:00:00 ==> -300
//2007-03-21 09:00:00 ==> -240
Result := -1; //todo
end;
或
int GetDateTimeMinutesOffsetFromUtc(FILETIME value)
{
//2006-03-21 09:00:00 ==> -300
//2007-03-21 09:00:00 ==> -240
Result := -1; //todo
}
提醒一下,我使用的是 Win32 api。
- 这不是 C/C++(即我无权访问 C 标准库)
- 这不是 C#(即我无权访问 .NET Framework Class 库)
- 这不是 Java(即我无权访问 Java Class 图书馆)
- 这不是Python
- 这不是 Javascript、React、Rust、Django
我说的是 Windows 和 Win32 API.
SQL 服务器
以上工作可以在SQL服务器中看到:
SELECT
EventDate,
DATEDIFF(minute, CAST(EventDate AS datetime) AT TIME ZONE 'Eastern Standard Time', EventDate) AS MinutesOffsetFromUTC
FROM (VALUES
('2019-01-21 09:00:00.000'),
('2019-02-21 09:00:00.000'),
('2019-03-21 09:00:00.000'),
('2019-04-21 09:00:00.000'),
('2019-05-21 09:00:00.000'),
('2019-06-21 09:00:00.000'),
('2019-07-21 09:00:00.000'),
('2019-08-21 09:00:00.000'),
('2019-09-21 09:00:00.000'),
('2019-10-21 09:00:00.000'),
('2019-11-21 09:00:00.000'),
('2019-12-21 09:00:00.000')
) foo(EventDate)
EventDate MinutesOffsetFromUTC
----------------------- --------------------
2019-01-21 09:00:00.000 -300
2019-02-21 09:00:00.000 -300
2019-03-21 09:00:00.000 -240
2019-04-21 09:00:00.000 -240
2019-05-21 09:00:00.000 -240
2019-06-21 09:00:00.000 -240
2019-07-21 09:00:00.000 -240
2019-08-21 09:00:00.000 -240
2019-09-21 09:00:00.000 -240
2019-10-21 09:00:00.000 -240
2019-11-21 09:00:00.000 -300
2019-12-21 09:00:00.000 -300
(12 rows affected)
研究工作
大多数 Winapi 函数用于将 "local" 转换为 "UTC",然后再返回,不要'考虑相关日期;但只使用 whether daylight savings is in effect right now:
Functions like FileTimeToLocalFileTime apply the current Daylight Savings Time (DST) bias rather than the bias that was in effect at the time in question.
其他人考虑转换的日期,但只看现在的夏令时开始和结束规则 - 而不是当时的规则。
但是 TzSpecificLocalTimeToSystemTime 是 理解日期时间和夏令时的一个函数:
TzSpecificLocalTimeToSystemTime takes into account whether daylight saving time (DST) is in effect for the local time to be converted.
实际上 Windows 并不知道 一切 。它在注册表中保留历史 “夏令时” 日期的数据库:
所以对我来说它真正知道的是
- 2007年巨变前
- 及之后
但这对我的用例来说已经足够好了。它是 good enough for SQL Server.
红利阅读
好的,时效已过。我给了每个人自己回答问题的机会,提供了各种提示,这样别人就可以得到甜蜜的声誉。
那个时代已经过去了。现在是回答问题的时候了because it's what Joel and Jeff would have wanted.
伪代码:
int GetDateTimeOffsetFromUtcMinutes(DateTime localDateTime)
{
//All code on Whosebug is public domain; no attribution is ever required.
/*
Given a datetime, tell me how many minutes offset it was from UTC.
2006-03-21 09:00:00 ==> -300 (before daylight savings rules changed)
2007-03-21 09:00:00 ==> -240
The problem is that we don't want to use the current setting of Daylight Savings or not.
We want use if daylight savings was in effect *at the date* being supplied.
And we can't even use the current rules:
- Second Sunday in March: spring forward (e.g. 3/14/2021 2:00 AM)
- First Sunday in November: fall back (e.g. 11/7/2021 2:00 AM)
because those are the rules today.
We need to use the rules that were in effect of the date we are considering.
- e.g. the rules changed in 2007. If we have an OrderDate from 2006, we need those older rules.
Also notice that some dates have two answers:
11/7/2021 1:45 AM: EDT (-4 hours)
11/7/2021 1:45 AM: EST (-5 hours, because at 2am we fallback to 1am, and encounter 1:45AM again, but this time as Standard time)
So which one do we return? Whatever one i feel like. That's the price you pay for not using UTC or datetime's with an offset.
*/
//Convert the date to a SYSTEM_TIME structure so we can call the Win32 API
SYSTEM_TIME stLocal;
DateTimeToSystemTime(LocalDateTime, out stLocal);
SYSTEM_TIME stUtc;
if (!TzSpecificLocalTimeToSystemTime(null, stLocal, out stUtc))
RaiseLastWin32Error();
//We now have both "local" and "utc" as a SYSTEM_TIME.
//Convert both to FILETIME so we can subtract them.
FILETIME ftLocal, ftUtc;
if (!SystemTimeToFileTime(stLocal, out ftLocal))
RaiseLastWin32Error();
if (!SystemTimeToFileTime(stUtc, out ftUtc))
RaiseLastWin32Error();
//Convert the FILETIMEs into Int64s.
//We do this because, as you know, you cannot access FILE_TIME structure
//as an 64-bit integer, even though it is two 32-bit integers back to back.
LARGE_INTEGER ulLocal, ulUtc;
ulLocal.LowPart = ftLocal.dwLowDateTime;
ulLocal.HighPart = ftLocal.dwHighDatetime;
ulUtc.LowPart = ftUtc.dwLowDateTime;
ulUtc.HighPart = ftUtc.dwHighDatetime;
//Now subtract the quadparts
Int64 delta = ulLocal.QuadPart - ulUtc.QuadPart;
//That delta is in 100ns intervals (0.00001 sec). We want it in whole minutes;
// 100 ns
// 0.1 us
// 0.0001 ms
// 0.0000001 s
delta = delta div 10000000; //100 ns ==> seconds (div is integer division)
delta = delta div 60; //seconds ==> minutes
return delta;
}
然后,当然,没有测试用例,任何功能都是不完整的
//After the Daylight Savings rule change of of 2007
Test("2019-01-21T09:00:00", -300); // (-5 hours) |
Test("2019-02-21T09:00:00", -300); // (-5 hours) |
Test("2019-03-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-04-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-05-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-06-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-07-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-08-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-09-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-10-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-11-21T09:00:00", -300); // (-5 hours) |
Test("2019-12-21T09:00:00", -300); // (-5 hours) |
//Before the Daylight Savings rule change of 2007
Test("2006-01-21T09:00:00", -300); // (-5 hours) |
Test("2006-02-21T09:00:00", -300); // (-5 hours) |
Test("2006-03-21T09:00:00", -300); // (-5 hours) | What what?
Test("2006-04-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-05-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-06-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-07-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-08-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-09-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-10-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-11-21T09:00:00", -300); // (-5 hours) |
Test("2006-12-21T09:00:00", -300); // (-5 hours) |
//Testing spring-forward. Spring forward March 14, 2021 at 2:00 AM
//The weirdness here is that the time from 2:00:00..2:59:59 doesn't exist.
Test("2021-03-14T00:00:00", -300); // EST
Test("2021-03-14T00:59:59", -300); // EST
Test("2021-03-14T01:00:00", -300); // EST
Test("2021-03-14T01:59:00", -300); // EST
Test("2021-03-14T02:00:00", -240); // There is no March 14, 2021 2am - it doesn't exist. The clock goes from 1:59:59 am --> 3:00:00 am. The function does return 240. TODO: figure out why it returns 240
Test("2021-03-14T02:59:59", -240); // There is no March 14, 2021 2:59am - it doesn't exist.
Test("2021-03-14T03:00:00", -240); // EDT
//Testing fall-back. Fall back March 14, 2021 at 2:00 AM
//The weirdness here is that 1:30 AM exists twice.
//12:00 AM -> 12:59:59 AM -> [1:00 AM -> 1:59:59 AM --> 1:00 AM -> 1:59:59 AM] -> 2:00 AM
//So there's no way to know if 11/7/2021 1:30 AM was EDT or EST - both are correct, because it actually did happen twice.
Test("2021-11-07T00:00:00", -240); // EDT
Test("2021-11-07T00:59:59", -240); // EDT
Test("2021-11-07T01:00:00", -240); // EDT (and EST!)
Test("2021-11-07T01:59:59", -240); // EDT (and EST!)
//Test("2021-11-07T01:00:00", -300); // EST (and EDT!)
//Test("2021-11-07T01:59:59", -300); // EST (and EDT!)
Test("2021-11-07T02:00:00", -300); // EST
给定 “本地” 的日期时间(即没有时区信息),例如:
| Datetime |
|---------------------|
| 2019-01-21 09:00:00 |
| 2019-02-21 09:00:00 |
| 2019-03-21 09:00:00 |
| 2019-04-21 09:00:00 |
| 2019-05-21 09:00:00 |
| 2019-06-21 09:00:00 |
| 2019-07-21 09:00:00 |
| 2019-08-21 09:00:00 |
| 2019-09-21 09:00:00 |
| 2019-10-21 09:00:00 |
| 2019-11-21 09:00:00 |
| 2019-12-21 09:00:00 |
我怎样才能得到该日期与 UTC 的偏移量? (假设机器本地时区信息)
例如,我的本地 PC 处于 东部 时区。 东部时区是:
- 300 分钟(5 小时)落后于 UTC
- 240 分钟(4 小时)落后于 UTC
取决于“夏令时”是否在该日期时间生效。
这意味着上面的列表:
| Datetime | Offset from UTC (minutes) |
|---------------------|----------------------------|
| 2019-01-21 09:00:00 | -300 (-5 hours) |
| 2019-02-21 09:00:00 | -300 (-5 hours) |
| 2019-03-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-04-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-05-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-06-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-07-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-08-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-09-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-10-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2019-11-21 09:00:00 | -300 (-5 hours) |
| 2019-12-21 09:00:00 | -300 (-5 hours) |
当然,如果日期 are from before 2007,这些偏移量也会改变,答案也会改变:
| Datetime | Offset from UTC (minutes) |
|---------------------|----------------------------|
| 2006-01-21 09:00:00 | -300 (-5 hours) |
| 2006-02-21 09:00:00 | -300 (-5 hours) |
| 2006-03-21 09:00:00 | -240 (-5 hours) |
| 2006-04-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-05-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-06-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-07-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-08-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-09-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 2006-10-21 09:00:00 | -240 (-5 hours) |
| 2006-11-21 09:00:00 | -300 (-5 hours) |
| 2006-12-21 09:00:00 | -300 (-5 hours) |
在 1977 年的能源危机期间,答案又会有所不同,因为国家 运行 全年实行夏令时:
| Datetime | Offset from UTC (minutes) |
|---------------------|----------------------------|
| 1977-01-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-02-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-03-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-04-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-05-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-06-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-07-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-08-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-09-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-10-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-11-21 09:00:00 | -240 (-4 hours) | Daylight savings
| 1977-12-21 09:00:00 | -240 (-4 hours) | Daylight savings
并且 before 1966 答案有一些变化。
Windows 知道所有这些事情。
所以问题是:
- 给定
FILETIME
格式的日期时间 - 假定为当前PC的时区
- 我怎样才能得到日期时间与 UTC 的偏移量
- 在日期时间
换句话说:
//Pesudocode. It may look like C#, but i'm using the native Win32 api
Int32 GetDateTimeMinutesOffsetFromUTC(DateTime value)
{
//2006-03-21 09:00:00 ==> -300
//2007-03-21 09:00:00 ==> -240
return -1; //todo
}
或
function GetDateTimeMinutesOffsetFromUtc(Value: TDateTime): Integer;
begin
//2006-03-21 09:00:00 ==> -300
//2007-03-21 09:00:00 ==> -240
Result := -1; //todo
end;
或
int GetDateTimeMinutesOffsetFromUtc(FILETIME value)
{
//2006-03-21 09:00:00 ==> -300
//2007-03-21 09:00:00 ==> -240
Result := -1; //todo
}
提醒一下,我使用的是 Win32 api。
- 这不是 C/C++(即我无权访问 C 标准库)
- 这不是 C#(即我无权访问 .NET Framework Class 库)
- 这不是 Java(即我无权访问 Java Class 图书馆)
- 这不是Python
- 这不是 Javascript、React、Rust、Django
我说的是 Windows 和 Win32 API.
SQL 服务器
以上工作可以在SQL服务器中看到:
SELECT
EventDate,
DATEDIFF(minute, CAST(EventDate AS datetime) AT TIME ZONE 'Eastern Standard Time', EventDate) AS MinutesOffsetFromUTC
FROM (VALUES
('2019-01-21 09:00:00.000'),
('2019-02-21 09:00:00.000'),
('2019-03-21 09:00:00.000'),
('2019-04-21 09:00:00.000'),
('2019-05-21 09:00:00.000'),
('2019-06-21 09:00:00.000'),
('2019-07-21 09:00:00.000'),
('2019-08-21 09:00:00.000'),
('2019-09-21 09:00:00.000'),
('2019-10-21 09:00:00.000'),
('2019-11-21 09:00:00.000'),
('2019-12-21 09:00:00.000')
) foo(EventDate)
EventDate MinutesOffsetFromUTC
----------------------- --------------------
2019-01-21 09:00:00.000 -300
2019-02-21 09:00:00.000 -300
2019-03-21 09:00:00.000 -240
2019-04-21 09:00:00.000 -240
2019-05-21 09:00:00.000 -240
2019-06-21 09:00:00.000 -240
2019-07-21 09:00:00.000 -240
2019-08-21 09:00:00.000 -240
2019-09-21 09:00:00.000 -240
2019-10-21 09:00:00.000 -240
2019-11-21 09:00:00.000 -300
2019-12-21 09:00:00.000 -300
(12 rows affected)
研究工作
大多数 Winapi 函数用于将 "local" 转换为 "UTC",然后再返回,不要'考虑相关日期;但只使用 whether daylight savings is in effect right now:
Functions like FileTimeToLocalFileTime apply the current Daylight Savings Time (DST) bias rather than the bias that was in effect at the time in question.
其他人考虑转换的日期,但只看现在的夏令时开始和结束规则 - 而不是当时的规则。
但是 TzSpecificLocalTimeToSystemTime 是 理解日期时间和夏令时的一个函数:
TzSpecificLocalTimeToSystemTime takes into account whether daylight saving time (DST) is in effect for the local time to be converted.
实际上 Windows 并不知道 一切 。它在注册表中保留历史 “夏令时” 日期的数据库:
所以对我来说它真正知道的是
- 2007年巨变前
- 及之后
但这对我的用例来说已经足够好了。它是 good enough for SQL Server.
红利阅读
好的,时效已过。我给了每个人自己回答问题的机会,提供了各种提示,这样别人就可以得到甜蜜的声誉。
那个时代已经过去了。现在是回答问题的时候了because it's what Joel and Jeff would have wanted.
伪代码:
int GetDateTimeOffsetFromUtcMinutes(DateTime localDateTime)
{
//All code on Whosebug is public domain; no attribution is ever required.
/*
Given a datetime, tell me how many minutes offset it was from UTC.
2006-03-21 09:00:00 ==> -300 (before daylight savings rules changed)
2007-03-21 09:00:00 ==> -240
The problem is that we don't want to use the current setting of Daylight Savings or not.
We want use if daylight savings was in effect *at the date* being supplied.
And we can't even use the current rules:
- Second Sunday in March: spring forward (e.g. 3/14/2021 2:00 AM)
- First Sunday in November: fall back (e.g. 11/7/2021 2:00 AM)
because those are the rules today.
We need to use the rules that were in effect of the date we are considering.
- e.g. the rules changed in 2007. If we have an OrderDate from 2006, we need those older rules.
Also notice that some dates have two answers:
11/7/2021 1:45 AM: EDT (-4 hours)
11/7/2021 1:45 AM: EST (-5 hours, because at 2am we fallback to 1am, and encounter 1:45AM again, but this time as Standard time)
So which one do we return? Whatever one i feel like. That's the price you pay for not using UTC or datetime's with an offset.
*/
//Convert the date to a SYSTEM_TIME structure so we can call the Win32 API
SYSTEM_TIME stLocal;
DateTimeToSystemTime(LocalDateTime, out stLocal);
SYSTEM_TIME stUtc;
if (!TzSpecificLocalTimeToSystemTime(null, stLocal, out stUtc))
RaiseLastWin32Error();
//We now have both "local" and "utc" as a SYSTEM_TIME.
//Convert both to FILETIME so we can subtract them.
FILETIME ftLocal, ftUtc;
if (!SystemTimeToFileTime(stLocal, out ftLocal))
RaiseLastWin32Error();
if (!SystemTimeToFileTime(stUtc, out ftUtc))
RaiseLastWin32Error();
//Convert the FILETIMEs into Int64s.
//We do this because, as you know, you cannot access FILE_TIME structure
//as an 64-bit integer, even though it is two 32-bit integers back to back.
LARGE_INTEGER ulLocal, ulUtc;
ulLocal.LowPart = ftLocal.dwLowDateTime;
ulLocal.HighPart = ftLocal.dwHighDatetime;
ulUtc.LowPart = ftUtc.dwLowDateTime;
ulUtc.HighPart = ftUtc.dwHighDatetime;
//Now subtract the quadparts
Int64 delta = ulLocal.QuadPart - ulUtc.QuadPart;
//That delta is in 100ns intervals (0.00001 sec). We want it in whole minutes;
// 100 ns
// 0.1 us
// 0.0001 ms
// 0.0000001 s
delta = delta div 10000000; //100 ns ==> seconds (div is integer division)
delta = delta div 60; //seconds ==> minutes
return delta;
}
然后,当然,没有测试用例,任何功能都是不完整的
//After the Daylight Savings rule change of of 2007
Test("2019-01-21T09:00:00", -300); // (-5 hours) |
Test("2019-02-21T09:00:00", -300); // (-5 hours) |
Test("2019-03-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-04-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-05-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-06-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-07-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-08-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-09-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-10-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2019-11-21T09:00:00", -300); // (-5 hours) |
Test("2019-12-21T09:00:00", -300); // (-5 hours) |
//Before the Daylight Savings rule change of 2007
Test("2006-01-21T09:00:00", -300); // (-5 hours) |
Test("2006-02-21T09:00:00", -300); // (-5 hours) |
Test("2006-03-21T09:00:00", -300); // (-5 hours) | What what?
Test("2006-04-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-05-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-06-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-07-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-08-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-09-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-10-21T09:00:00", -240); // (-4 hours) | Daylight savings
Test("2006-11-21T09:00:00", -300); // (-5 hours) |
Test("2006-12-21T09:00:00", -300); // (-5 hours) |
//Testing spring-forward. Spring forward March 14, 2021 at 2:00 AM
//The weirdness here is that the time from 2:00:00..2:59:59 doesn't exist.
Test("2021-03-14T00:00:00", -300); // EST
Test("2021-03-14T00:59:59", -300); // EST
Test("2021-03-14T01:00:00", -300); // EST
Test("2021-03-14T01:59:00", -300); // EST
Test("2021-03-14T02:00:00", -240); // There is no March 14, 2021 2am - it doesn't exist. The clock goes from 1:59:59 am --> 3:00:00 am. The function does return 240. TODO: figure out why it returns 240
Test("2021-03-14T02:59:59", -240); // There is no March 14, 2021 2:59am - it doesn't exist.
Test("2021-03-14T03:00:00", -240); // EDT
//Testing fall-back. Fall back March 14, 2021 at 2:00 AM
//The weirdness here is that 1:30 AM exists twice.
//12:00 AM -> 12:59:59 AM -> [1:00 AM -> 1:59:59 AM --> 1:00 AM -> 1:59:59 AM] -> 2:00 AM
//So there's no way to know if 11/7/2021 1:30 AM was EDT or EST - both are correct, because it actually did happen twice.
Test("2021-11-07T00:00:00", -240); // EDT
Test("2021-11-07T00:59:59", -240); // EDT
Test("2021-11-07T01:00:00", -240); // EDT (and EST!)
Test("2021-11-07T01:59:59", -240); // EDT (and EST!)
//Test("2021-11-07T01:00:00", -300); // EST (and EDT!)
//Test("2021-11-07T01:59:59", -300); // EST (and EDT!)
Test("2021-11-07T02:00:00", -300); // EST