Как эмулировать функцию SephdsBetween в Delphi 2007 в C #? - PullRequest
2 голосов
/ 20 декабря 2011

Это продолжение предыдущего вопроса: Несоответствие между вычислениями даты и времени в C # и Delphi

Я портирую корпоративное приложение, написанное на Delphi, на C #. Приложение использует очень элементарную форму шифрования для хранения текстовых файлов, которые оно генерирует. Это шифрование основано на команде Delphi SecondsBetween, которая возвращает количество секунд между двумя датами.

Проблема для меня в том, что в более старой версии Delphi (той, с которой я портирую) есть ошибка с командой SecondsBetween, которая заставляет ее возвращать значения, которые отключены на один - , но только около 50% времени

Ошибка - ошибка округления. Delphi изначально использовал Trunc вместо Round. Подробнее здесь - http://qc.embarcadero.com/wc/qcmain.aspx?d=59310

Вот код, демонстрирующий проблему:

Delphi:

SecondsBetween(StrToDateTime('16/02/2009 11:25:34 p.m.'), StrToDateTime('1/01/2005 12:00:00 a.m.'));

130289133

C #:

TimeSpan span = DateTime.Parse("16/02/2009 11:25:34 p.m.").Subtract(DateTime.Parse("1/01/2005 12:00:00 a.m."));

130289134

Что я хотел бы сделать, так это выяснить, как я могу эмулировать это ошибочное поведение в C #, чтобы я мог читать / записывать текстовые файлы, написанные приложением Delphi.

Ответы [ 4 ]

5 голосов
/ 20 декабря 2011

Это перевод необходимых функций (SpanOfNowAndThen, SecondSpan) для репликации функции Delphi 2007 SecondsBetween.

using System;
using System.Text;

namespace D2007SecondsBetween
{
    class Program
    {
      const double HoursPerDay   = 24;
      const double MinsPerHour   = 60;
      const double SecsPerMin    = 60;
      const double MSecsPerSec   = 1000;
      const double MinsPerDay    = HoursPerDay * MinsPerHour;
      const double SecsPerDay    = MinsPerDay * SecsPerMin;

        static double SpanOfNowAndThen(Double ANow, Double AThen)
        {
          if (ANow < AThen)
            return AThen - ANow;
          else
            return ANow - AThen;
        }


        static double SecondSpan(Double ANow, Double AThen)
        {
         return  SecsPerDay * SpanOfNowAndThen(ANow, AThen);
        }

        static int SecondsBetween(DateTime ANow, DateTime AThen)
        {
          return (int)Math.Truncate(SecondSpan(ANow.ToOADate(), AThen.ToOADate()));
        }

        static void Main(string[] args)
        {
            TimeSpan span ;            
            span = DateTime.Parse("16/02/2009 23:25:34").Subtract(DateTime.Parse("1/01/2005 00:00:00"));
            Console.WriteLine(span.TotalSeconds);//returns 130289134
            Console.WriteLine(SecondsBetween(DateTime.Parse("16/02/2009 23:25:34"), DateTime.Parse("1/01/2005 00:00:00")));//returns 130289133

            span = DateTime.Parse("16/11/2011 23:25:43").Subtract(DateTime.Parse("1/01/2005 00:00:00"));
            Console.WriteLine(span.TotalSeconds);//returns 216948343
            Console.WriteLine(SecondsBetween(DateTime.Parse("16/11/2011 23:25:43"), DateTime.Parse("1/01/2005 00:00:00")));//returns 216948343

            Console.ReadKey();
        }
    }
}
3 голосов
/ 20 декабря 2011

Я думаю, что в вашей ситуации я бы просто скомпилировал неисправную подпрограмму Delphi в DLL и использовал p / invoke для вызова из C #.Я бы включил вызов, чтобы установить контрольное слово 8087 перед calc, и один, чтобы потом восстановить его до значения вызывающего абонента.Это был бы подход с наименьшим риском, который я могу придумать.

0 голосов
/ 20 декабря 2011

Деловой риск звучит очень высоко, и, к сожалению, от Delphi есть полная информация о том, как эта ошибка ведет себя внутренне.Написание и модульное тестирование компенсаторного метода в C # не может гарантировать постоянное смягчение проблемы.

Если осведомленная душа не вмешивается в конкретные детали, возможно, вы сможете перекомпилировать и развернуть свое оригинальное приложение Delphi, используя версию 15.0.3729.28755 (с исправлением ошибки)?существует возможность «большого взрыва» для вашего порта C # полностью заменить Delphi, хотя это может быть более напряженным с точки зрения обучения и поддержки персонала.

Удачи с этим - это сложная проблема.

0 голосов
/ 20 декабря 2011

Как насчет искусственного прибавления 0,5 секунды к вычитаемому члену (справа), а затем усечение TimeSpan.TotalSeconds до значения int?Возможно, это сработает:

int BuggySecondsBetween(DateTime left, DateTime right)
{
    TimeSpan actual = left - right;
    TimeSpan buggyResult = actual - TimeSpan.FromSeconds(0.5d);
    return (int)buggyResult.TotalSeconds;
}
...