Преобразование строки в дату




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2025-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

17 Comments

  1. 3.14159
    Причиной создания этой функции послужил вот такой формат даты «1 Января 2015 г. 13:25»

    конструктор форматной строки для даты: ДФ=’d ММММ yyyy «г.» чч:мм’

    «йогурт без даты…» 🙂

    Reply
  2. Serg G

    (1) 3.14159, это когда вам известно, что в источнике все даты одного формата, а если нет? а если источник не один, а даты заполняют произвольно? и тд.

    Форматы, к сожалению, не всегда «делают погоду».

    Reply
  3. AnryMc

    😉

    Забыли «обратный» вариант написания дат: YYYY-MM-DD

    https://dev.1c-bitrix.ru/api_help/main/general/lang/format.php

    ЗЫ http://dev.1c-bitrix.ru/api_help/main/functions/date/formatdatefromdb.php

    Примеры использования

    echo FormatDateFromDB(’01/23/2013′, ‘DD MMMM YYYY’); // вернет 23 Enero 2013, если язык сайта испанский

    echo FormatDateFromDB(‘7 June 2012 12:00pm’, ‘SHORT’); // вернет 7 Июня 2012, если язык сайта русский и короткий формат языка — DD MMMM YYYY

    echo FormatDateFromDB(‘7 June 2012 12:00pm’); // вернет 7 Июня 2012 12:00pm, если язык русский и полный формат — DD MMMM YYYY G:MIT

    echo FormatDateFromDB(‘7 June 2012 12:00pm’, ‘DD.MM’); // вернет 07.06 для любого языка

    Reply
  4. Serg G

    (3) AnryMc, да, я знаю об этих национальных нюансах. Кстати, MS Excel и MS Access в коде VB используется нац.формат, а в запросах евро «mm/dd/yyyy» — вот где можно запутаться )))

    Что касается yyyy/*/* , то можно добавить проверку первого отбора(дней) и если количество сиволов = 4, то … и тут опять тупик: «а следующий месяц или дни?»

    С месяцами mm/dd/yyyy сложнее. Разве что контролировать на >12.

    Это сложно и сделать на автомате практически нереально. Нельзя определить 01/01/01 где тут месяцы, года и дни ) без дополнительных вопросов = формат

    Reply
  5. chmv

    Любопытно

    Reply
  6. premierex

    Автор, а про регулярные выражения и объект «VBScript.RegExp» Вы слышали?

    Вот такой шаблон, например: d{1,2}D{1}d{1,2}D{1}d{2,4} позволит выделить в строке дату или время из тестовых строк :

    27/082015 3-15-22 = 27/082015

    2/3/55 = 2/3/55

    05/3/15 = 05/3/15

    02/04/2015 = 02/04/2015

    27.08.2015 3:15:22 = 27.08.2015

    27.08-2015 5:24 = 27.08-2015

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

    Также можно написать шаблон для дат, в которых месяц указан прописью.

    Например, шаблон d{1,2}s+D+d{2,4} выделит из строки «1 ФеВраЛя 05 г. 20:01:0» строку «1 ФеВраЛя 05».

    В общем код сократится в разы!

    Reply
  7. Serg G

    (6) premier, Знаю и использовал. Так же знаю, что использование функции разбивающей строку на подстроки сократит код в . И?

    К слову, то, что вы не видите код и его количество в обьекте RegExp, это не значит, что его нет. ))

    Функция самодостаточна в рамках 1с — это огромный плюс.

    Протестируйте( в 1с), что будет быстрее работать, скажем с 100 000 строк. Но, можете не тратить время зря. )) Создание обьекта — это уже огромный «тормоз».А 100000 раз превращает такой вариант в кошмар. Так что, не вижу, ни единого плюса от RegExp в данном случае. Разве что, делать пакетную обработку столбца/структуры, что неудобно в рамках таблиц и циклов.

    Reply
  8. WKBAPKA

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

    Reply
  9. premierex

    (7) а кто запрещает создавать объект один раз за сеанс и сохранять его во временном хранилище? Где-то на Инфостарте я читал статью на эту тему. А то, что мы не видим код в объекте, позволяет нам не загромождать собственный код. Хотя, я впрочем — совсем не противник альтернативных вариантов. Просто механизм регулярных выражений достаточно мощный и что немаловажно язык — лаконичный. Ну и минусы, конечно есть — COM объект всё-таки, можно использовать только на клиенте.

    А вообще, конечно, при отсутствии описания используемого формата, достаточно велика погрешность преобразования. Например:

    Сообщить(СтрВДату(«2/3/55»)) вернёт 02.03.1955 0:00:00, хотя это может быть также и 01.01.0001 02:03:55 т.е. время, а может быть и 02.03.2055 0:00:00, в общем, вариантов много.

    Reply
  10. Serg G

    (9) premier, (9) premier, вы протестируйте на нескольких сотнях тыщ и будете удивлены. Только не пакетную передачу, а по одной переменной.

    ))) Блин….вы занудствуете. Если вам известно, что «2/3/55» это время, так передайте в функцию «1/1/01 «+»2/3/55» и не нужны никакие форматы!!! Вам же известно, что это время…. если, конечно, вы не Чумак или Кашпировский ))) Могли бы добавить критики, что функция не отрабатывает «// 2/3/55», а такой «2/3/55 //» делает )) Ну, я же надеялся на вас )

    Дам совет, а вы уже можете к нему прислушиваться или нет, это ваше дело. Не используйте никогда сторонние приложения если этого можно избежать. Причин для этого тьма, начиная от средств защиты системы, до самой ОС. Понимаете, между 1с и внешним обьектом может стоять анивирус/hips, зависит от настроек, и ваше приложение может работать нормально, а у пользователя жутко тормозить. Вы лысину заработает на правом яичке, но не догадаетесь, что у него стоит ESET NOD )))

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

    Эту функцию можно вставить в любой проект, даже «голый» и она отработает своё независимо, какие ActiveX/Com разрешены/запрещены/инфицированы/присутствуют и какая это версия — в этом ее огромный плюс.

    Более того, разделители же можно добавить, убрать,… гибкость и вариативность присутствует на откупе программиста. Каждый может подстроить под свои нужды или добавить большей универсальности. Но смысл и суть функции это : » меньше вопросов — больше дела». Есть дата(кстати, это не время) и она отработает ее по основным, часто встречающимся форматам, а точнее разделителям/делиметерам. Всё! Если ваш формат какой-то особый — это не для вас. Но в гуще своей, если вам встречаются данные с разными форматами, заполняемые разными программами, сканируемые неизвестно откуда и всё это нужно класть в одно место, зычно и красиво, вот, когда эта функция очень нужна.

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

    Reply
  11. premierex

    (10) убедили. «+» за идею, «-» за оформление кода. Мне, например, очень сложно было вникнуть в программный код, приведенный Вами. Ну, а вообще, конечно больше на «+» тянет. Большую работу проделали. Как говорится — «респект и уважуха».

    Reply
  12. NoRazum

    10/02/2016 00:33:07

    загнулась на таком дате (((

    версия платформы 8.3.8.1784

    Reply
  13. Romeooo

    Класс! Спасибо! была мелкая ошибка, добавил затык, а так работает отлично!

    Reply
  14. ZhokhovM

    не читаются месяцы «мая», «июня» и «июля», требуется доработка кода

    ошибка:

    Преобразование значения к типу Дата не может быть выполнено

    п_мТЕМП[6] = дата(п_мТЕМП[6]);

    Reply
  15. manson2017

    Если п_мТЕМП[2] = 5 Тогда

    п_мТЕМП[3] = «мая»;

    ИначеЕсли п_мТЕМП[2] = 6 Тогда

    п_мТЕМП[3] = «июня»;

    ИначеЕсли п_мТЕМП[2] = 7 Тогда

    п_мТЕМП[3] = «июля»;

    КонецЕсли;

    Reply
  16. shoy

    (14)

    п_мТЕМП[3] = ?(п_мТЕМП[3]=»май», «мая», ?(п_мТЕМП[3]=»июнь», «июня», ?(п_мТЕМП[3]=»июль», «июля», п_мТЕМП[3])));
    Reply
  17. ZhokhovM

    (16)По последним комментариям — все равно не подходит.

    Добавлял свой код:

    п_Месяцы = Новый Массив;
    п_Месяцы.Добавить(«янв»);
    п_Месяцы.Добавить(«фев»);
    п_Месяцы.Добавить(«мар»);
    п_Месяцы.Добавить(«апр»);
    п_Месяцы.Добавить(«ма»);
    п_Месяцы.Добавить(«июн»);
    п_Месяцы.Добавить(«июл»);
    п_Месяцы.Добавить(«авг»);
    п_Месяцы.Добавить(«сен»);
    п_Месяцы.Добавить(«окт»);
    п_Месяцы.Добавить(«ноя»);
    п_Месяцы.Добавить(«дек»);
    п_мФорматы[3] = п_Месяцы;
    …
    п_мТЕМП[3] = найти(п_мТЕМП[1], п_мФорматы[3][п_мТЕМП[2]]);
    п_мТЕМП[2] = п_мТЕМП[2]+1;
    // Берем из «янв.» только «янв»
    //п_мТЕМП[3] = СтрЗаменить(Формат(Дата(«2001» + Формат(п_мТЕМП[2],п_мФорматы[1]) + «01»), п_мФорматы[3]),».»,»»);// + локализация
    //п_мТЕМП[3] = найти(п_мТЕМП[1], п_мТЕМП[3]); (не читаются месяцы «мая», «июня» и «июля»)

    Показать

    Может где то еще добавлял.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *