Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > [BCB2009] TDateTime - Результат сравнения


Автор: MuForum 13.9.2009, 17:00
Доброе время суток.
Работаю на "Borland C++ Builder 2009".

# Задача: Сравнить два объекта TDateTime и вернуть результат разницы дней, часов, минут и секунд в строке.
- Возвращаемый результат: XX days HH:mm:ss; (01 days 12:03:15)
- Я решил эту задачу, однако реализация мне не очень нравится.

Код

#include <DateUtils.hpp> // DaysBetween;
...
AnsiString GetDifDateTime(TDateTime dtSource, TDateTime dtDest)
{
    AnsiString sResult = "";
    // ----
    int iDays = 0;
    __int64 iRes = 0, iDif = 0;
    // ----
    iDays = DaysBetween(dtSource, dtDest);
    if(iDays < 10) sResult += "0";
    sResult += (String)iDays + " days ";
    iDif = iDays * 24;
    // ----
    iRes = HoursBetween(dtSource, dtDest);
    if(iRes > 24) iRes = iRes - iDif;
    if(iRes < 10) sResult += "0";
    sResult += (String)iRes + ":";
    iDif *= 60;
    if(iRes > 0) iDif += (iRes * 60);
    // ----
    iRes = MinutesBetween(dtSource, dtDest);
    if(iRes > 24) iRes = iRes - iDif;
    if(iRes < 10) sResult += "0";
    sResult += (String)iRes + ":";
    iDif *= 60;
    if(iRes > 0) iDif += (iRes * 60);
    // ----
    iRes = SecondsBetween(dtSource, dtDest);
    if(iRes > 24) iRes = iRes - iDif;
    if(iRes < 10) sResult += "0";
    sResult += (String)iRes;
    // ----
    return sResult;
}



P.S. -> Если кто-то может предложить лучший способ вычисления, буду рад.

Автор: Efs 13.9.2009, 18:24
Хм.. а почему бы не оперировать с типами TDateTime, встроенными в BCPP, а не со строками ? 

Автор: smoke_man 13.9.2009, 18:41
Например, так:
Код

    unsigned short hour,min,sec,msec;
    unsigned short d,m,y;    
    TDateTime t1 = Now();
    Sleep(2000);
    TDateTime t2 = Now();
    TDateTime t3 = t2-t1;
    t3.DecodeTime(&hour,&min,&sec,&msec);
    t3.DecodeDate(&y,&m,&d);

Автор: MuForum 13.9.2009, 22:44
Цитата(smoke_man @ 13.9.2009,  18:41)
Например, так:
Код

    unsigned short hour,min,sec,msec;
    unsigned short d,m,y;    
    TDateTime t1 = Now();
    Sleep(2000);
    TDateTime t2 = Now();
    TDateTime t3 = t2-t1;
    t3.DecodeTime(&hour,&min,&sec,&msec);
    t3.DecodeDate(&y,&m,&d);

Данный способ хорош, НО, он не правильно определяет дату. (год, месяц, день)

Автор: Efs 14.9.2009, 06:28
Есть одна хорошая штука в билдере - DateTimePicker. С него можно брать заданную дату и время:
Код

TDateTime td1;
td1=(TDateTime)(DateTimePicker1->DateTime.DateString());

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

Автор: MuForum 14.9.2009, 07:54
Цитата(Efs @ 14.9.2009,  06:28)
Есть одна хорошая штука в билдере - DateTimePicker. С него можно брать заданную дату и время:
Код

TDateTime td1;
td1=(TDateTime)(DateTimePicker1->DateTime.DateString());

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

Вы не поняли задачу.
С получением даты и времени проблем не возникает.
Проблема возникает с вычитанием двух TDateTime -> Результат времени корректен, а вот результат даты нет.
Код

    unsigned short hour,min,sec,msec;
    unsigned short d,m,y;    
    TDateTime t1 = Now();
    Sleep(2000);
    TDateTime t2 = Now();
    TDateTime t3 = t2-t1;
    t3.DecodeTime(&hour,&min,&sec,&msec);
    t3.DecodeDate(&y,&m,&d);
....
Результаты:
hour = 0;
min = 0;
sec = 0;
msec = 0;
y = 1899;
m = 12;
d = 30;

- Я тоже так сделал в первый раз, но из-за не корректного результата даты отказался.
- Может я что-то не так делаю, подскажите.


P.S. -> Ещё раз уточняю задание. Есть два объекта TDateTime, мне необходимо получить их разность.

