【问题标题】:DateTimeOffset date doesn't include records with end dateDateTimeOffset 日期不包括具有结束日期的记录
【发布时间】:2020-04-13 19:42:13
【问题描述】:

我想按日期范围获取数据库记录,包括包含结束日期范围的数据。数据库中的TimeStamp 列是dateTime2(7) 的类型。日期和时间存储在UTC 中。但是,我根据用户时区显示数据。为此,我正在查找时区,然后在C# 中将其转换为BaseUtfOffset。前任。 3/18/20203/29/2020

 var newOffSetDate = TimeZoneInfo.FindSystemTimeZoneById(timeZoneName);

 DateTimeOffset d1 = new DateTimeOffset(Convert.ToDateTime(date1), newOffSetDate.BaseUtcOffset);
 DateTimeOffset d2 = new DateTimeOffset(Convert.ToDateTime(date2), newOffSetDate.BaseUtcOffset);

然后,我在此处创建的过程(DateTimeOffset 参数的类型)中传递开始和结束日期,以在 SQL 中执行简单的选择语句。返回的数据只包括有开始日期的记录。

create table MyTable
(
  Id int Primary Key Identity(1,1),
  [TimeStamp] datetime2(7) not null
)

insert into MyTable(TimeStamp) values('2020-03-29 19:40:46.8500000')
insert into MyTable(TimeStamp) values('2020-03-29 19:40:53.1000000')
insert into MyTable(TimeStamp) values('2020-03-18 17:15:48.2600000')

select * from MyTable
where
convert(datetimeoffset, convert(datetime2(7), timestamp, 1)) >= '3/18/2020 12:00:00 AM -04:00' and 
convert(datetimeoffset, convert(datetime2(7), timestamp, 1)) <= '3/29/2020 12:00:00 AM -04:00'

例如,在上面的场景中,我应该得到所有记录,但我只得到一个记录。

2020-03-18 17:15:48.2600000

C# 中产生的DateTimeOffset 的格式会影响结果还是我遗漏了什么?

SQLFIDDLE

更新:

存储过程参数:

,@StartDate     DateTimeOffset  = NULL
,@EndDate       DateTimeOffset  = NULL

在示例中使用:开始日期3/18/2019 和结束日期3/29/2020。将日期转换为 DateTimeOffset 的 C# 方法产生以下输出:

d1 = 3/18/2020 12:00:00 AM -04:00
d2 = 3/29/2020 12:00:00 AM -04:00

【问题讨论】:

  • convert(datetime2(7), timestamp, 1) 在这里想要达到什么目的? TimeStamp 已经是 datetime2 ,将其转换为一个只会减慢查询速度。
  • @Larnu,我无需进行任何转换即可获得相同的结果。这是我最近一次尝试,看看我是否愿意将日期时间转换为 2020-03-29 19:40:46.8500000 +00:00 的样子,也许它可以解决问题,但毫无疑问,不会。
  • 如果你想过滤一个日期范围包含,那么你需要在你的上限范围内包括时间。最简单的方法是在日期上加 1 并将过滤器更改为 less than。示例:用户想要在日期 3/18 和 3/29 之间进行过滤。使您的 where 子句大于或等于 2020-3-18 且小于 2020-3-30。此评论没有考虑时区,它严格说明时间在您的 where 子句中很重要,而您目前没有考虑它。
  • 关于时区。如果您的日期保留为 datetime2 并且日期信息为 UTC,那么您需要将输入参数转换为 UTC,然后按这些参数进行过滤。
  • 2020-03-29 19:40:53.1000000+00:00 is after 2020-03-29T00:00:00-04:00 因此convert(datetimeoffset, convert(datetime2(7), timestamp, 1)) &lt;= '3/29/2020 12:00:00 AM -04:00' 为假且不显示该行。

标签: c# sql-server-2016 datetimeoffset


【解决方案1】:

我相信你让它变得比它需要的更困难。

在您的代码中:将TimeZoneInfo 应用于用户提供的DateTime 参数。由于数据保存为DateTime2,因此在本例中使用与System.DateTime 匹配的参数类型。根据您的问题,您希望上限值包含在内,使用 Dates 最简单的方法是在 Date 值上加 1(或 24 小时也是可以接受的)并将查询更改为 less比。

看下面的代码,你可以把它修改成一个存储过程。而是。

public void Test(DateTime argStartDate, DateTime argEndDate)
{
    var newOffSetDate = System.TimeZoneInfo.FindSystemTimeZoneById("");

    DateTime startParam = new DateTimeOffset(argStartDate, newOffSetDate.GetUtcOffset(argStartDate)).UtcDateTime;
    DateTime endParam = new DateTimeOffset(argEndDate, newOffSetDate.GetUtcOffset(argEndDate)).UtcDateTime;

    endParam = endParam.AddDays(1);

    const string query = "SELECT [column1], [column2], ... FROM [YourTable] WHERE [TimeStamp] >= @start AND [TimeStamp] < @end";
    using (var con = new System.Data.SqlClient.SqlConnection(""))
    using (var com = new System.Data.SqlClient.SqlCommand(query, con))
    {
        com.Parameters.Add("@start", SqlDbType.DateTime2).Value = startParam;
        com.Parameters.Add("@end", SqlDbType.DateTime2).Value = endParam;
        con.Open();
        using (var reader = com.ExecuteReader())
        {
            while (reader.Read())
            {
                // do stuff
            }
        }
    }
}

【讨论】:

  • 伊戈尔,你是对的。我把它复杂化了。谢谢!
【解决方案2】:

您的查询返回行的原因是因为这是正确的。你有 3 次,你说的是 UTC:

2020-03-29 19:40:46.8500000+00:00
2020-03-29 19:40:53.1000000+00:00
2020-03-18 17:15:48.2600000+00:00

因此,让我们将它们转换为 -04:00(即 EDT):

2020-03-29 15:40:46.8500000-04:00
2020-03-29 15:40:53.1000000-04:00
2020-03-18 13:15:48.2600000-04:00

然后您将查看时间是否在之后 2020-03-18T00:00:00-04:00 和在或之前 2020-03-29T00:00:00-04:00

2020-03-18 13:15:48.2600000-04:00 既在2020-03-18T00:00:00-04:00 之后又在2020-03-29T00:00:00-04:00 之前,所以这是显示。另一方面,both 2020-03-29 15:40:53.1000000-04:002020-03-29 15:40:46.8500000-04:00 都在 2020-03-29T00:00:00-04:00 之后,因此不会显示。

您将获得 1 行,因为其中只有 1 行满足WHERE

【讨论】:

  • 哦哦。我现在看到你之前在评论中提到的内容。所以我想我要找的是结束日期应该是3/29/2020 23:59:00 PM -04:00?我想,也许我没有清楚地解释我的要求。我也会更新问题。我需要的是,如果用户本地日期在日期范围内,我想在不关心时间的情况下将其包括在内。因此,对于 2020 年 3 月 18 日和 2020 年 3 月 29 日的范围,我想要所有属于该日期的记录,而不必担心时间。在这种情况下,我发现我的转换导致了问题。
  • 如果您想要 3 月 29 日的所有日期而不考虑时间,请使用 &lt; 2020-03-30T00:00:00-04:00, @smr5 。
猜你喜欢
  • 2020-05-07
  • 2019-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-20
  • 2011-07-10
  • 1970-01-01
  • 2021-12-17
相关资源
最近更新 更多