Функция timestampdiff DB2, возвращающая неожиданные результаты - PullRequest
4 голосов
/ 06 октября 2011

Я использую следующий синтаксис

TIMESTAMPDIFF(2, CHAR(CREATED - TIMESTAMP('1970-01-01 00:00:00'))

, где CREATED имеет тип TIMESTAMP, а база данных - DB2. Намерение состоит в том, чтобы преобразовать метку времени в миллисы из эпохи. Если есть лучшая функция, это было бы более полезно.

Пример данных:
Для 2011-10-04 13:54:50 возвращаемое значение равно 1316613290, но фактическое значение должно быть 1317732890 (получено из http://www.epochconverter.com)

Запрос на запуск

SELECT TIMESTAMPDIFF(2, CHAR(TIMESTAMP('2011-10-04 13:54:50') - TIMESTAMP('1970-01-01 00:00:00'))) FROM  SYSIBM.SYSDUMMY1;

Ответы [ 3 ]

7 голосов
/ 06 октября 2011

Это результат того факта, что TIMESTAMPDIFF возвращает оценку разницы между временными метками, а не фактическое значение, как ожидалось.

Из справки , стр. 435 (при условии, для iSeries):

Следующие предположения используются при преобразовании значений элемента к запрашиваемому типу интервала:

  • Один год имеет 365 дней.
  • У одного года 52 недели.
  • Один год имеет 12 месяцев.
  • Один квартал имеет 3 месяца.
  • Один месяц имеет 30 дней.
  • Одна неделя имеет 7 дней.
  • Один день имеет 24 часа.
  • Один час имеет 60 минут.
  • Одна минута имеет 60 секунд.
  • Одна секунда имеет 1000000 микросекунд.

И фактический расчет:

секунд + (минуты + (часы + ((дни + (месяцы * 30) + (годы * 365)) * 24)) * 60) * 60

Это по понятным причинам неточно. Не полезно.

Кажется, это прямое следствие того, как возвращаются арифметические результаты с отметками времени.
То есть;

SELECT                                                              
TIMESTAMP('1971-03-02 00:00:00') - TIMESTAMP('1970-01-01 00:00:00') 
FROM sysibm/sysdummy1        

возвращается:

10,201,000,000.000000         

Which can be divided into:
  • 1 год
  • 02 месяцев
  • 01 дней
  • 00 часов
  • 00 минут
  • 00 секунд
  • 000000 микросекунд

Что является неточным Период / продолжительность информации Хотя существует множество ситуаций, когда этот тип данных является полезным, это не одна из них.

Краткий ответ: Точный ответ не может быть правильно рассчитан в базе данных, и фактически не должен .

<Ч />

Длинный ответ:

Расчеты возможны , но довольно сложны и определенно не подходят для расчета в базе данных. Я не собираюсь их здесь воспроизводить (посмотрите JodaTime , если вам интересно, в частности различные подклассы Chronology). Ваша самая большая проблема будет в том, что месяцы не одинаковы. Кроме того, вы столкнетесь с серьезными проблемами, если ваши временные метки будут отличаться от UTC, а точнее, переход на летнее время будет разрушать вычисления. Зачем? Потому что смещения могут измениться в любое время, для любой страны.

Может быть, вы могли бы объяснить почему вам нужно количество миллисекунд? Надеюсь, вы используете Java (или можете сделать это) и можете использовать java.time. Но если вы на iSeries, это, вероятно, RPG ...

1 голос
/ 07 октября 2011

Часть вашей ошибки возникает из-за неточности функции TIMESTAMPDIFF, как указали другие.

Другой источник ошибки возникает из-за того, что эпоха основана на времени по Гринвичу, поэтому вы должны учитывать местный часовой пояс.

Таким образом, вы можете сделать это с помощью следующего выражения:

(DAYS(timestamp('2011-10-04-13.54.50.000000') - current timezone) - DAYS('1970-01-01-00.00.00.000000')) * 86400 + MIDNIGHT_SECONDS(timestamp('2011-10-04-13.54.50.000000') - current timezone)

Вы можете написать простой UDF, чтобы упростить это:

create or replace function epoch (in db2ts timestamp)
   returns bigint
   language sql
   deterministic
   no external action
   return (days(db2ts - current timezone) - days('1970-01-01-00.00.00.000000')) * 86400 + midnight_seconds(db2ts - current timezone);

Удачи,

1 голос
/ 06 октября 2011

Согласно информационному центру v9.7 , TIMESTAMPDIFF возвращает расчетную разницу во времени, основанную на 365 днях в году (не соответствует истине ~ 25% времени), 30 дней в месяце (не соответствует действительности в 75% случаев, хотя в среднем это немного лучше), 24 часа в сутки (не соответствует действительности пару дней в году в некоторых часовых поясах), 60 минут в час (ура, один раз!) и 60 секунд в минуту (правда> 99,9% времени - мы получаем дополнительные секунды).

Итак, нет, это не способ получить время эпохи в DB2. До сих пор я прибегал к получению времени в качестве метки времени и преобразованию его в клиенте.

...