Форум программистов, компьютерный форум, киберфорум
Delphi для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.60/15: Рейтинг темы: голосов - 15, средняя оценка - 4.60
1 / 1 / 0
Регистрация: 07.09.2021
Сообщений: 105
Delphi 6-7

Как извлечь из Эксель правильно формат дата в Делфи?

09.12.2021, 10:06. Показов 3792. Ответов 41
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день уважаемые форумчане. Пытаюсь помочь музейщикам в их нелегкой кропотливой работе по выгрузке данных по труженикам тыла. Проект похож на участников ВОВ, тему я тут по ним создавал и с вашей помощью успешно справился Функция поиска и индексации методом TStringgrid

По труженикам тыла программу делаю основываясь на предыдущей разработке. Т.е. подключаюсь к эксель через адо. Все норм, кроме одного момента: Даты в столбике забиты в разнобой. Где то просто год, допустим 1899, а где то полноразмерная дата: 04.12.1909.
Там, где просто год - все нормально. А там где полноразмерная дата, в дбгрид выводится какое то преобразованное число.
Естественно в самом эксель у ячеек где просто год присвоен формат общий, а там где полноразмерная дата, он преобразовал ее в дату.

Пробовал создать простенький "проверятор" на корректность даты. Если число больше определенного значения, то пытаться считать поле как дату.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
procedure TForm1.DBGrid1CellClick(Column: TColumn);
var
d: TDateTime;
l:integer;
begin
if dbgrid1.Fields[3].AsInteger>1970 then
  begin
     d:=dbgrid1.Fields[3].AsDateTime;
     Label1.Caption:=DateToStr(d);
  end
else
  label1.Caption:=dbgrid1.Fields[3].AsString
 
end;
Но программа крашится. Т.е. в адб дата уже в числовом формате.

И вот я ломаю голову как мне это обойти. Копался в интернете но ничего не нашел.

сам код загрузки эксель через адб (смотреть нужно ADOQuery3. ADOQuery1,2 и 4 нужны для подгрузки списка комбобокс и таблицы расшифровки населенных пунктов):
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
procedure TForm1.BitBtn2Click(Sender: TObject);
var
EXLApp, vActiveWorkBook : variant;
Sheet : OleVariant;
st : string;
i,k : integer;
b : boolean;
begin
if Opendialog1.Execute then   //если файл экспорта выбран
  begin
    //пытаемся узнать наименование листа в эксель книге, для чего приходится
    //сначала открывать рабочую книгу через OLEObject
    EXlApp := CreateOleObject('Excel.Application');
    EXlApp.workbooks.Add(OpenDialog1.FileName);
    tablename:= '['+ExlApp.Sheets[1].Name + '$]';
    ExlApp.workbooks.close;
    ExlApp.quit;
    ExlApp:=unassigned;
 
    ADOQuery3.Active:=false;    //блок связывания эксель в качестве бд через ADO
    ADOConnection2.Connected:=false;
    adoconnection2.ConnectionString:='Provider =Microsoft.ACE.OLEDB.12.0; Data Source ='+opendialog1.FileName+'; Extended Properties ="Excel 12.0 Xml;HDR=YES;ReadOnly=false"';
    ADOQuery1.Active:=true;
    ADOQuery3.SQL.Clear;
    ADOQuery3.SQL.Add('SELECT DISTINCT "Место рождения" FROM ' + tablename + ' WHERE ("Место рождения" IS NOT NULL) and (Vigruz IS NULL)');
    ADOQuery3.Open;
    ADOQuery2.SQL.Clear;
    ADOQuery2.SQL.Add('select * from adres');
    ADOQuery2.Open;
    ADOQuery1.Last;
    i := ADOQuery1.Fields[0].AsInteger;
 
    While not ADOQuery3.Eof do     //заполняем список комбобокс уникальными непустыми значеняимя поля 'MESTO_ROG'
      begin
        st := ADOQuery3.Fields[0].AsString;
        while pos('"',st)<>0 do delete(st,pos('"',st),1); //убираем из строки с н.п. кавычки, т.к. они искажают SQL запрос
        b := ADOQuery1.Locate('Adres',st,[]);
        if b = false then
           begin
                inc(i);
                ADOQuery2.SQL.Clear;
                ADOQuery2.SQL.Add('INSERT INTO Adres(AdresID, Adres) Values("' + inttostr(i) + '", "' + st + '")');
                ADOQuery2.ExecSQL;
                ADOQuery1.Close;
                ADOQuery1.Open;
           end;
        ADOQuery3.Next;
      end;
    DBLookUPCombobox1.KeyValue:=1;
    ADOQuery3.SQL.Clear;         //Экспортируем выбранный файл ексель в таблицу DBGRID1
    ADOQuery3.SQL.Add('SELECT * FROM ' + tablename);
    ADOQuery3.Open;
    DBGrid2.Enabled:=true;
    DBGrid1.Enabled:=true;
    DBGrid1.Visible:=true;
    ADOConnection1.Connected:=true;
    DataSource1.Enabled:=true;
    BitBtn4.Enabled:=true;
    DBLookUpCombobox1.Enabled:=true;
    RadioButton1.Enabled:=true;
    RadioButton2.Enabled:=true;
    CheckBox2.Enabled:=true;
    k:=DBLookupcombobox1.KeyValue;
    ADOQuery4.SQL.Clear;
    ADOQuery4.SQL.add('SELECT * FROM Description where Description.Adres_ID=' + inttostr(k));
    ADOQuery4.Open;
    DBGrid2.Enabled:=true;
    ADOConnection1.Connected:=true;
    If RadioButton2.Enabled = true then
        if Radiobutton2.Checked then
             begin
                 ADOQuery3.Active:=false;
                 DBGrid1.Enabled:=false;
                 ADOQuery3.SQL.Clear;
                 ADOQuery3.SQL.Add('SELECT * FROM ' + tablename + ' WHERE "Место рождения" = "' + DBLookupcombobox1.Text + '"');
                 ADOQuery3.Active:=true;
                 DBGrid1.Enabled:=true;
            end;
  end;
 
