diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -1,399 +1,413 @@
 #include "exitcode.h"
 #include "mainwindow.h"
 #include "psettings.h"
 #include "updater.h"
 #include <kactivityindicator.h>
 #include <ksettings.h>
 #include <sqlproc.h>
 #include <klogon_win.h>
 #include <QApplication>
 #include <QCloseEvent>
+#include <QDateTime>
 #include <QEvent>
 #include <QFileDialog>
 #include <QHBoxLayout>
 #include <QLabel>
 #include <QProgressBar>
 #include <QPushButton>
 #include <QShortcut>
 #include <QStandardPaths>
 #include <QStyle>
 #include <QTextCodec>
 #include <QTextEdit>
 #include <QTimer>
 #include <QVBoxLayout>
 #include <QtConcurrentRun>
+#include <time.h>
+
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags)
     : QDialog(parent, flags)
     , _exitCode(0)
     , _errorCount(0)
     , _updater(new DatabaseUpdater)
 {
     setWindowTitle(QStringLiteral("Создание/обновление базы данных"));
     setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
     setSizeGripEnabled(true);
 
     QHBoxLayout* mainLayout = new QHBoxLayout;
     QVBoxLayout* leftLayout = new QVBoxLayout;
     QVBoxLayout* rightLayout = new QVBoxLayout;
     QHBoxLayout* bottomRightLayout = new QHBoxLayout;
 
     leftLayout->setContentsMargins(0,
                                    2 * style()->pixelMetric(QStyle::PM_LayoutTopMargin),
                                    style()->pixelMetric(QStyle::PM_LayoutRightMargin), 0);
 
     QLabel* picture = new QLabel;
     picture->setPixmap(QPixmap(":/picture.png"));
 
     //кнопки, скрытые до завершения процесса
     _btnSave = new QPushButton(QStringLiteral("Сохранить"));
     _btnClose = new QPushButton(QStringLiteral("Закрыть"));
     _btnSave->setVisible(false);
     _btnClose->setVisible(false);
     _btnClose->setDefault(true);
 
     leftLayout->addWidget(picture);
     leftLayout->addStretch();
     leftLayout->addWidget(_btnSave);
     leftLayout->addWidget(_btnClose);
 
     QLabel* label = new QLabel(QStringLiteral("Протокол работы"));
     rightLayout->addWidget(label);
 
     _protocol = new QTextEdit();
     _protocol->setReadOnly(true);
     label->setBuddy(_protocol);
     rightLayout->addWidget(_protocol);
 
     //индикаторы выполнения
     _progress = new QProgressBar;
     _progress->setTextVisible(false);
     _ai = new KActivityIndicator;
     _ai->setVisible(false);
 
     bottomRightLayout->addWidget(_progress);
     bottomRightLayout->addWidget(_ai);
     rightLayout->addLayout(bottomRightLayout);
 
     mainLayout->addLayout(leftLayout);
     mainLayout->addLayout(rightLayout);
     setLayout(mainLayout);
 
     //нажатие Esc не соединяется со слотом, чтобы окно не закрывалось
     new QShortcut(QKeySequence(Qt::Key_Escape), this);
 
     //соединить сигналы со слотами
     connect(_btnSave, SIGNAL(clicked()), this, SLOT(saveProtocol()));
     connect(_btnClose, SIGNAL(clicked()), this, SLOT(closeDialog()));
 
     QTimer::singleShot(0, this, SLOT(startExecution()));
 }
 
 MainWindow::~MainWindow()
 {
     delete _updater;
 }
 
 //---------------------------------------------------------------------------
 void MainWindow::closeEvent(QCloseEvent* a_event)
 {
     if (_futureWatcher.isRunning())
         a_event->ignore();
     else
         a_event->accept();
 }
 
 //---------------------------------------------------------------------------
 void MainWindow::startExecution()
 {
     if (_futureWatcher.isRunning())
         return;
 
     ProgramSettings pset = processArguments();
     logon(pset);
     _logFile = pset.logFile;
 
     connect(_updater, SIGNAL(progress(int)), _progress, SLOT(setValue(int)));
     connect(_updater, SIGNAL(error(const QString&)), this, SLOT(error(const QString&)));
     connect(_updater, SIGNAL(message(const QString&)), this, SLOT(message(const QString&)));
     connect(_updater, SIGNAL(sqlError(const QString&, const QString&, const QString&)),
             this, SLOT(sqlError(const QString&, const QString&, const QString&)));
     connect(_updater, SIGNAL(logConnectionParameters(const QString&, const QString&, const QString&)),
             this, SLOT(logConnectionParameters(const QString&, const QString&, const QString&)));
     connect(&_futureWatcher, SIGNAL(finished()), this, SLOT(finishExecution()));
 
     _ai->setVisible(true);
     _ai->start();
 
     //int rc = _updater.run( pset );
     QFuture<int> rc = QtConcurrent::run(_updater, &DatabaseUpdater::run, pset);
     _futureWatcher.setFuture(rc);
 }
 
 //---------------------------------------------------------------------------
 void MainWindow::finishExecution()
 {
     _ai->stop();
     _ai->setVisible(false);
 
     //проверяем число ошибок, т.к. при выполнении без транзакции run() всегда возвращает 0
     if (_errorCount == 0)
     {
         ExitCode rc(_updater->revisionBefore(), _updater->revisionAfter());
         message(rc.message());
         _exitCode = rc.exitCode();
 
         closeDialog(); //при успешном завершении, то окно закрывается автоматически
     }
     else
     {
         _btnClose->show();
         _btnSave->show();
         _btnClose->setFocus();
         message(QStringLiteral("Выполнение прервано в результате ошибки.\nБаза данных не изменилась."));
         _exitCode = -1;
     }
 
     if (!_logFile.isEmpty())
         saveProtocol(_logFile);
 }
 
 //---------------------------------------------------------------------------
 int MainWindow::executeAction()
 {
     ProgramSettings pset = processArguments();
     logon(pset);
 
     _ai->start();
     DatabaseUpdater updater;
 
     connect(&updater, SIGNAL(progress(int)), _progress, SLOT(setValue(int)));
     connect(&updater, SIGNAL(error(const QString&)), this, SLOT(error(const QString&)));
     connect(&updater, SIGNAL(message(const QString&)), this, SLOT(message(const QString&)));
     connect(&updater, SIGNAL(sqlError(const QString&, const QString&, const QString&)),
             this, SLOT(sqlError(const QString&, const QString&, const QString&)));
     connect(&updater, SIGNAL(logConnectionParameters(const QString&, const QString&, const QString&)),
             this, SLOT(logConnectionParameters(const QString&, const QString&, const QString&)));
 
     int rc = updater.run(pset);
 
     //проверяем число ошибок, т.к. при выполнении без транзакции run() всегда возвращает 0
     if (_errorCount == 0)
     {
         int before = updater.revisionBefore();
         int after = updater.revisionAfter();
 
         if (before == after)
             message(QStringLiteral("База данных в актуальном состоянии."));
         else if (before == 0)
             message(QStringLiteral("База данных создана и обновлена до версии %1.").arg(after));
         else
             message(QStringLiteral("База данных версии %1 обновлена до версии %2.").arg(before).arg(after));
         rc = (before & 0xFFFF) | ((after & 0xFFFF) << 16);
     }
     else
     {
         _btnClose->show();
         _btnSave->show();
         _btnClose->setFocus();
         message(QStringLiteral("Выполнение прервано в результате ошибки."
                                   "<br>База данных не изменилась."));
         rc = -1;
     }
 
 
     return rc;
 }
 
 //---------------------------------------------------------------------------
 void MainWindow::logon(ProgramSettings& a_pset)
 {
     if (!a_pset.host.isEmpty() || !a_pset.username.isEmpty())
         return;
 
     KLogon* logon = KLogon::create();
     if (!logon)
         return;
 
     QString defaultDSN;
     QString ospoName;
 
     HKEY k;
     DWORD cb = 0;
     QString valuename("System Directory");
     if ((RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\irs\\b04"), 0, KEY_QUERY_VALUE, &k) == ERROR_SUCCESS
          || RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\irs\\b03"), 0, KEY_QUERY_VALUE, &k) == ERROR_SUCCESS)
         && RegQueryValueEx(k, LPCTSTR(valuename.constData()), 0, 0, 0, &cb) == ERROR_SUCCESS
         && cb > 0)
     {
         QString systemdir;
         systemdir.resize((cb / sizeof(QChar)) - 1);
         RegQueryValueEx(k, LPCTSTR(valuename.constData()), 0, 0, LPBYTE(systemdir.data()), &cb);
         RegCloseKey(k);
 
         KSettings systemini(systemdir + "/system.ini");
         systemini.beginGroup("Database");
         defaultDSN = systemini.value("DefaultDSN").toString();
         systemini.endGroup();
 
         systemini.beginGroup("Common");
         ospoName = systemini.value("SystemName").toString().replace(QLatin1Char('B'),QStringLiteral("ОСПО Б-"));
     }
     QString username = QString::fromLocal8Bit(qgetenv("USERNAME"));
     QHash<QString, QString> aliases = loadAliases(ospoName);
     if (aliases.contains(username))
         username = aliases[username];
     logon->setParent(winId());
     logon->setUsername(username);
     if (!defaultDSN.isNull())
         logon->setDSN(defaultDSN);
 
     if (!logon->execute())
         emit message(QStringLiteral("Отказ от ввода имени и пароля пользователя"));
     else
     {
         a_pset.host = logon->host();
         a_pset.username = logon->username();
         a_pset.password = logon->password();
     }
 
     delete logon;
 }
 
 //---------------------------------------------------------------------------
 QHash<QString, QString> MainWindow::loadAliases(const QString& a_ospoName)
 {
     QHash<QString, QString> result;
     QApplication::setOrganizationName(a_ospoName);
     QString filename = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(1);
     filename.replace(QApplication::applicationName(), QStringLiteral("aliases.conf"));
     QFile inf(filename);
     if (inf.open(QIODevice::ReadOnly))
     {
         QTextStream is(&inf);
         is.setCodec(QTextCodec::codecForName("UTF-8"));
         while ( !is.atEnd() )
         {
             QStringList chunks = is.readLine().split(QLatin1Char(':'));
             if (chunks.size() == 2)
                 result[chunks.at(0).trimmed()] = chunks.at(1).trimmed();
         }
     }
 
     return result;
 }
 
 //---------------------------------------------------------------------------
 void MainWindow::logConnectionParameters(const QString& a_host,
                                          const QString& a_database,
                                          const QString& a_username)
 {
     message(QStringLiteral("Подключение к базе данных\n"
                            "\tСервер: **%1**\n\tБаза данных: **%2**\n"
                            "\tПользователь: **%3**")
             .arg(a_host, a_database, a_username));
 }
 
 //---------------------------------------------------------------------------
 void MainWindow::sqlError(const QString& a_dbError,
                           const QString& a_commandDescription,
                           const QString& a_command)
 {
     QString errorHtml;
 
     if (!a_commandDescription.isEmpty())
         errorHtml.append(QStringLiteral("<font color=\"#0000FF\">Операция:</font><br>")).append(a_commandDescription).append("<br>");
 
     QString dbError = a_dbError;
     errorHtml.append(QStringLiteral("<font color=\"#0000FF\">Сообщение об ошибке:</font><pre>")).append(dbError.trimmed().replace('\n', "<br>")).append("</pre>");
 
     if (!a_command.isEmpty())
         errorHtml.append(QStringLiteral("<font color=\"#0000FF\">Текст команды:</font><pre>")).append(a_command).append("</pre>");
 
     errorHtmlToLog(errorHtml);
 }
 
 //---------------------------------------------------------------------------
 void MainWindow::error(const QString& a_error)
 {
     QString errorHtml = a_error;
     errorHtmlToLog(errorHtml.replace('<', "&lt;").replace('>', "&gt;").replace('\n', "<br>"));
 }
 
 //---------------------------------------------------------------------------
 void MainWindow::errorHtmlToLog(const QString& a_errorHtml)
 {
     QString errorHtml = a_errorHtml;
     QTextCursor cursor = _protocol->textCursor();
     cursor.insertHtml(QStringLiteral("<font color=\"#0000FF\">Ошибка</font><br>"));
     cursor.insertHtml(errorHtml);
     cursor.insertHtml(QStringLiteral("<hr>"));
     _protocol->moveCursor(QTextCursor::End);
     ++_errorCount;
 }
 
 QString MainWindow::toHtml(const QString& a_text)
 {
     QString result = a_text;
 
     static const QString BOLD = QStringLiteral("**");
     static const QString HTML_BOLD_BEGIN = QStringLiteral("<b>");
     static const QString HTML_BOLD_END = QStringLiteral("</b>");
     static const QString HTML_BR = QStringLiteral("<br>");
     static const QString HTML_NBSP = QStringLiteral("&nbsp;&nbsp;");
     static const QChar NL('\n');
     static const QChar TAB('\t');
 
     bool begin = true;
     int pos = result.indexOf(BOLD);
     while (pos >= 0)
     {
         result.replace(pos, BOLD.size(), begin ? HTML_BOLD_BEGIN : HTML_BOLD_END);
         begin = !begin;
         pos = result.indexOf(BOLD, pos + 1);
     }
 
     if (result.contains(NL))
         result.replace(NL, HTML_BR);
 
     if (result.contains(TAB))
         result.replace(TAB, HTML_NBSP);
 
     return result;
 }
 
 //---------------------------------------------------------------------------
 void MainWindow::message(const QString& a_message)
 {
     QString message = a_message;
     _protocol->textCursor().insertHtml(toHtml(message).append(QStringLiteral("<br>")));
     _protocol->moveCursor(QTextCursor::End);
 }
 
 //---------------------------------------------------------------------------
 void MainWindow::closeDialog()
 {
     QDialog::done(_exitCode);
 }
 
 //---------------------------------------------------------------------------
 void MainWindow::saveProtocol(const QString& a_fileName)
 {
     QString filename = a_fileName;
     if (filename.isEmpty())
         filename = QFileDialog::getSaveFileName(this,
                                                 QStringLiteral("Сохранить протокол в файл…"), QString(),
                                                 QStringLiteral("Текстовые файлы (*.txt);;Все файлы (*.*)"));
+
+    //если имя файла содержит символы %, то оно считается строкой формата для функции strftime,
+    //и выполняется подстановка текущего времени
+    if (filename.contains('%'))
+    {
+        char buffer[1024];
+        time_t ctime = QDateTime::currentSecsSinceEpoch();
+        strftime(buffer, sizeof(buffer), filename.toUtf8().constData(), localtime(&ctime));
+        filename = QString::fromUtf8(buffer);
+    }
+
     if (!filename.isEmpty())
     {
         QFile outf(filename);
         if (outf.open(QIODevice::WriteOnly | QIODevice::Truncate))
         {
             QTextStream os(&outf);
             os << _protocol->toPlainText().replace('\n', "\r\n");
         }
     }
 }
 
 //!главное окно приложения