Работа с полями TimeStamp в FB

Модераторы: kdv, CyberMax

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Сообщение stix-s » 21 авг 2007, 09:56

Slavik писал(а):Согласись, что разницу между этими двумя значениями можно считать часом лишь приближённо на "бытовом" уровне :)
Угу, а если мне ничего более и не требуется?

Кузнецов Евгений
Сообщения: 144
Зарегистрирован: 16 фев 2006, 22:36

Сообщение Кузнецов Евгений » 21 авг 2007, 10:06

Доброго времени суток!
Slavik писал(а):Если к значению типа timestamp прибавлять h/23.(9) (где h - целое количество часов от 1 до 23), то точность вычислений растёт с увеличением количества девяток, и наилучший (но всё же не точный) результат достигается при девяти девятках, а дальше точность падает в полном соответствии с предыдущими изысканиями о точности вычисления 1/23.(9).
Видимо, потому что timestamp в 3-м диалекте - это NUMERIC(18,9).
C вычитанием тоже интересная вещь получается - см. http://groups.google.com/group/ru-fireb ... 463f430b62

Slavik
Сообщения: 115
Зарегистрирован: 17 янв 2007, 11:52

Сообщение Slavik » 21 авг 2007, 11:43

Кузнецов Евгений писал(а):Видимо, потому что timestamp в 3-м диалекте - это NUMERIC(18,9).
Это объясняет, почему достигается полная точность (до одной десятитысячной секунды) при добавлении к timestamp'у часов в виде выражения h/24.(0) с десятью и более нулями после точки.

Но это не объясняет падение точности вычисления выражения 1/23.(9) при увеличении количества девяток после девяти штук.

Slavik
Сообщения: 115
Зарегистрирован: 17 янв 2007, 11:52

Сообщение Slavik » 21 авг 2007, 13:15

Кузнецов Евгений писал(а):C вычитанием тоже интересная вещь получается - см. http://groups.google.com/group/ru-fireb ... 463f430b62
Эта ветка мне на многое открыла глаза. Я тоже был в заблуждении и думал, что разница между timestamp'ами вычисляется точно. И согласен, что точную разницу между timestamp'ами можно получить в десятитысячных секуды:
Кузнецов Евгений (по ссылке) писал(а):Разумеется, можно, сделать CAST((end_date-start_date)*86400*10000 AS INTEGER) и дальше использовать его в расчетах
Правда я бы приводил к bigint или numeric(18,0).
А вот дальнейшие рассуждения мне непонятны. Чем это некрасиво? Ведь если имеем точную разницу в десятитысячных секунды, то чтобы получить её же, например, в целых секундах достаточно разделить полученное целое значение десятитысячных на 10000 (дробная часть при этом отбрасывается). Если же надо получить разницу в дробных секундах (как при вычитании двух значений типа time) -- то делим на 10000.0000.

Кузнецов Евгений
Сообщения: 144
Зарегистрирован: 16 фев 2006, 22:36

Сообщение Кузнецов Евгений » 21 авг 2007, 13:24

Slavik писал(а):Но это не объясняет падение точности вычисления выражения 1/23.(9) при увеличении количества девяток после девяти штук.
Да, этого я тоже не понимаю - результат 1/23.9999999999 вроде бы должен иметь точность NUMERIC(18,10), но этого не получаем
Slavik писал(а):Правда я бы приводил к bigint или numeric(18,0). А вот дальнейшие рассуждения мне непонятны. Чем это некрасиво?
Почитайте до конца - это неправильно, нужно еще округлять. Говоря о некрасивости, я имел в виду, что при вычислении разницы в часах одним запросом будет нагромождение CAST'ов

В общем, вот окончательный вариант в виде процедуры - http://www.delphikingdom.com/asp/answer ... swer=50989

Slavik
Сообщения: 115
Зарегистрирован: 17 янв 2007, 11:52

Сообщение Slavik » 22 авг 2007, 11:31

Кузнецов Евгений писал(а):Почитайте до конца - это неправильно, нужно еще округлять.
Зачем? Ведь округление уже происходит в выражении
CAST((end_date-start_date)*86400*10000 AS INTEGER)
Проведя тест, на разнице в датах от 0 до 9999 десятитысячных секунды, я не обнаружил ни одной ошибки в этом округлении. Зачем ещё какие-то округления и танцы с +-0.5?
Кузнецов Евгений писал(а):В общем, вот окончательный вариант в виде процедуры - http://www.delphikingdom.com/asp/answer ... swer=50989
Выполнил запрос:

