Преобразование .NET Ticks в SQL Server DateTime
Я сохраняю значение TimeSpan
(из .NET) в своем db как BIGINT
в SQL Server (сохраняя свойство Ticks). Я хочу знать, как преобразовать это значение BIGINT
в значение DATETIME
в SQL Server (а не в .NET). Любые идеи?
Приветствия
EDIT:
Я использую NHibernate для отображения свойства TimeSpan
, которое у меня есть, и оно сохраняет свойство Ticks. Я использую его для относительных часов (или минут) контроля над какой-то датой.
Внутренне в системе все нормально, это преобразование не требуется. Однако при выполнении случайных запросов в SQL Server трудно понять сохраненную форму TimeSpan
. Таким образом, функция, в которой передается значение Ticks
и возвращается DATETIME
, дает количество в часах, минутах и секундах, которое соответствует TimeSpan
.
Ответы
Ответ 1
Я не уверен, насколько точно это будет с секундами, но вы можете попробовать что-то вроде:
Declare @TickValue bigint
Declare @Days float
Set @TickValue = 634024345696365272
Select @Days = @TickValue * POWER(10.00000000000,-7) / 60 / 60 / 24
Select DATEADD(d, Cast(@Days As int), Cast('0001-01-01' As DATE))
+ Cast( (@Days - FLOOR(@Days)) As DateTime)
Фактически другой способ, который будет работать в SQL 2005, - отметить, что количество тиков от 0001-01-01 до 1900-01-01 составляет 599266080000000000. С этим вы могли бы сделать:
Declare @TickOf19000101 bigint
Declare @TickValue bigint
Declare @Minutes float
Set @TickOf19000101 = 599266080000000000
Set @TickValue = DATEDIFF(mi, 0 ,CURRENT_TIMESTAMP) * Cast(60 As BigInt)
* POWER(10.00000000000,7) + @TickOf19000101
Select @TickValue
Select @Minutes = (@TickValue - @TickOf19000101) * POWER(10.00000000000,-7) / 60
Select @Minutes
Select DATEADD(MI, @Minutes, '1900-01-01')
Ответ 2
Вы можете использовать эту функцию, взятую из блога Павла Гатилова, чтобы преобразовать 64-разрядное целое число в значение datetime с точностью до миллисекунды в локальное время сервера:
CREATE FUNCTION NetFxUtcTicksToDateTime
(
@Ticks bigint
)
RETURNS datetime
AS
BEGIN
-- First, we will convert the ticks into a datetime value with UTC time
DECLARE @BaseDate datetime;
SET @BaseDate = '01/01/1900';
DECLARE @NetFxTicksFromBaseDate bigint;
SET @NetFxTicksFromBaseDate = @Ticks - 599266080000000000;
-- The numeric constant is the number of .Net Ticks between the System.DateTime.MinValue (01/01/0001) and the SQL Server datetime base date (01/01/1900)
DECLARE @DaysFromBaseDate int;
SET @DaysFromBaseDate = @NetFxTicksFromBaseDate / 864000000000;
-- The numeric constant is the number of .Net Ticks in a single day.
DECLARE @TimeOfDayInTicks bigint;
SET @TimeOfDayInTicks = @NetFxTicksFromBaseDate - @DaysFromBaseDate * 864000000000;
DECLARE @TimeOfDayInMilliseconds int;
SET @TimeOfDayInMilliseconds = @TimeOfDayInTicks / 10000;
-- A Tick equals to 100 nanoseconds which is 0.0001 milliseconds
DECLARE @UtcDate datetime;
SET @UtcDate = DATEADD(ms, @TimeOfDayInMilliseconds, DATEADD(d, @DaysFromBaseDate, @BaseDate));
-- The @UtcDate is already useful. If you need the time in UTC, just return this value.
-- Now, some magic to get the local time
RETURN @UtcDate + GETDATE() - GETUTCDATE();
END
GO
Альтернативный код, подходящий для встроенного использования:
DECLARE @Ticks bigint
set @Ticks = 634899090000000000
select DATEADD(ms, ((@Ticks - 599266080000000000) -
FLOOR((@Ticks - 599266080000000000) / 864000000000) * 864000000000) / 10000,
DATEADD(d, (@Ticks - 599266080000000000) / 864000000000, '01/01/1900')) +
GETDATE() - GETUTCDATE()
Ответ 3
Я действительно не знаю SQL Server, но сегодня у моего коллеги была такая же проблема, и я думаю, что нашел решение вроде этого:
CAST(([ticks] - 599266080000000000) / 10000000 / 24 / 60 / 60 AS datetime)
где 599266080000000000 - значение тиков для 01/01/1900 00:00:00.
Ответ 4
A TimeSpan
не является датой, и сохранение ее как таковой может вызвать путаницу в будущем.
Есть ли причина, по которой вы не можете просто сохранить тики в целочисленное поле и не изменять его значение?
Ответ 5
Получите значение TimeSpan.TicksPerSecond
в .NET(просто запишите его).
Затем в вашем SQL вы можете разделить количество тиков на это число, чтобы указать количество секунд.
Затем вы можете разделить это на 60, чтобы получить минуты и т.д.
Ответ 6
Вы можете использовать функцию CAST, встроенную в SQL Server.
SELECT(CAST(CAST(CAST ('02/02/10' AS datetime) AS BIGINT) AS datetime))
вы получите 2010-02-02 00: 00: 00.000
Ответ 7
Я понял это самостоятельно:
288 000 000 000 тиков составляет 8 часов, поэтому следующий SELECT
возвращает фиктивную дату с указанием количества часов...
SELECT DATEADD(millisecond, 288000000000/10000, CAST('1900-01-01' AS DATETIME))
Благодаря всем усилиям.