如何在C#中模拟Delphi 2007 SecondsBetween函数?

如何在C#中模拟Delphi 2007 SecondsBetween函数?,c#,delphi,datetime,delphi-2007,C#,Delphi,Datetime,Delphi 2007,这是前一个问题的后续问题: 我正在将一个用Delphi编写的企业应用程序移植到C#。应用程序使用一种非常基本的加密形式来存储它生成的文本文件。此加密基于Delphi SecondsBetween命令,该命令返回两个日期之间的秒数 我遇到的问题是,在旧版本的Delphi(我正在移植的版本)中,SecondsBetween命令有一个bug,导致它返回的值关闭了一次,但只有大约50%的时间关闭 这只虫子是一只圆虫子。Delphi最初使用Trunc而不是Round。请参阅此处的更多详细信息- 下面是演示

这是前一个问题的后续问题:

我正在将一个用Delphi编写的企业应用程序移植到C#。应用程序使用一种非常基本的加密形式来存储它生成的文本文件。此加密基于Delphi SecondsBetween命令,该命令返回两个日期之间的秒数

我遇到的问题是,在旧版本的Delphi(我正在移植的版本)中,SecondsBetween命令有一个bug,导致它返回的值关闭了一次,但只有大约50%的时间关闭

这只虫子是一只圆虫子。Delphi最初使用Trunc而不是Round。请参阅此处的更多详细信息-

下面是演示问题的代码:

德尔菲:

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

130289133
C#:


我想做的是找出如何在C#中模拟这种错误行为,这样我就可以读/写Delphi应用程序编写的文本文件。

如何人为地将被减去的项(右侧)增加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;
}

业务风险听起来很高,不幸的是,Delphi提供了所有关于此bug内部行为的信息。用C#编写一个补偿方法并进行单元测试并不能保证在任何时候都能缓解这个问题

除非有一个知识渊博的灵魂与特定的细节相呼应,否则您是否有可能使用版本15.0.3729.28755(有缺陷修复)重新编译并推出您的原始Delphi应用程序

另一种可能性是为您的C#port推出“大爆炸”,以完全取代Delphi port,尽管这在培训和员工支持方面可能会更加紧张


祝您好运-这是一个棘手的问题。

这是对所需函数的翻译(第二个span),以复制Delphi 2007函数

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();
        }
    }
}
使用系统;
使用系统文本;
命名空间D2007SecondsBetween
{
班级计划
{
const双倍小时/天=24;
常数双分钟/小时=60;
const-double-SecsPerMin=60;
常数双msecpersec=1000;
常数双分钟/天=小时/天*分钟/小时;
const double SecsPerDay=分钟/天*秒/分钟;
第二个静态双跨距(第二个双跨距,第二个双跨距)
{
如果(ANow
我认为在您的情况下,我只需将出错的Delphi例程编译成一个DLL,然后使用p/invoke从C#调用它。我将包括一个在calc之前设置8087控制字的调用,以及一个在calc之后将其恢复为调用者值的调用。这将是我能想到的风险最低的方法。

这不是高风险,它是一个相对基本的应用程序,团队规模非常小。尽管如此,我假设如果应用程序由于时间戳不正确而开始向磁盘写入错误编码的数据,这将是一个主要的业务问题?如果不是的话,你可以直接推出C#应用程序来慢慢修复这个bug吗?我知道这可能需要运行一个通宵的过程来解密和重新加密所有用Delphi bug编码的文件。我已经检查了所有的风险,妈妈,现在我可以有一个解决方案:)除非你有关于bug行为的详细信息,否则你不能模拟它。我希望有人能给你这个信息。祝你好运。我相信你会抓住这个机会,在未来的版本中朝着一个健壮的加密方向发展。你为什么不在D2007中编写一个转换器,以更好的格式存储生成的文本文件呢。这将确保您的加密/解密操作正确,避免将来的灾难。哇。加密算法中存在浮点错误。:-)然而,可以想象,这种代码在极少数情况下会失败。我希望.net和D2007对浮点运算的处理有所不同。中间产物可以是一个80位,另一个64位。等等如果不研究实际的机器语言,就不可能确定,即使这样,它也取决于抖动的作用。依靠浮点加密是愚蠢的。这是我对StackOverflow的最好回答,这是你第二次真正帮助我。非常感谢。我现在必须疯狂地测试它。投票支持疯狂地致力于帮助人们。如果代码是在delphi dll中隔离的,为什么要设置8087控制字(我甚至不知道这是什么意思)?因为C#代码可能会使用与delphi预期值不同的8087CW。系统不会为您管理处理器上下文的这一特定部分,因此您需要这样做。
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();
        }
    }
}