end;
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
09.12.2021, 10:06
Ответы с готовыми решениями:

дата выдачи кредита - 11.11.11. дата погашения 11.12.11. Как записать это в делфи и решить это в делфи?
Имеетс:)я задача в ходе которой надо вычислить кол-во дней. Даны данные: дата выдачи кредита - 11.11.11. дата погашения 11.12.11. Как...

Формат поля = Дата + краткий формат времени - часы отображаются одной цыферой хоть задано ДВЕ!
Форумчане! - только на вас надеюсь - у меня идеи закончились. Итак: Поле в таблице в формате полой даты времени, на форме нужно вывести...

Как изменить формат <Дата> и <Номер> в макете?
есть запрос: Процедура ПечатьЗаявки(ТабДок, Ссылка) Экспорт //{{_КОНСТРУКТОР_ПЕЧАТИ(ПечатьЗаявки) Макет =...

41
1 / 1 / 0
Регистрация: 07.09.2021
Сообщений: 105
10.12.2021, 13:28  [ТС]
Студворк — интернет-сервис помощи студентам
если известно имя, тогда вообще не надо предварительно ее узнавать. С этой позиции тогда лучше оставить старую версию с открытием через GetOleObject

Добавлено через 1 минуту
Цитата Сообщение от qwertehok Посмотреть сообщение
ну бери первый лист который не database
Кстати мысль
0
6005 / 4580 / 1096
Регистрация: 29.08.2013
Сообщений: 28,288
Записей в блоге: 3
10.12.2021, 13:45
Цитата Сообщение от esgard Посмотреть сообщение
С этой позиции тогда лучше оставить старую версию с открытием через GetOleObject
тогда и работать с экселем можно с помощью методов OLE
0
1 / 1 / 0
Регистрация: 07.09.2021
Сообщений: 105
10.12.2021, 13:48  [ТС]
Цитата Сообщение от qwertehok Посмотреть сообщение
тогда и работать с экселем можно с помощью методов OLE
Гораздо медленнее чем через АДО
0
AxBxC=X
 Аватар для harrybook
155 / 135 / 58
Регистрация: 27.04.2016
Сообщений: 549
10.12.2021, 14:03
Как вариант: экспортировать таблицы в dbf и работать с ними.
Предварительно сменить назавания заголовков колонок на латиницу (<=8 символов, без пробелов, 1-й символ не цифра)
0
6005 / 4580 / 1096
Регистрация: 29.08.2013
Сообщений: 28,288
Записей в блоге: 3
10.12.2021, 14:10
Цитата Сообщение от esgard Посмотреть сообщение
Гораздо медленнее чем через АДО
ты просто готовить не умеешь

поищи - была статья как работать с экселем с помощью массивов, а не по строчно
0
 Аватар для Пытливый
