На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
  
> Ошибка в вычислениях в модуле DateUtils , Ошибка вычисления времени между переменными типа TDateTime
    Всем доброго времени суток.
    Обнаружил интересную ошибку(может фича такая) при вычислении количества часов, минут, секунд между датами и временем...
    использовал функции из модуля DateUtils:
    HoursBetween, MinutesBetween, SecondsBetween.

    var
    D1,D2: TDateTime;
    begin
    D1 := StrToTime(Edit1.text);
    D2 := StrToTime(Edit2.text);
    Edit3.text := IntToStr(SecondsBetween(D1,D2));
    end;

    например, если D1 = 13:00:00, а D2 = 14:00:00, то все нормально(3600 секунд между ними)
    а если D1=17:00:00, а D2 = 18:00:00 , то между ними 3599 секунд.
    Соответственно функция HoursBetween выдает 0 часов.

    И как с этим работать дальше ???
    Кто сталкивался - пишите варианты решения...
      Пошарил по коду DateUtils и получается, что ошибка закрадывается при отнимании от одной даты другой...
      вот тут:

      function SpanOfNowAndThen(const ANow, AThen: TDateTime): TDateTime;
      begin
      if ANow < AThen then
      Result := AThen - ANow
      else
      Result := ANow - AThen;
      end;

      В другом месте ошибке взяться вроде неоткуда...
        Во-первых, глянь в описание - SecondsBetween возвращает целое число секунд в интервале, т.е. не округляет, а обрезает рез-т до целого (несмотря на остаток миллисекунд 0.999..). Во-вторых, время в TDateTime хранится в виде дробной части суток в формате double и соот-но, как при любой работе с вещественными числами, при представлении дробей могут возникать "микроскопические" погрешности, связанные с ограниченной разрядностью представления мантиссы числа. Вот у тебя и получается разница в 3599.999.., которую SecondsBetween обрезает до целого числа 3599. Если тебе нужно не обрезать, а округлять секунды, то юзай
        round(SecondSpan(D1,D2));
          Да про Round() я уже думал.
          Вообще непонятно как с модулем раньше работали и работают, если он точно ничего не определяет...
          Ведь как панацея на форумах пишется.
          Я уже и код под это дело набацал...
          Сейчас все переделывать придется :rtfm:
          На PHP и Perl я с таким не сталкивался..

          Добавлено
          Вердикт однозначный. Для расчетов с временем использовать модуль DateUtils в принципе нельзя.
          Точности нет. И это в датах-то...
          Выход нашел.
          Надо было количество часов получать между датами.
          Получаю округленное количество секунд round(SecondSpan(D1,D2))и делю на 3600.
          Лучшего пока-что не придумал.
          А функцию HoursBetween для этого не подходит.
            Цитата agesandr @
            Вообще непонятно как с модулем раньше работали и работают, если он точно ничего не определяет...

            Справку нужно внимательно читать :rtfm:
              Читал справку и примеры смотрел.
              Вот сколько часов должно быть между 17:00:00 и 18:00:00??
              Один час вроде бы... но никак не ноль.
              Глючные функции и модуль.
                Сам неоднократно сталкивался с такими "глюками". Увы, ничего лучше с существующим видом TDateTime придумать нельзя :(. Вот если бы оно было по принципу FILETIME (два DWORD), тогда всё было бы наишоколаднейше. А так - приходится извращаться.

                Добавлено
                Цитата agesandr @
                Глючные функции и модуль

                "Глючное" само представление. Вернее, это багофича, а еще вернее - фича, которая приводит к багам.
                  Время это в принципе вещь неточная и приблизительная, тем более когда речь идет об округлении к часам, минутам и т.п. И круглые цифры типа 17:00:00:000 и 18:00:00:000 - это чистые абстракции, которые можно получить только через EncodeTime, а любое реальное время всегда определяется с некоторой погрешностью и соотв-но работать с ним нужно по правилам вещественных чисел - через round-ы и т.п. А если тебя это не устраивает, то и незачем юзать вещественный тип TDateTime - работай с целочисленными TSystemTime и TTimeStamp
                    Цитата leo @
                    Время это в принципе вещь неточная и приблизительная, тем более когда речь идет об округлении к часам, минутам и т.п. И круглые цифры типа 17:00:00:000 и 18:00:00:000 - это чистые абстракции, которые можно получить только через EncodeTime, а любое реальное время всегда определяется с некоторой погрешностью и соотв-но работать с ним нужно по правилам вещественных чисел - через round-ы и т.п. А если тебя это не устраивает, то и незачем юзать вещественный тип TDateTime - работай с целочисленными TSystemTime и TTimeStamp

                    Вот за TSystemTime и TTimeStamp спасибо огромное )))
                    Совсем про них забыл ... Помнил только TDateTime...
                    Вот что значит много на PHP работать )))
                    Буду дальше колупать...
                      Резюме - дело не в модуле DateUtils, а в представлении TDateTime в виде вещественного числа double, в котором невозможно абсолютно точно представить казалось бы "круглые" цифры типа 17:00:00. Тех, кто это понимает и учитывает, вещественный формат вполне устраивает. И модуль DateUtils сделан с учетом этого: хочешь обрезать дроби - юзай функции ..Between, хочешь с дробями - юзай ..Span и дальше по усмотрению round, trunc или ва-аще sin\cos ;)
                        Цитата agesandr @
                        а если D1=17:00:00, а D2 = 18:00:00

                        Приведи точное время, хотя бы с точностью до микросекунды, а еще лучше все 15 знаков.
                          Цитата Anatoly Podgoretsky @
                          Цитата agesandr @
                          а если D1=17:00:00, а D2 = 18:00:00

                          Приведи точное время, хотя бы с точностью до микросекунды, а еще лучше все 15 знаков.

                          Да с этим все понятно.
                          Просто думал удобнее будет с TDateTime работать и модулем DateUtils...
                          А оказалось проще делать все с TTimeStamp все делать...
                          Давно просто не работал с Delphi и многое забыть успел )))
                            Цитата Anatoly Podgoretsky @
                            Приведи точное время, хотя бы с точностью до микросекунды, а еще лучше все 15 знаков

                            А зачем, если и так "с этим все понятно" ;)
                            18:00 как и все часы, кратные 3-м, представляются точно максимум 3-мя двоичными разрядами, т.к. 3*k/24 = k/8, где 8 = 23
                            А все часы, не кратные 3-м, будут иметь делитель = 3, который и в десятичной, и в двоичной системе будет давать бесконечную периодическую дробь, например, 17/24 = 0.7083(3) = 0.$B5(5)
                              Цитата agesandr @
                              Просто думал удобнее будет с TDateTime работать и модулем DateUtils...
                              А оказалось проще делать все с TTimeStamp все делать...
                              Давно просто не работал с Delphi и многое забыть успел )))

                              Конечно проще с TDateTime, но надо учитывать его относительную точность, ведь реальный тип это Double, а прочие типы использовать только при крайней нужде.
                              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                              0 пользователей:


                              Рейтинг@Mail.ru
                              [ Script execution time: 0,0447 ]   [ 16 queries used ]   [ Generated: 7.04.26, 22:18 GMT ]