Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - TDateTime - Операции с временем [вычитание, сложение]

Ответить
Настройки темы
C/C++ - TDateTime - Операции с временем [вычитание, сложение]

Аватара для Drongo

Будем жить, Маэстро...


Сообщения: 6694
Благодарности: 1393


Конфигурация

Профиль | Сайт | Отправить PM | Цитировать


Приветствую всех.

Друзья, понадобилась ваша помощь, самостоятельно решить не могу, вернее, только частично. Пишу парсер логов AVZ. В программу добавил функцию поиска файлов, созданых в определённый промежуток времени - 30 дней с момента создания лога AVZ. В логе AVZ эта строка означает дату сканирования
Код: Выделить весь код
LogDate="7/17/2010 10:33:29 PM"
Переменная DataScan в ней хранится уже извлечённая дата
Код: Выделить весь код
DataScan = "7/17/2010 10:33:29 PM"
В таком же формате времени записаны даты создания файлов.
Переменная AnsiString str хранит передаваемую дату создания файла.

Задача: Как правильно вычесть одну дату из другой?
Код: Выделить весь код
DataScan - str
Если в логах AVZ формат даты может быть разным:

Код: Выделить весь код
7/17/2010 10:33:29 PM - Месяц/День/Год - M/D/YYYY
20.03.2010 19:14:48 - День.Месяц.Год - DD.MM.YYYY
19.Jul.2010 19:14:48 - День.Месяц.Год
20.03.2010 19:14:48 - День-Месяц-Год - DD-MM-YYYY
В общем любой формат времени из возможных с любым разделителем. Как из дат различных форматов правильно произвести вычитание?


С последним форматом проблем нет, также можно заменить разделитель /, - на точку. Друг помог с форматом 19.Jul.2010 19:14:48

Функция SearchCreateToNMounth принимает два аргумента: 1-й дату, 2-й полное имя файла.


