如何以“d.hh:mm:ss”格式在数据库中保存TimeSpan值?

时间:2016-02-19 06:03:04

标签: c# sql-server entity-framework

    <RadioGroup
        android:id="@+id/rg_flowers"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <RadioButton
            android:id="@+id/rb_amaryllis"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Amaryllis"
            android:textColor="@android:color/black" />

        <RadioButton
            android:id="@+id/rb_rose"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Rose"
            android:textColor="@android:color/black" />
    </RadioGroup>

我想使用EF在DB中保存“timeInDays”。表列的类型为“时间”。 它给了我运行时异常,

  

“SqlDbType.Time溢出。值'2.08:08:08'超出范围。必须   在00:00:00.0000000和23:59:59.9999999之间。“

请帮我解决这个问题。

3 个答案:

答案 0 :(得分:3)

正如@Mainul所说,time类型的最大范围是24小时。为了存储更长的时间段,我建议使用bigint(64位整数)来直接表示时间跨度值。有关详细信息,请参阅此质量检查:What is the correct SQL type to store a .Net Timespan with values > 24:00:00?

如果你不能改变表模式那么你将不得不截断数据,一种方法是在保存到数据库之前向右移动(然后在加载时左移),丢失不太重要的位,但这会很混乱:

默认情况下,SQL Server中的time类型为time(7)(精度的7位小数),使用5个字节,请参见此处:https://msdn.microsoft.com/en-us/library/bb677243.aspx - 所以我们需要移位二进制表示时间跨度(“ticks”),使用8个字节,右边3个字节(得到5),即24位。如下图所示:

TimeSpan tick value (64-bits): 0x01 0x23 0x45 0x67 0x89 0xAB 0xCD 0xEF
SQL Server time field        :                0x01 0x23 0x45 0x67 0x89

由于TimeSpan Tick在左侧存储了它们最重要的位,这意味着我们将失去的三个字节(0xAB 0xCD 0xEF)代表我们可以承受的一小部分,这些不值得担心关于。当我们从数据库中加载数据并将其左移3个字节时,它将如下所示(请注意丢失其值的三个0x00 0x00 0x00字节):

TimeSpan tick value (64-bits): 0x01 0x23 0x45 0x67 0x89 0x00 0x00 0x00

存储

TimeSpan tooBig = new TimeSpoan( 2, 8, 8, 8 );
Int64 tooBigBits = tooBig.Ticks;
Int64 truncated = tooBigBits >> 24;
TimeSpan temp = TimeSpan.FromTicks ( truncated );

yourDbEntity.timeValue = temp;

装载:

TimeSpan temp = yourDbEntity.timeValue;
Int64 truncated = temp.Ticks;
Int64 adjusted = truncated << 24;
TimeSpan actual = TimeSpan.FromTicks( adjusted );

yourDbEntity.timeValue = actual;

答案 1 :(得分:2)

  

在T-SQL中,时间类型列定义一天的时间。时间没有了   时区意识,基于24小时制。   https://msdn.microsoft.com/en-us/library/bb677243.aspx

您的TimeSpan()方法返回时间,包括大于24小时值的日期值。 您可以做的是,保存没有日期值的时间值。

编辑:如果您想从当前TimeSpan中减去日期值。

new TimeSpan(timeInDays.Hours, timeInDays.Minutes, timeInDays.Seconds)

答案 2 :(得分:1)

您可以将您的时间存储在数据库中DateTime(02.01.0001 08:08:08),并仍然使用您的项目时间

public class Task
{
    [NotMapped] 
    public TimeSpan Duration
    {
        get { return Duration2 - DateTime.MinValue; }
        set { Duration2 = DateTime.MinValue + value; }
    }

    public DateTime Duration2 { get; set; }
}

这样做的缺点是您无法根据Duration

进行数据库查询
var tasks = from t in tasks where t.Duration > TimeSpan.FromHours(50);

但你必须使用

var duration = DateTime.MinValue + TimeSpan.FromHours(50);
var tasks = from t in tasks where t.Duration2 > duration;

或者您可以使用相同的概念在数据库中存储秒而不是日期值。