bil*_*bob 5 c# sql-server timezone timezone-offset nodatime
我正在使用 C# 程序处理日期。
我想过滤任何具有 DateTime、DateTime2、DateTimeOffset 列的表。
我将LastRefreshDateas存储DateTimeOffSet为 UTC,并使用它来过滤这些表上的数据。我调整偏移量(使用NodaTime)LastRefreshDate我根据用于在这些表中存储日期的时区通常,它是由用户给出的。
所以我创建了一个测试样本来解释这个问题。通常,SQL 查询是动态的,参数也是动态的。这是示例代码:
[TestMethod]
public void Test()
{
using (SqlConnection connection = new SqlConnection("Server=myserver;Database=mydb;User ID=admin;Password=admin"))
{
connection.Open();
using (SqlCommand command = new SqlCommand("SELECT [TimeStamp] FROM [dbo].[DATA] WHERE [TimeStamp] >= @p0", connection))
{
string datestring = "2019-06-18 13:35:20.1133868 -04:00";
// Does not work
// DateTimeOffset p0 = DateTimeOffset.Parse(datestring, CultureInfo.InvariantCulture);
// Does work
DateTime p0 = DateTime.Parse(datestring, CultureInfo.InvariantCulture);
command.Parameters.AddWithValue("@p0", p0);
using (SqlDataReader reader = command.ExecuteReader())
{
var dataTable = new DataTable();
dataTable.Load(reader);
var result = dataTable.Rows.Count == 0;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我创建了 2 个 SQL fiddles 来演示这个问题。顺便说一下,我运行了 SQL Server Profiler,生成的查询与 fiddle 中的查询类似。
日期时间小提琴:http://sqlfiddle.com/#!18/ a06be/1
declare @p0 datetime = '2019-06-18 13:35:20'
SELECT
[TimeStamp]
FROM
[dbo].[DATA]
WHERE
([TimeStamp] >= @p0)
Run Code Online (Sandbox Code Playgroud)
DateTimeOffSet 小提琴:http://sqlfiddle.com/#!18/a06be /2
declare @p0 datetimeoffset(7) ='2019-06-18 13:35:20.1133868 -04:00'
SELECT [TimeStamp]
FROM
[dbo].[DATA]
WHERE
([TimeStamp] >= @p0 )
Run Code Online (Sandbox Code Playgroud)
我做了更多测试。通过直接应用强制转换,SQL 查询就可以工作。SQL Server隐式转换的行为方式似乎与显式转换不同。这是测试用例:
declare @p0 datetime
set @p0 = '2019-06-18 17:48:00.00'
declare @p1 datetimeoffset(7)
set @p1 = '2019-06-18 17:47:00.5385563 -04:00'
select 1
where @p0 > cast(@p1 as datetime) -- working
--where @p0 > @p1 -- not working
Run Code Online (Sandbox Code Playgroud)
一些东西:
在 SQL Server 中,如果您使用CAST, 或CONVERT不指定样式,则默认样式为0,当将 a 转换datetimeoffset为 a 时datetime,或datetime2仅从 中获取日期和时间值而不datetimeoffset考虑偏移量。如果您想考虑偏移量,请使用CONVERT并传递1样式:
DECLARE @p0 datetimeoffset = '2019-06-18 13:35:20.1133868 -04:00'
SELECT convert(datetime, @p0, 0) as 'A', convert(datetime, @p0, 1) as 'B'
-- A = 2019-06-18T13:35:20.113Z
-- B = 2019-06-18T17:35:20.113Z
Run Code Online (Sandbox Code Playgroud)当使用参数查询datetimeordatetime2字段时datetimeoffset,隐式转换中确实考虑了偏移量(就像B上面一样)。
在 C# 方面,要小心DateTime.Parse. 默认情况下,当提供偏移量时,它会发出基于本地时间的值。如果你检查一下,你就会看到p0.Kind == DateTimeKind.Local。您可以通过DateTimeStyles.AdjustToUniversal,但更好的想法是像DateTimeOffset您在“不起作用”代码中所示的那样进行解析。但是,不要传递完整的DateTimeOffset,而是传递UtcDateTime属性:
DateTime p0 = DateTimeOffset.Parse(datestring, CultureInfo.InvariantCulture).UtcDateTime;
Run Code Online (Sandbox Code Playgroud)出于性能和稳定性方面的原因,您可以考虑使用ParseExact或TryParseExact代替Parse。或者,既然您说过您已经在使用 Noda Time,那么您可以将其文本解析功能与OffsetDateTimePattern. 从那里您可以致电.ToDateTimeOffset().UtcDateTime, 或.ToInstant().ToDateTimeUtc()。
或者,您可以将 SQL 数据库列定义为datetimeoffset,然后您可以传递任何DateTimeOffset参数,查询时它将被标准化为 UTC。
| 归档时间: |
|
| 查看次数: |
2513 次 |
| 最近记录: |