Мой код
Код: Выделить весь код
// Поиск файлов созданых в течении 1, 2, 3-х месяцев-------------------------
void __fastcall TForm1::SearchCreateToNMounth(String str, String nf)
{
   // Вычисляем диапазон создания файла
   TDateTime tmp = StrToDateTime(StrToDateTime(MyDate(DateScan)) - StrToDateTime(MyDate(str)));

   if((int)tmp <= 3){
      Edit3->Text = String(nf) + " = " + DateScan;
     }                     
}
// BadDate - это дата, которую нужно проверить на "правильность" записи. Допустим, "3-Окт-17 23:22:21"
AnsiString __fastcall TForm1::MyDate(String BadDate)
{
   String MonthRUS[13]={"", "Янв", "Фвр", "Мрт", "Апр", "Май", "Июн", "Июл", "Агс", "Снт", "Окт", "Нбр", "Дкб"}; 
   String MonthENG[13]={"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

   for(int i = 1; i <= 12; i++){
      BadDate = StringReplace(BadDate, MonthENG[i], i, TReplaceFlags()<<rfReplaceAll);  //Здесь мы заменяем название месяца на его порядковый номер
      BadDate = StringReplace(BadDate, MonthRUS[i], i, TReplaceFlags()<<rfReplaceAll);  //Здесь мы заменяем название месяца на его порядковый номер
     }
   ShortDateFormat = "dd.mm.yyyy";  //Устанавливаем вид "правильной" даты
   for(int i = 1; i < BadDate.Length(); i++){  //Вот здесь мы начинаем проходить циклом по всей записи
      if(!(BadDate[i] >= '0' && BadDate[i] <= '9')){   // И ищем тот символ, который не является цифрой
         DateSeparator = BadDate[i];
         break;
        }   //Как только находим его - делаем его разделителем и прерываем цикл (обязательно, иначе конечным символом станет ":", потому что это будет последняя "не цифра")
   }
   BadDate = StrToDateTime(BadDate);   //Теперь приводим к нужному формату записи
   return BadDate; //И возвращаем
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   AnsiString Time = "6/17/2010 10:07:11 PM";   //Edit1->Text; 5/17/2010 10:07:11 PM
   AnsiString NameFile = "C:\\WinXP\\MyFile.exe";
   SearchCreateToNMounth(Time, NameFile);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
   DateScan = Edit2->Text;  //Edit2->Text; 4/17/2010 10:07:11 PM
}
//---------------------------------------------------------------------------

Ошибку выдаёт такую



Про операции проводимые с временем читал здесь и здесь

Что я не так делаю? Если не трудно, подскажите как можно это сделать правильно?

Спасибо.

-------
Правильная постановка вопроса свидетельствует о некотором знакомстве с делом.
3нание бывает двух видов. Мы сами знаем предмет — или же знаем, где найти о нём сведения.
[Quick Killer 3.0 Final [OSZone.net]] | [Quick Killer 3.0 Final [SafeZone.cc]] | [Парсер логов Gmer] | [Парсер логов AVZ]

http://tools.oszone.net/Drongo/Userbar/SafeZone_cc.gif


Отправлено: 14:55, 19-07-2010

 
pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Можно сделать угадывалку (по типу угадывалки кодировки в Total Commander) примерно так:
Код: Выделить весь код
#include <vector>
using namespace std;

class GuessDateFormat
{
public:
    enum state_t {
        state_ready, // угадал
        state_not_enough, // есть неоднозначности, не хватает примеров
        state_umbiguity // противоречивые примеры
    };

    GuessDateFormat();
    void add_sample(const char* date_str);
    state_t state() const;
    bool convert(const char* from, time_t& to);

private:
    enum {
            like_nothing = 0x0000,  // битовые поля "похоже на..."
            like_year = 0x0001,
            like_mon  = 0x0002,
            like_mday = 0x0004,
            like_wday = 0x0008,
            like_hour = 0x0010,
            like_min  = 0x0020,
            like_sec  = 0x0040,
            like_pm   = 0x0080,    // pm/am
            like_amon = 0x0100,    // месяц прописью
            like_date = like_year|like_mon|like_mday|like_amon,
            like_time = like_hour|like_min|like_sec,
            like_alpha = like_amon|like_pm,
            like_everything = 0x01ff,

            got_pm          = 0x01,
            got_year2000    = 0x02,
            got_amon        = 0x04
    };

    vector<short> _like_what; // каждый элемент показывает, на что похоже содержимое позиции
    short _its_clear, _expecting; // какие элементы точно выяснены

    void _suspecting_one(int);
    void _suspecting_pair(int);
};

bool GuessDateFormat::convert(const char* from, time_t& to)
{
    typedef struct tm tm_t;
    tm_t tm1 = {};

    vector<short>::iterator first=_like_what.begin(), last=_like_what.end();

    while ( *from && first!=last)
    {
        // найти первый подходящий символ
        while (!isalnum(*from) && *++from) {}

        if (*from)
        {
            switch ( *first)
            {
                case like_year :
                    tm1.tm_year = atoi(from);
                    break;

                case like_mon :
                    tm1.tm_mday = atoi(from)-1;
                    break;

                case like_mday :
                    tm1.tm_mday = atoi(from);
                    break;

                case like_hour :
                    tm1.tm_hour = atoi(from);
                    break;

                case like_min :
                    tm1.tm_min = atoi(from);
                    break;

                case like_sec :
                    tm1.tm_sec = atoi(from);
                    break;

                case like_pm :
                    // думаем что PM после времени пишется.
                    if (*from=='P') tm1.tm_hour += 12;
                    break;

                case like_amon :
                    // выбрать месяц из справочника
                    break;
            }
        }

        while (isalnum(*from) && *++from) {}
    }

    to = mktime(&tm1);
    return true;
}

GuessDateFormat::state_t GuessDateFormat::state() const
{
    for (vector<short>::iterator first=_like_what.begin(),
            last=_like_what.end(); first!=last; ++first)
    {
        short n = *first;
        if (!n) return state_umbiguity;
        while ( !(n & 1)) n>>=1;
        if (n & (~1)) return state_not_enough;
    }

    return state_ready;
}

void GuessDateFormat::_suspecting_one(int bitset)
{
    _like_what.push_back(bitset & _expecting);
    _expecting = like_everything;
}

void GuessDateFormat::_suspecting_pair(int bitset)
{
    if (!_like_what.empty()) *(_like_what.end()-1) &= bitset;
    _expecting = bitset;
}

bool GuessDateFormat::add_sample(const char* date_str)
{
    // отмели простейший случай
    if (!date_str || !*date_str) return false;

    _expecting = like_everything;
    _its_clear = 0;

    do
    {
        short suspecting = _expecting;

        // пропустили пробелы
        while (*date_str && isspace(*date_str)) ++date_str;
        if ( !*date_str) break;

        if (isalpha(*date_str))
        {
            suspecting &= like_alpha;

            if (date_str[1]=='M' && (date_str[0]=='A' || date_str[0]=='P'))
            {
                suspecting &= like_pm;
                _its_clear |= got_pm;
            }
            else {
                suspecting &= ~like_pm;
                _its_clear |= got_amon;
            }

            _suspecting_one(suspecting);
        }
        else if (isdigit(*date_str))
        {
            suspecting &= ~like_alpha;

            // проверяем границы
            int value = atoi(date_str);
            do {++date_str;} while (*date_str && isdigit(*date_str));

            if (12 < value)
            {
                suspecting &= ~like_mon;
                if (_its_clear & got_am) suspecting &= ~like_hour;

                if (23 < value)
                {
                    suspecting &= ~like_hour;

                    if (31 < value)
                    {
                        suspecting &= ~(like_mon|like_mday);

                        if (59 < value)
                        {
                            suspecting &= like_year;
                            _its_clear |= got_year2000;
                        }
                    }
                }
            }

            if ( (_its_clear & got_year2000) && value < 60)
            {
                suspecting &= ~like_year;
            }

            if (_its_clear & got_amon)
            {
                suspecting &= ~like_mon;
            }

            _suspecting_one(suspecting);
        }
        else
        {
            switch (*date_str)
            {
                case '/' :
                case '.' :
                case '-' :
                    _suspecting_pair(like_date);
                    break;

                case ':' :
                    _suspecting_pair(like_time);
                    break;
            }
        }
    }
    while (*date_str);
}
//----------------------------------------
как пользоваться:
1) создали
GuessDateFormat guess_format;
2) скидали в него все даты, какие есть
for(...) guess_format.add_sample(date[n].c_str());
3) проверили, угадался ли формат
if (guess_format.state()==GuessDateFormat::state_ready)
4) переводим даты
time_t t1;
for(...) guess_format.convert(date[n].c_str(), t1);

