比较 DateTime 和解析的 DateTimeOffset 刻度的差异
Difference in comparing DateTime and parsed DateTimeOffset ticks
我有两个应用程序。一个客户端应用程序和一个服务器应用程序。
客户端应用程序向服务器发送 HTTP 请求,其中请求正文包含 DateTime
.
在我收到 DateTime
的服务器上,将其转换为 Ticks
并将其保存在 SQLite 数据库中。 (你可能会争论为什么 Ticks,但这就是这个应用程序的构建方式..)
到目前为止一切顺利。
不久之后(几分钟),服务器应用程序对数据库进行查询,并尝试查询过去 30 分钟内的所有记录。
在代码中我做了这样的事情来获得当前 DateTime
减去 30 分钟:
DateTimeOffset.Now.AddMinutes(-30).Ticks;
由于某种原因,这个数字大于新创建记录的时间戳。
我可能遗漏了什么,但我就是没看到...
这是一段完美模仿我的问题的代码。 (Link 到 post 底部的工作演示)
public static void Main()
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Client app
////////////////////////////////////////////////////////////////////////////////////////////////////////////
var clientTimestamp = DateTimeOffset.Now.DateTime;
var jsonDateTime = clientTimestamp.ToString("yyyy-MM-ddThh:mm:ss.fffZ");
// Then, the client app sends data as JSON to the server app...
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Server app
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Mimick as if we received a json string with a DateTime in it. Parse that back to a real DateTime object.
// This is also the value that will be stored in the database
var serverDateTime = DateTime.Parse(jsonDateTime);
Console.WriteLine("Ticks serverDateTime: " + serverDateTime.Ticks.ToString());
// A minute or so later, a recurring job checks the database for newly added records in the range of: 30 minutes ago till now.
// Create a new DateTime Now minus 30 minutes... Both Ticks values below are greater than the jsonDateTime ticks?
// DateTimeOffset:
// This value is larger, even with the minus -10 minutes?
var nowDateTimeOffset = DateTimeOffset.Now.AddMinutes(-10).Ticks.ToString();
Console.WriteLine("Ticks nowDateTime -10 minutes: " + nowDateTimeOffset);
// DateTime
// This value is larger, even with the minus -10 minutes?
var nowDateTime = DateTimeOffset.Now.AddMinutes(-10).Ticks.ToString();
Console.WriteLine("Ticks nowDateTime -10 minutes: " + nowDateTime);
}
在这种情况下,问题似乎出在日期时间的格式上:
"yyyy-MM-ddThh:mm:ss.fffZ" // lower hh
然而,它应该是:
"yyyy-MM-ddTHH:mm:ss.fffZ" // upper HH
使用 12 小时 (hh
) 格式而不是 24 小时 (HH
) 格式会导致 50% 的时间出现 12 小时差异!
正如 Hans 在评论中提到的,您应该确保使用 UTC 来比较 DateTime 值。 DateTime.Parse
默认情况下将 DateTime 类型设置为 DateTimeKind.Local
。客户端发送的是 UTC 日期时间吗?
更新客户端时间戳,以便它发送带有 ToUniversalTime
:
的 UTC 日期时间
var clientTimestamp = DateTimeOffset.Now.ToUniversalTime();
而不是 DateTime.Parse
考虑 DateTime.ParseExact
和 AdjustToUniversal
:
// convert the date to UTC before saving to database
var utcServerDate = DateTime.ParseExact(jsonDateTime, "yyyy-MM-ddTHH:mm:ss.fffZ",
CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
并且在比较 DateTimeOffset.Now
值时使用 UtcTicks
:
var nowDateTimeOffset = DateTimeOffset.Now.AddMinutes(-30).UtcTicks;
我在尝试比较两个 DateTimeOffset 时遇到了同样的问题,它们是用 0(零)毫秒创建的,并且都使用 UTC。
在我的研究和长期调试此源代码中:
// local variable
DateTimeOffset datetime = DateTimeOffset.Parse ("2021-03-02T02:10:15.000Z");
// method
DateTimeOffset getNowTruncated () {
DateTimeOffset now = DateTimeOffset.UtcNow.AddMilliseconds;
now.AddMilliseconds (-now.Milliseconds);
}
// inside Main program
while (true) {
if (getNowTruncated () == datetime) {
break;
} else {
Console.WriteLine (getNowTruncated ());
}
}
两个日期时间都是相同的年、月、日、时、分、秒、毫秒和unixtimestamp(使用ToUnixTimeMilliseconds()方法)。
那么,为什么永远不会触发“中断”?
当我比较两者的TICKS时,我发现了差异,如此接近解决它......
搜索 TICKS 时发现了 NANOSECOND 这个词,所以我猜这是问题所在,当从 DateTime.UtcNow 创建日期时间时,它是用纳秒创建的,并且只有在调用 Ticks 方法时才可见,为了避免它,我创建了下一个方法:
public static DateTimeOffset GetNowTruncate ()
{
DateTimeOffset now = DateTimeOffset.UtcNow;
return new DateTimeOffset (now.Year, now.Month, now.Day,
now.Hour, now.Minute, now.Second, TimeSpan.Zero);
}
当你看到时,不存在任何设置纳秒的参数,因此它将为零。
我有两个应用程序。一个客户端应用程序和一个服务器应用程序。
客户端应用程序向服务器发送 HTTP 请求,其中请求正文包含 DateTime
.
在我收到 DateTime
的服务器上,将其转换为 Ticks
并将其保存在 SQLite 数据库中。 (你可能会争论为什么 Ticks,但这就是这个应用程序的构建方式..)
到目前为止一切顺利。
不久之后(几分钟),服务器应用程序对数据库进行查询,并尝试查询过去 30 分钟内的所有记录。
在代码中我做了这样的事情来获得当前 DateTime
减去 30 分钟:
DateTimeOffset.Now.AddMinutes(-30).Ticks;
由于某种原因,这个数字大于新创建记录的时间戳。
我可能遗漏了什么,但我就是没看到...
这是一段完美模仿我的问题的代码。 (Link 到 post 底部的工作演示)
public static void Main()
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Client app
////////////////////////////////////////////////////////////////////////////////////////////////////////////
var clientTimestamp = DateTimeOffset.Now.DateTime;
var jsonDateTime = clientTimestamp.ToString("yyyy-MM-ddThh:mm:ss.fffZ");
// Then, the client app sends data as JSON to the server app...
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Server app
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Mimick as if we received a json string with a DateTime in it. Parse that back to a real DateTime object.
// This is also the value that will be stored in the database
var serverDateTime = DateTime.Parse(jsonDateTime);
Console.WriteLine("Ticks serverDateTime: " + serverDateTime.Ticks.ToString());
// A minute or so later, a recurring job checks the database for newly added records in the range of: 30 minutes ago till now.
// Create a new DateTime Now minus 30 minutes... Both Ticks values below are greater than the jsonDateTime ticks?
// DateTimeOffset:
// This value is larger, even with the minus -10 minutes?
var nowDateTimeOffset = DateTimeOffset.Now.AddMinutes(-10).Ticks.ToString();
Console.WriteLine("Ticks nowDateTime -10 minutes: " + nowDateTimeOffset);
// DateTime
// This value is larger, even with the minus -10 minutes?
var nowDateTime = DateTimeOffset.Now.AddMinutes(-10).Ticks.ToString();
Console.WriteLine("Ticks nowDateTime -10 minutes: " + nowDateTime);
}
在这种情况下,问题似乎出在日期时间的格式上:
"yyyy-MM-ddThh:mm:ss.fffZ" // lower hh
然而,它应该是:
"yyyy-MM-ddTHH:mm:ss.fffZ" // upper HH
使用 12 小时 (hh
) 格式而不是 24 小时 (HH
) 格式会导致 50% 的时间出现 12 小时差异!
正如 Hans 在评论中提到的,您应该确保使用 UTC 来比较 DateTime 值。 DateTime.Parse
默认情况下将 DateTime 类型设置为 DateTimeKind.Local
。客户端发送的是 UTC 日期时间吗?
更新客户端时间戳,以便它发送带有 ToUniversalTime
:
var clientTimestamp = DateTimeOffset.Now.ToUniversalTime();
而不是 DateTime.Parse
考虑 DateTime.ParseExact
和 AdjustToUniversal
:
// convert the date to UTC before saving to database
var utcServerDate = DateTime.ParseExact(jsonDateTime, "yyyy-MM-ddTHH:mm:ss.fffZ",
CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
并且在比较 DateTimeOffset.Now
值时使用 UtcTicks
:
var nowDateTimeOffset = DateTimeOffset.Now.AddMinutes(-30).UtcTicks;
我在尝试比较两个 DateTimeOffset 时遇到了同样的问题,它们是用 0(零)毫秒创建的,并且都使用 UTC。
在我的研究和长期调试此源代码中:
// local variable
DateTimeOffset datetime = DateTimeOffset.Parse ("2021-03-02T02:10:15.000Z");
// method
DateTimeOffset getNowTruncated () {
DateTimeOffset now = DateTimeOffset.UtcNow.AddMilliseconds;
now.AddMilliseconds (-now.Milliseconds);
}
// inside Main program
while (true) {
if (getNowTruncated () == datetime) {
break;
} else {
Console.WriteLine (getNowTruncated ());
}
}
两个日期时间都是相同的年、月、日、时、分、秒、毫秒和unixtimestamp(使用ToUnixTimeMilliseconds()方法)。
那么,为什么永远不会触发“中断”?
当我比较两者的TICKS时,我发现了差异,如此接近解决它......
搜索 TICKS 时发现了 NANOSECOND 这个词,所以我猜这是问题所在,当从 DateTime.UtcNow 创建日期时间时,它是用纳秒创建的,并且只有在调用 Ticks 方法时才可见,为了避免它,我创建了下一个方法:
public static DateTimeOffset GetNowTruncate ()
{
DateTimeOffset now = DateTimeOffset.UtcNow;
return new DateTimeOffset (now.Year, now.Month, now.Day,
now.Hour, now.Minute, now.Second, TimeSpan.Zero);
}
当你看到时,不存在任何设置纳秒的参数,因此它将为零。