Код: Выделить всё

select * from DATE_DIFF('2007-08-22 00:00:01.0010', '2007-08-22 00:00:00.0000')
и получил следующий результат:
DAYS = 0; HOURS = 0; MINUTES = 0; SECONDS = 1; MILLISECONDS = 11 :)
Неговоря уже о том, что странно обзывать десятитысячные миллисекундами, но результат неверен: вместо 10 получили 11. Думаю, это из-за +0.5.

Попутно я обнаружил, что вычитание двух timestamp'ов (Date1-Date2), если Date1<Date2, не всегда даёт верный результат (например, если значения отличаются на одну десятитысячную, разница будет почему-то равна нулю :( ).
Поэтому лучше всегда вычитать из большей даты меньшую:

Код: Выделить всё

cast((case when Date1<Date2 then -(Date2-Date1) else Date1-Date2 end)
  *(24*60*60*10000) as bigint)
Это и будет окончательное выражение для подсчёта разницы между двумя timestamp'ами в десятитысячных секунды. А дальше стандартно вычисляем секунды, минуты, часы,...

Кузнецов Евгений
Сообщения: 144
Зарегистрирован: 16 фев 2006, 22:36

Сообщение Кузнецов Евгений » 22 авг 2007, 12:16

Доброго времени суток!
Slavik писал(а):Проведя тест, на разнице в датах от 0 до 9999 десятитысячных секунды, я не обнаружил ни одной ошибки в этом округлении. Зачем ещё какие-то округления и танцы с +-0.5?
Видимо, что-то в двойке правили, я писал для 1.5.4
Slavik писал(а):Выполнил запрос:

Код: Выделить всё

select * from DATE_DIFF('2007-08-22 00:00:01.0010', '2007-08-22 00:00:00.0000')
и получил следующий результат:
DAYS = 0; HOURS = 0; MINUTES = 0; SECONDS = 1; MILLISECONDS = 11 :)
В 1.5 все работает нормально.
Slavik писал(а):Неговоря уже о том, что странно обзывать десятитысячные миллисекундами
Да, это я заметил, но править не стал

Кузнецов Евгений
Сообщения: 144
Зарегистрирован: 16 фев 2006, 22:36

Сообщение Кузнецов Евгений » 22 авг 2007, 12:24

To Slavik

Посмотрел еще - при вычитании дат в FB 2 происходит округление, а в 1.5 - отбрасывание разрядов

Код: Выделить всё

select (CAST('2007-08-22 00:00:00.0019' AS TIMESTAMP)-
      CAST('2007-08-22 00:00:00.0000' AS TIMESTAMP))*86400*10000
from rdb$database
в FB 2.02.12897 возвращает 19.008,
в 1.5.4 - 18.144

Любопытно, но

Код: Выделить всё

select (CAST('2007-08-22 00:00:00.0000' AS TIMESTAMP)-
      CAST('2007-08-22 00:00:00.0019' AS TIMESTAMP))*86400*10000
from rdb$database 
в FB 2.0.2.12897 возвращает -18.144 (т.е. округления в этом случае не происходит, поэтому у Вас и теряется миллисекунда)

Что-то тут не так. Подождем, пока в эту ветку разработчики заглянут

Slavik
Сообщения: 115
Зарегистрирован: 17 янв 2007, 11:52

Сообщение Slavik » 22 авг 2007, 18:02

Кузнецов Евгений писал(а):Что-то тут не так. Подождем, пока в эту ветку разработчики заглянут
Да уж. Похоже, безопаснее пользоваться своей UDF, если нужна точность.

Кузнецов Евгений
Сообщения: 144
Зарегистрирован: 16 фев 2006, 22:36

Сообщение Кузнецов Евгений » 29 авг 2007, 11:09

Доброго времени суток!

To Slavik
К счастью, в 2.1 Beta 2 разработчики это поправили: http://tracker.firebirdsql.org/browse/CORE-1428

Slavik
Сообщения: 115
Зарегистрирован: 17 янв 2007, 11:52

Сообщение Slavik » 30 авг 2007, 07:37

Кузнецов Евгений писал(а):К счастью, в 2.1 Beta 2 разработчики это поправили: http://tracker.firebirdsql.org/browse/CORE-1428
Осталось дождаться релиза. :)

Ответить