чего в коде нет:
1) таблицы соответсвия месяц-номер месяца (на всех языках, со всеми сокращениями)
2) не может отличить минуты от секунд. Чтобы это обойти, надо внутри добавить код: пробежаться по вектору с подозрениями и если встретится элемент времени, то последовательно обозначить час, минута, секунда.
Это сообщение посчитали полезным следующие участники:

Отправлено: 20:35, 20-07-2010 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

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


Аватара для Drongo

Будем жить, Маэстро...


Сообщения: 6694
Благодарности: 1393

Профиль | Сайт | Отправить PM | Цитировать


Вложения
Тип файла: rar DateTime.rar
(15.7 Kb, 8 просмотров)

pva, Код конечно шикарный, осталось в нём разобраться. Можешь его внедрить в простой пример?

-------
Правильная постановка вопроса свидетельствует о некотором знакомстве с делом.
3нание бывает двух видов. Мы сами знаем предмет — или же знаем, где найти о нём сведения.
[Quick Killer 3.0 Final [OSZone.net]] | [Quick Killer 3.0 Final [SafeZone.cc]] | [Парсер логов Gmer] | [Парсер логов AVZ]

http://tools.oszone.net/Drongo/Userbar/SafeZone_cc.gif


Отправлено: 22:06, 20-07-2010 | #3

pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


вот, правда сделано на билдере 4 (у билдера 6 есть проблема с линковкой имён с подчёркиваниями)

Последний раз редактировалось pva, 25-02-2012 в 11:59.

Это сообщение посчитали полезным следующие участники:

Отправлено: 22:28, 21-07-2010 | #4



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - TDateTime - Операции с временем [вычитание, сложение]

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
Assm - Сложение двух чисел Rebel666 Программирование и базы данных 8 22-04-2012 17:30
Проблема со временем PLATON Непонятные проблемы с Железом 2 20-04-2008 15:35
Delphi - Вычитание дат на Delphi d_voffka Программирование и базы данных 2 05-06-2006 11:53
Сложение строк на PHP Vlad Drakula Вебмастеру 1 08-06-2003 21:30




 
Переход