Привет, хабр!
На самом деле пост об одной строчке в документации, как оказалось. Но это было неожиданно, поэтому я решил поделиться с Вами найденным.

Новый проектик, новые таблицы, решил запилить для них тесты, и, в общем-то, был удивлён, когда первый же написанный мной тест сломался на том, что объект, который я закинул в базу, не равен этому же вычинанному из базы объекту.
После повторных запусков стало ясно, что миллисекунды не сходятся. Ну то есть берёшь, такой, объект, говоришь «вот тебе new Date(), а теперь запиши это в БД. А теперь прочти по айдишнику. А теперь equals. Чтоооо? О_о». Как-то так. И, да, внезапно тест может выполниться успешно.
После некоторых копаний выяснилась интересная вещь.
В документации на сайте Sybase есть описание используемых типов данных. Для типа данных datetime ещё в версии 15.0 ASE было лишь это:
если ссылка сломается, то Adaptive Server Enterprise 15.0 > Reference Manual: Building Blocks > System and User-Defined Datatypes > Date and time datatypes, где сказано, что
datetime columns hold dates between January 1, 1753 and December 31, 9999. datetime values are accurate to 1/300 second on platforms that support this level of granularity. Storage size is 8 bytes: 4 bytes for the number of days since the base date of January 1, 1900 and 4 bytes for the time of day.
Ещё раз обращаю внимание на то, что
datetime values are accurate to 1/300 second
В старших 4х байтах хранятся дни, а в младших 4х — время дня. В сутках 24часа*60минут*60секунд*1000миллисекунд = 86_400_000 миллисекунд в сутках, число, которое вполне влазит в 4 байта (0x5_26_5C_00). Даже для знакового бита есть место. Кто-нибудь, поделитесь, пожалуйста, как так нужно хранить время суток, чтобы оно не влезло?
Для версии ASE 15.7 немного расширено описание того, как ведёт себя этот тип данных.
Adaptive Server Enterprise 15.7 > Reference Manual: Building Blocks > System and User-Defined Datatypes > Date and time datatypes
datetime columns hold dates between January 1, 1753 and December 31, 9999. datetime values are accurate to 1/300 second on platforms that support this level of granularity. The last digit of the fractional second is always 0, 3, or 6. Other digits are rounded to one of these three digits, so 0 and 1 round to 0; 2, 3, and 4 round to 3; 5, 6, 7, and 8 round to 6; and 9 rounds to 10… Storage size is 8 bytes: 4 bytes for the number of days since the base date of January 1, 1900 and 4 bytes for the time of day.
То есть записываешь объект ты с одним таймштампом, а вычитываешь «почти то же самое, иногда даже точно такое же». Можно даже немного в будущее (на миллисекунду) отправиться, если выпадет девятка.
Ну, это задокументировано, так что это «не баг, а фича», претензий к Sybase никаких.
При всём при этом в ASE 15.7 есть
bigdatetime columns hold dates from January 1, 0001 to December 31, 9999 and 12:00:00.000000 AM to 11:59:59.999999 PM. Its storage size is 8 bytes. The internal representation of bigdatetime is a 64 bit integer containing the number of microseconds since 01/01/0000.

Мораль этого поста: RTFM and use bigdatetime, Luke!
Поделиться с друзьями
-->

Комментарии (2)


  1. Ogoun
    10.06.2016 12:37
    +1

    В случае когда нужно хранить и использовать даты, время обычно не несет смысловой нагрузки (если это не логи и не другие частные случаи). В этом случае при хранении в программе можно округлять именно до даты. Как, например, делаю в шарпе

    DateTime.Compare(Start.Date, End.Date)
    


  1. inversed
    10.06.2016 15:00

    В документации вас честно предупреждали что будет храниться примерное время с точностью до 1/300 секунды. Поэтому, всегда перед проектированием структуры БД стоит изучить всю специфику используемых типов данных.

    А Sybase вообще достаточно специфичная БД.
    Например, у нее не во всех редакциях есть уникальный идентификатор rowid, по которому можно однозначно идентифицировать конкретную запись в таблице — во всех остальных БД, с которыми я имел дело (SqlServer, Oracle, DB2, Teradata), такие идентификаторы есть.
    И с таблицами метаданных там не все так удобно и очевидно, как в родственном Sql Server.