Добавлено @ 08:03
Кстати, пробовал и в ручную получить разницу даты и записать в класс TDateTime, однако выдаёт ошибку о выходе за пределы допустимых интервалов значений.
Код

    unsigned short hour, min, sec, msec;
    unsigned short d, m, y, d2, m2, y2;
    TDateTime t1 = Now();
    Sleep(2000);
    TDateTime t2 = Now();
    TDateTime t3 = t2 - t1;
    // ----
    t1.DecodeDate(&y, &m, &d);
    t2.DecodeDate(&y2, &m2, &d2);
    t3 = EncodeDate(y2 - y, m2 - m, d2 - d); // Project TEST.exe raised exception class EConvertError with message 'Invalid argument to date encode'.
    // ----
    t3.DecodeTime(&hour, &min, &sec, &msec);
    t3.DecodeDate(&y, &m, &d);
....
//#include <SysUtils.hpp>
extern PACKAGE System::TDateTime __fastcall EncodeDate(System::Word Year, System::Word Month, System::Word Day);

- Странность в том, что у функции EncodeDate() типы передаваемых данных WORD/unsigned short: [0..65535];
- разница всех переменных даты даёт результат 0. То есть, вроде всё должно быть нормально, однако на деле вылетает ошибка.


P.S. -> Может снова что-то криво делаю, либо чего-то недопонимаю =(

Автор: mrbrooks 14.9.2009, 08:42
MuForum, к сожалению разность дат в VCL сделана мягко говоря, через одно место. Как было верно замечено разность TTime идет корректно, в отличие от TDate. Поэтому можно немного и подмухлевать.

Код

#include <DateUtils.hpp> // DaysBetween;
String GetDifDateTime(TDateTime dt1, TDateTime dt2)
{
    return  String().sprintf(L"%d days ", DaysBetween(dt1,dt2)) + (dt1-dt2).TimeString();
}

Автор: Anikmar 14.9.2009, 08:50
Help Билдера:
Цитата

The System::TDateTime class inherits a val data member declared as a double that holds the date-time value. The integral part of a System::TDateTime value is the number of days that have passed since 12/30/1899. The fractional part of a System::TDateTime value is the time of day.


Если вы вычитаете даты, то в декодированном виде именно такой результат у вас и должен получится.
Со временем где-то ошибка: секунд должно быть 2.


Автор: mrbrooks 14.9.2009, 08:52
Цитата(Anikmar @  14.9.2009,  08:50 Найти цитируемый пост)
Если вы вычитаете даты, то в декодированном виде именно такой результат у вас и должен получится.

И это есть нормальная реализация?

Цитата(Anikmar @  14.9.2009,  08:50 Найти цитируемый пост)
Со временем где-то ошибка: секунд должно быть 2.

Это про что?

Автор: Anikmar 14.9.2009, 09:08
Цитата(mrbrooks @  14.9.2009,  08:52 Найти цитируемый пост)
Это про что? 


Цитата(MuForum @  14.9.2009,  07:54 Найти цитируемый пост)
Результаты:
hour = 0;
min = 0;
sec = 0;
msec = 0;
y = 1899;
m = 12;
d = 30;


Это про то, что sec должно быть 2


Цитата(mrbrooks @  14.9.2009,  08:52 Найти цитируемый пост)
И это есть нормальная реализация?

Я не говорил, что это нормальная реализация. Просто она такая. И результат именно тот, который описан в документации.
В результате вычитания 2-х дат получается новая дата, в которой целая часть равна 0.
Целая часть поля val подразумевает количество дней, прошедших с 30 декабря 1899 года 

Как вариант из декодированных лет вычесть 1899, из дней 30 и из месяцев 12, но возможны отрицательные значения - их надо обработать как-то.

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

Для простоты я бы взял такой способ:

Код

    unsigned short hour,min,sec,msec;
    unsigned short d,m,y;    
    TDateTime t1 = Now();
    Sleep(2000);
    TDateTime t2 = Now();
    TDateTime t3 = t2-t1;
    t3.DecodeTime(&hour,&min,&sec,&msec);
    t3.DecodeDate(&y,&m,&d);
  y-=1899;
  m-=12;
  d-=30;
if (d < 0) {d = 30 - d; m--;}
if (m < 0) {m = 12 - m; y--; }


Если я ничего не напутал с минусами/плюсами (что-то не тем сейчас голова занята).

Автор: mrbrooks 14.9.2009, 09:17
Цитата(Anikmar @  14.9.2009,  09:08 Найти цитируемый пост)
Я не говорил, что это нормальная реализация. Просто она такая. И результат именно тот, который описан в документации.

Я же не с претензией  smile  Я же - обсудить рукоблудие парней их Эмбаркадеро.


Цитата(Anikmar @  14.9.2009,  09:08 Найти цитируемый пост)
Для простоты я бы взял такой способ:

можно. но я бы остановился на своем исходя из условии задачи.  smile 

Автор: Anikmar 14.9.2009, 09:32
Цитата(mrbrooks @  14.9.2009,  09:17 Найти цитируемый пост)
можно. но я бы остановился на своем исходя из условии задачи. 

Само собой. 
Я просто думал, что там еще года и месяцы нужны. Если только дни и время то можно и таким способом.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)