среда, 23 февраля 2011 г.

Перевод даты из БД TopSpeed в DataTime

Пришлось на днях работать с базой данных TopSpeed компании Clarion.
Из первых впечатлений...
Положительные:

  • высокая скорость работы.

Отрицательные:
  • отсутствие odbc-драйвера для 64'х битной платформы (по крайней мере, мне их найти не удалось).
  • странный формат хранения даты.
Собственно о переводе даты из базы данных TopSpeed в привычное человеку представление здесь речь и пойдет.


Дата в этой базе данных хранится в виде целого числа. В связи со странным представлением даты я, не долго думая, отправился читать Google, но ничего толкового не обнаружил...
На данном этапе я имел только число 68900 и знал лишь, что это 19 августа 1989 года. После относительно нудных экспериментов, я выяснил, что дата в TopSpeed начинается с 29 декабря 1800 года. Очень странно, но факт... Те есть, для человека - 29.12.1800, а для базы данных TopSpeed - 1. Соответственно, для человека - 1.1.1801. Для БД - 3. И так далее по такой же логике.

После этих экспериментов, у меня нарисовались два метода для двустороннего перевода даты. Из TopSpeed в DateTime и обратно. Думаю, код поможет сэкономить время и нервы.

        /// <summary>
        /// Перевод даты из формата файла бд TopSpeed (tps) в формат DateTime.
        /// </summary>
        /// <param name="date">Дата в формате целого числа из файла бд TopSpeed (tps).</param>
        /// <returns>Дата в формате DateTime.</returns>
        private static DateTime TopSpeedDateToDateTime( int date )
        {
            int year = 1801;
            int month = 1;
            int day = 1;
            int dateTopSpeed = 3;
 
            // Вычисляем год
            for ( ; dateTopSpeed < date; year++ )
            {
                DateTime d = new DateTime( year, 12, 31 );
 
                if ( ( dateTopSpeed + d.DayOfYear ) > date )
                {
                    break;
                }
                dateTopSpeed += d.DayOfYear;
            }
 
            // Вычисляем месяц
            for ( ; dateTopSpeed < date; month++ )
            {
                if ( ( dateTopSpeed + DateTime.DaysInMonth( year, month ) ) > date )
                {
                    break;
                }
                dateTopSpeed += DateTime.DaysInMonth( year, month );
            }
 
            // Вычисляем день
            day = date - dateTopSpeed;
 
            return new DateTime( year, month, day );
        }
 
 
        /// <summary>
        /// Перевод даты из DateTime в формат даты бд TopSpeed (tps).
        /// </summary>
        /// <param name="date">Дата в формате DateTime.</param>
        /// <returns>>Дата в формате целого числа из файла бд TopSpeed (tps).</returns>
        private static int DateTimeToTopSpeedDate( DateTime date )
        {
            int year = 1801;
            int month = 1;
            int dateTopSpeed = 3;
 
            // Вычисляем год
            for ( ; year < date.Year; year++ )
            {
                DateTime d = new DateTime( year, 12, 31 );
                dateTopSpeed += d.DayOfYear;
            }
 
            // Вычисляем месяц
            for ( ; month < date.Month; month++ )
            {
                dateTopSpeed += DateTime.DaysInMonth( year, month );
            }
 
            // Вычисляем день
            dateTopSpeed += date.Day;
 
            return dateTopSpeed;
        }