3765 / 2272 / 706
Регистрация: 29.05.2013
Сообщений: 9,622
10.12.2021, 14:13
А вы хоть посмотрели, что такое эта ваша База_данных? А стоило. Это именованная область всех данных из искомой таблицы, т.е. запрос вида select * from База_данных вернет вам требуемый набор данных и не надо получать никаких других имен листов.
0
6005 / 4580 / 1096
Регистрация: 29.08.2013
Сообщений: 28,288
Записей в блоге: 3
10.12.2021, 14:13
Пытливый, а он не знает название листа, они как попало называются

я бы выводил пользователю combobox с листами и пусть сами выбирают
0
 Аватар для Пытливый
3765 / 2272 / 706
Регистрация: 29.05.2013
Сообщений: 9,622
10.12.2021, 14:18
Да не нужно ему знать название листа, оно вообще может быть каким угодно. Автор эксельной таблицы просто выделил весь блок данных и дал ему псевдоним База_данных. Теперь это такой-же объект в книге как и лист и вы хоть как называйте лист, а псевдоним останется неизменным.
0
1 / 1 / 0
Регистрация: 07.09.2021
Сообщений: 105
10.12.2021, 15:38  [ТС]
А как мне тогда обратиться к этой базе данных? В одной таблице это допустим database, в другой таблице я такого вообще не увидел. Вообще запутался...
Узнавать наименование листа через GetOleObject является пока что безотказным методом, пусть это и костыль.

Добавлено через 2 минуты
Цитата Сообщение от qwertehok Посмотреть сообщение
ты просто готовить не умеешь
Так и есть.
Цитата Сообщение от qwertehok Посмотреть сообщение
поищи - была статья как работать с экселем с помощью массивов, а не по строчно
А вывести список из таблицы в dbgrid я так же смогу?
0
 Аватар для Пытливый
3765 / 2272 / 706
Регистрация: 29.05.2013
Сообщений: 9,622
10.12.2021, 16:08
Цитата Сообщение от esgard Посмотреть сообщение
В одной таблице это допустим database, в другой таблице я такого вообще не увидел.
Стоп. Я видимо что-то пропустил, т.е. у вас как минимум два разных по структуре файла эксель, а не один из первоначальной темы. Тогда конечно данный метод сработает только на первом файле, а на втором даст ошибку. Тогда уточняющий вопросы.
1. К вам эти файлы поступают к вам с изменениями или же это каждый раз новые данные?
2. Структура самой таблицы при этом меняется?
3. Название листа меняется?
4. Каждый из файлов при поступлении имеет неизменное имя?
0
1 / 1 / 0
Регистрация: 07.09.2021
Сообщений: 105
10.12.2021, 16:19  [ТС]
Цитата Сообщение от Пытливый Посмотреть сообщение
Стоп. Я видимо что-то пропустил, т.е. у вас как минимум два разных по структуре файла эксель, а не один из первоначальной темы. Тогда конечно данный метод сработает только на первом файле, а на втором даст ошибку. Тогда уточняющий вопросы.
1. К вам эти файлы поступают к вам с изменениями или же это каждый раз новые данные?
2. Структура самой таблицы при этом меняется?
3. Название листа меняется?
4. Каждый из файлов при поступлении имеет неизменное имя?
Ну тут моя вина. Какие вводные данные, такие и советы)

Я делаю 2 подобные программки, про участников великой отечественной войны, и ветеранов труда. Первую уже сделал. На ее основе сейчас занимаюсь второй, т.к. структурно данные похожи и методы обработки схожи.

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

1) Сказать как будет называться точно другой лист с данными у другого района - я не могу. Те, кто составляет эти таблицы могут обозвать его как угодно.
2) структурно скорее всего она будет такой же. Но в случае чего вручную подкорректировать позицию столбцов можно будет самому пользователю.
3) ответил в первом пункте)
4) Название файлов разное, но конкретно здесь это не имеет значения, ибо в программа предусмотрено, чтобы пользователь сам выбирал файл для загрузки через опендиалог.
0
1 / 1 / 0
Регистрация: 07.09.2021
Сообщений: 105
13.12.2021, 10:36  [ТС]
Цитата Сообщение от Пытливый Посмотреть сообщение
А вот что касается первоначального вопроса по дате, то тут все проще. Дело в том, что Ado читая данные их таблицы, строит набор полей анализируя содержимое первых 10 строк. И если у вас там встречается хотя-бы одно поле не содержащее данных, то поле считается строковым. Бороться с этим можно с помощью создания специального файла описателя структуры schema.ini, где в явном виде задаются типы полей. Вот как выглядит содержание такого файла:
КодВыделить код
[20180601-20180607.xls]
ColNameHeader=False
MaxScanRows=0
CharacterSet=ANSI
Format=TabDelimited
TextDelimiter=none
DecimalSymbol=.
Col1=Date
Col2=Date
Col3=Date
Col4=Date
Col5=Date
Col6=Text
Col7=Text
Col8=Text
Попытался по вышеприведенной схеме описать все поля текстовыми (так как с ними проще работать) но бд все равно считает эти поля типом флоат.
Я в описании где то ошибку допустил?
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[Труженики тыла.xls]
ColNameHeader=True
MaxScanRows=0
CharacterSet=ANSI
Format=TabDelimited
TextDelimiter=none
DecimalSymbol=.
Vigruz=Text
"№ п/п"=text
"Год рождения"=Text
"Место рождения"=Text
"Место жительства на момент награждения"=Text
"Государственные награды за труд в тылу"=Text
"Место работы"=Text
"Должность"=Text
"Почетные звания за труд в тылу"=Text
"Дата смерти"=Text
"Место захоронения"=Text
"Источник информации"=Text
"примечания"=Text
0
 Аватар для Пытливый