22 комментария:

  1. Пятый раз смотрю на код и не понимаю зачем городить такие сложности.
    Всё проще.
    http://pastie.org/1675087

    ОтветитьУдалить
  2. Спасибо Паш за замечание =)
    Действительно все гораздо проще =)

    ОтветитьУдалить
  3. Способ, предложенный Пашей:
    static readonly DateTime TopSpeedEpoch = new DateTime(1800, 12, 28);

    private static int DateTimeToTopSpeedDate(DateTime date)
    {
    var span = date - TopSpeedEpoch;
    return span.Days;
    }

    private static DateTime TopSpeedDateToDateTime(int date)
    {
    var span = new TimeSpan(date, 0, 0, 0);
    return TopSpeedEpoch + span;
    }

    ОтветитьУдалить
  4. Зачем эти танцы с бубнами???
    Для перевода в норм представление числа из формата Клариона достаточно отнять - 36161. Соответственно чтобы перевести в формат Клариона +36161.... Все гениальное просто.

    ОтветитьУдалить
  5. Просто мне тоже пришлось на поработать с "этим" сегодня ((((.

    ОтветитьУдалить
  6. Будем иметь ввиду =)
    А от какой ИС база? Если не секрет? =)

    ОтветитьУдалить
  7. Зато столкнулся с другой проблемой... Не могу писать в таблицы через TopSpeed ODBC. (((

    КААААК?!

    ОтветитьУдалить
  8. В смысле не можете?

    У меня была проблема: данные писал, но ИС (Документы ПУ 5) не видела эти данные, не понятно почему - но факт. В итоге сделал перенос данных через экспорт/импорт без прямой загрузки в таблицы БД Clarion.

    ОтветитьУдалить
  9. Пример, у меня есть База которую я изменять не могу. Изучать Кларион нет желания. Я зацепил все таблицы которые у меня посыпались и данные в которых мне нужно было откорректировать. Сделал как СВЯЗАННЫЕ таблицы. Работал в АССЕSS 2003. Настроил связи, выходные формы. Стал забивать данные а они не вносятся. Таблицы в режиме чтения ONLY. ПОЧЕМУ?
    Как писать через ODBC в таблицы?

    ОтветитьУдалить
  10. Попробовал экспорт - импорт. Сначала импортировал... Потом экспортировал.
    помогло. А если таблиц не 5 а 100???

    ОтветитьУдалить
  11. Я, вроде, когда устанавливал ODBC-драйвер, при установке был выбор опции: чтобы тока читать, или и читать и записывать. Щас попробую уточнить...

    ОтветитьУдалить
  12. Не поделитесь своим драйвером? homemonster@inbox.ru

    ОтветитьУдалить
  13. Да, при установке, инсталлятор спрашивает в каком режиме установить драйвер.
    P.S.: Драйвер отправил.

    ОтветитьУдалить
  14. По свежее чем у меня. 2.1.0.0.0.
    У меня 2.0.0.0
    Есть 3.0.0.0.
    Буду искать

    ОтветитьУдалить
  15. Добейтесь, чтобы запись данных в таблицы заработала. Посмотрите, может исключение какое валится. А там, думаю, будет всеравно какая версия драйвера. Главное, чтобы оно работало и выполняло свои задачи.

    ОтветитьУдалить
  16. Добрый день.
    Не работает(((
    Нашел версию драйвера 5.05. В таблицу пишет запросы выполняет но !!! БЕЗУМНО МЕДЛЕННООО!!
    В чем трабл? Решил Тупо сделать экспорт в таблицы ассеss. Отработал свои алгоритмы... Ну, думаю, счас один раз запись в таблицу сделаю запросиком и алалуя! Фиг!!! Хоть запросом INSERT INTO, хоть через запись Recordset.AddNew ... Recordset.Udate... Вносится ровно 1392 записи из 2780 и все!(((

    ОтветитьУдалить
  17. Как запросом проверить на на повторяющиеся записи в ключе? сейчас проверил таблицу КЛАРИОНА там 4 поля. Все ключевые, т.е. ключ составной. Поробовал сделать так же поля ключевыми - он орет нифига!
    Из за повторяющихся значений в индексном поле
    .

    ОтветитьУдалить
  18. Эти индексные поля сильно повязаны с другими таблицами?
    Повторяющиеся строки можно проверить комбинаторно. Те грузите таблицу в DataTable и ищите копии.
    Фмшка в том, что повторяющихся записей в ключе быть не должно, поэтому не думаю что есть такие SQL-команды.

    ОтветитьУдалить