3765 / 2272 / 706
Регистрация: 29.05.2013
Сообщений: 9,622
13.12.2021, 15:23
Проверил, не работает. Стал вспоминать как же это у меня-то работало когда-то. И ведь вспомнил, но к сожалению вам это не поможет. Передавали мне для обработки файлы с расширением .xls, которые на самом деле были .csv и для них я использовал такую схему.
Каюсь, обманул. Прошу понять и простить.
0
1 / 1 / 0
Регистрация: 07.09.2021
Сообщений: 105
13.12.2021, 15:51  [ТС]
Все мы заблуждаемся и ошибаемся) Не ошибается только тот, кто ничего не делает)
В общем пока пришел к тому, что надо исправить даты с порядкового номера на нормальный.
Тут и затык.
Пытался это реализовать 2 методами:
1) Через редактирование таблицы методом ADO.Edit
Delphi
1
2
3
4
5
6
7
8
9
10
    While not Adoquery3.Eof do //исправляем исковерканные экселем даты
          begin
          l:= dbgrid1.Fields[3].AsInteger;
          if l>1990 then
                  begin
                  ADOQuery3.Edit;
                  ShowMessage(DateToStr(IncDay(MyDate,l-2)) + 'строка № ' + inttostr(ADOQuery3.RecNo));
                  ADOQuery3.Fields[3].AsFloat := IncDay(MyDate,l-2);
                  ADOQuery3.Post;
                  end;
Первую дату вроде бы исправляет без ошибок

Вторая точно такая же на вид

Но заканчивается ошибкой.


Пробовал добавлять после ADO.Post открытие и закрытие ADO. Но тогда он просто бесконечно выводит первую дату. Т.е. исправления фактически не происходит.

2) Через SQL запрос "Update".

Delphi
1
2
3
4
5
6
7
8
9
10
11
    While not Adoquery3.Eof do //исправляем исковерканные экселем даты
          begin
 
          l:= dbgrid1.Fields[3].AsInteger;
          if l>1990 then
                  begin
                  ADOQuery5.SQL.Clear;
                  ADOQuery5.SQL.Add('Update ' + tablename + ' SET "Год рождения" = "' + DateToStr(IncDay(MyDate,l-2)) + '"');
                  ADOQuery5.SQL.Add(' WHERE "Год рождения" = "' + inttostr(l) + '"');
                  ADOQuery5.ExecSQL;
                  end;
Результирующий запрос получается таким

Ошибка вылезает как будто бы в ADO отсутствуют данные.

Пробовал перед этим в том же АДО5 делать запрос "SElect * FROM" - бес толку. Адо5 как и адо3 привязаны к адоконнектишон2, который в свою очередь связывается с эксель. Но датасеты у них разные.

Я уже окончательно запутался, что я не так делаю)))
0
 Аватар для Аватар
5393 / 1465 / 513
Регистрация: 31.05.2012
Сообщений: 5,153
13.12.2021, 16:16
Можно попробовать нужные поля в строку запросом, в проге со строкой будет проще
SQL
1
SELECT CAST(F1 AS VARCHAR(20)) AS F1,...
0
1 / 1 / 0
Регистрация: 07.09.2021
Сообщений: 105
13.12.2021, 17:01  [ТС]
Кажется начинаю понимать почему с запросом update не получалось. Вместо двойных кавычек " надо было использовать апострофы `
0
 Аватар для Пытливый
3765 / 2272 / 706
Регистрация: 29.05.2013
Сообщений: 9,622
13.12.2021, 17:20
Возьмите название поля в квадратные скобки, а не в апострофы. [Год рождения]
1
1 / 1 / 0
Регистрация: 07.09.2021
Сообщений: 105
20.12.2021, 10:51  [ТС]
Блин. Который день уже бьюсь над проблемой исправления кривых дат. И все как головой об стену -результат нулевой.
Если стоблец в экселе предварительно сделать как текстовый, то адо его воспринимает как текстовый соответственно. Но вылезает проблема с датами. И вот на этапе приведения дат к удобочитаемому виду и вылезает бяка.

как видим тип данных WideString. При попытке сохранить текст вылезает ошибка:


Без разницы щелкаешь ты по другому полю в DBGrid или же через обработчик в отдельной кнопке:
Delphi
1
2
ADOQuery3.Edit;
ADOQuery3.Post;
То ли он его пытается сохранить как дату...
0
 Аватар для Аватар
5393 / 1465 / 513
Регистрация: 31.05.2012
Сообщений: 5,153
20.12.2021, 11:10
Ты же пишешь результат преобразования в то же самое строковое поле, у которого есть фиксированная длина. И этой длины мало для записи развернутой даты , если widechar то для даты нужно 20 байт.
0
1 / 1 / 0
Регистрация: 07.09.2021
Сообщений: 105
20.12.2021, 12:07  [ТС]
И эту проблему с помощью адо никак не обойти?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
20.12.2021, 12:07

Как задать формат колонки дата-грида программно?
Нашла такой вариант в xaml: &lt;DataGridTextColumn Binding=&quot;{Binding Дата, StringFormat=dd:mm:yyyy}&quot;/&gt;, но нужно еще сделать проверку на то,...

Как поменять формат даты у пользовательского свойства с типом дата?
Здравствуйте! Подскажите пожалуйста, есть свойство с типом дата, как поменять формат даты, в данный момент выводится вот так 20.09.2018, а...

Как проверить, что дата подходит под наш формат времени?
Дата вводится в maskedBox в формате дд.мм.гггг. И мне нужно проверить, что это дата корректная и подходит по наш формат записи дат. Как это...

делфи и эксель
привет всем помогите плз есть бд в экселе надо сделать несколько манипуляций с ней, добавление записи, просмотр и тд.есть несколько...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Про "Windows must die!"
kumehtar 04.11.2026
Знаете, чет накатило. . . . Когда-то это было почти боевым кличем: мол, нормальный человек сидит на DOS, OS/ 2 или Linux, а вот это вот - Must Die. А теперь человек произносит «мастдай» с усмешкой - и. . .
Красочные поля с номером страницы svg+background-image
russiannick 04.11.2026
Красочные поля с номером страницы не менее важны чем в эпоху бумажных книг. Посему спешу представить почтеннейшей публике этот важный инструмент который эти поля и формирует. В процессе разработки. . .
Вступаем в новую фазу генерации favicons, векторную.
russiannick 02.11.2026
Теперь нет нужды скрывать что используется простой svg. Исходный код изображения помещаем в поле и жмем кнопку. Исходник преобразуется в вид корректный для помещения в favicon или в url(). Нажатие. . .
Генератор паролей (вариант №4)
Maks 01.11.2026
После публикации 3-го варианта генератора паролей, разослал его своим коллегам (с целью оценки), в итоге были получены следующие рекомендации: 1. Вернуть возможность использования знаков | 1 l I;. . .
Генератор паролей (вариант №3)
Maks 30.10.2026
Финальная версия генератора паролей 1С. Доработка решения в этот раз коснулась только визуальной части, а именно, добавлен реквизит ДопПараметры (тип Булево), который скрывает/ отображает реквизиты:. . .
Магическое мышление и магия, современная наука не отличима от магии (говорит ИИ Джемени)
zorxor 30.10.2026
Джемени, расскажи, пожалуйста, что такое магическое мышление, что такое магия, почему современная наука чем-то напоминает магию? Фраза «Любая достаточно развитая технология неотличима от магии». . .
За какое время ИИ может подобрать пароль по хешу (рассказывает Джемени ИИ)
zorxor 30.10.2026
Расскажи, Джемени, если известен хэш МД5, например, за сколько ИИ сможет подобрать соответствующий пароль? Искусственный интеллект (ИИ) может подобрать простой или средний по сложности пароль по. . .
Кто убил Suno? Почему наше солнышко погасло? (диалог с ИИ Джемени)
zorxor 30.10.2026
Как убивали Suno. Хронология. «Убийство» музыкальной нейросети Suno — это затяжной процесс, в котором технологический хайп стартапа разбился о жесткую реальность судебных исков от гигантов. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru