-----------------------------------------------------------------------------
                      [BUG/PRB.] VFP 9.0 FIX - ROUND THE DATETIME DATA TO INTEGER SECONDS
                                 January 2024
                 -----------------------------------------------------------------------------
                                    CCB



1. BUG:

     There is a test program from Mr. Tomas Tamm:

     *PROC testcomparedatetime

     dt1=DATETIME(2017,1,1,0,0,0)
     dt2=DATETIME(2017,1,1,0,0,0)

     FOR li=1 TO 10000000

        dt1   = dt1+60
        dt2 = DATETIME(YEAR(dt1),MONTH(dt1),DAY(dt1),HOUR(dt1),MINUTE(dt1),SEC(dt1))

        IF dt2 != dt1
           ? "After "+TRANSFORM(li)+" iterations of adding 60 seconds to dt1"
           ? "dt1 = "+TRANSFORM(dt1)
           ? "dt2 = "+TRANSFORM(dt2)
           ? "dt1 and dt2 visibly seem to be equal"
           ? "But dt1 = dt2 evaluates to "+TRANSFORM(dt1=dt2)
           ? "dt2 - dt1 = "+TRANSFORM(dt2-dt1)
           EXIT
        ENDIF

     ENDFOR
     WAIT

     RETURN

     * END OF PROC TESTCOMPAREDATETIME.

     Usually, we think dt2 is always equal to dt1, but it will display:
     After 139810 iterations of adding 60 seconds to dt1
     dt1 = 04/08/17 02:10:00 AM
     dt2 = 04/08/17 02:10:00 AM
     dt1 and dt2 visibly seem to be equal
     But dt1 = dt2 evaluates to .F.
     dt2 - dt1 = 1


2. CAUSE:

     VFP uses the Value structure to save the value of the variables:

     // An expression's value.
     Typedef struct {
        char         ev_type;
        char         ev_padding;
        short         ev_width;
        unsigned      ev_length;
        long         ev_long;
        double         ev_real;
        CCY         ev_currency;
        MHANDLE      ev_handle;
        ULONG         ev_object;
     } Value;

     For the datetime data,
     ev_type = 'T'
     ev_real = Date + (seconds/86400.0)

     VFP uses the floating-point number to save the datetime data, for example,
     dt1=DATETIME(2017,1,2,3,4,5)
     dt1.ev_real = VAL(SYS(11,DATE(2017,1,2))) + ((3*60+4)*60+5)/86400.0 = 2457756.1278356481340

     For the test program testcomparedatetime,
     After 139810 iterations of adding 60 seconds,
     dt1.ev_real = 2457852.0902719907460
     dt2.ev_real = 2457852.0902777779850

     dt2.ev_real - dt1.ev_real = 5.7872384786605834960E-06
     5.7872384786605834960E-06 * 86400.0 = 0.5000174045562744140 > 0.5 (seconds)
     So dt2 != dt1.

     If we enable rounding the datetime data to integer seconds in Visual FoxPro Advanced,
     Visual FoxPro Advanced will round the datetime data to integer seconds, for example,
     DATETIME() Function,
     seconds number + datetime expression.
     datetime expression + seconds number,
     datetime expression - seconds number,
     datetime expression - datetime expression.

     For the statement in the test program testcomparedatetime:
     dt1   = dt1+60
     Visual FoxPro Advanced will calculate:
     dt1.ev_real = dt1.ev_real+60
     and then round dt1.ev_real to integer seconds:
     dt1.ev_real = floor(dt1.ev_real * 86400.0 + 0.5) / 86400.0

     After 139810 iterations of adding 60 seconds,
     dt1.ev_real = 2457852.0902777775190
     dt2.ev_real = 2457852.0902777779850

     dt2.ev_real - dt1.ev_real = 4.6566128730773925780E-10
     4.6566128730773925780E-10 * 86400.0 = 0.0000402331352233887 < 0.5 (seconds)
     So dt2 == dt1.


3. RESOLUTION:

     We can write some code to fix the BUG.

     Label58fd6b ::
             sub eax , 05449h                                                ;0x0058fd6b :        2d49540000
             je Label58fda5                                                  ;0x0058fd70 :        7433
             sub eax , 05h                                                   ;0x0058fd72 :        83e805
             jne Label58fe1d                                                 ;0x0058fd75 :        0f85a2000000
             fld qword ptr [ Data91fbc8 ]                                    ;0x0058fd7b :        dd05c8fb9100
             fld qword ptr [ esi + 16 ]                                      ;0x0058fd81 :        dd4610
             fucompp                                                         ;0x0058fd84 :        dae9
             fstsw ax                                                        ;0x0058fd86 :        dfe0
             test  byte ptr ah , 044h                                        ;0x0058fd88 :        f6c444
             jnp Label420eae                                                 ;0x0058fd8b :        0f8b1d11e9ff
             fld qword ptr [ ebx + 16 ]                                      ;0x0058fd91 :        dd4310
             fmul qword ptr [ Data922280 ]                                   ;0x0058fd94 :        dc0d80229200
             fadd qword ptr [ esi + 16 ]                                     ;0x0058fd9a :        dc4610


     ;
     ;                 ------------------------------------------------------------------
     ;                      VFP 9.0 FIX - ROUND THE DATETIME DATA TO INTEGER SECONDS
     ;                                December 2017
     ;                 ------------------------------------------------------------------
     ;                                     CCB
     ;
     ; Round the datetime data to integer seconds.
     ;
     ; 2017/12/20, by ccb
     ;

             cmp dword ptr vfpa_sys9002_data,00h
             je Label58fd9d

             sub esp , 08h
             fstp qword ptr [ esp ]
             call Fun87c7af


     Label58fd9d ::
             fstp qword ptr [ esi + 16 ]                                     ;0x0058fd9d :        dd5e10
             jmp Label420eae                                                 ;0x0058fda0 :        e90911e9ff

     Label58fda5 ::
             fld qword ptr [ Data91fbc8 ]                                    ;0x0058fda5 :        dd05c8fb9100
             fld qword ptr [ esi + 16 ]                                      ;0x0058fdab :        dd4610
             fucompp                                                         ;0x0058fdae :        dae9
             fstsw ax                                                        ;0x0058fdb0 :        dfe0
             test  byte ptr ah , 044h                                        ;0x0058fdb2 :        f6c444
             jnp Label420eae                                                 ;0x0058fdb5 :        0f8bf310e9ff
             fild dword ptr [ ebx + 12 ]                                     ;0x0058fdbb :        db430c
             fmul qword ptr [ Data922280 ]                                   ;0x0058fdbe :        dc0d80229200
             fadd qword ptr [ esi + 16 ]                                     ;0x0058fdc4 :        dc4610


     ;
     ;                 ------------------------------------------------------------------
     ;                      VFP 9.0 FIX - ROUND THE DATETIME DATA TO INTEGER SECONDS
     ;                                December 2017
     ;                 ------------------------------------------------------------------
     ;                                     CCB
     ;
     ; Round the datetime data to integer seconds.
     ;
     ; 2017/12/20, by ccb
     ;

             cmp dword ptr vfpa_sys9002_data,00h
             je Label58fdc7

             sub esp , 08h
             fstp qword ptr [ esp ]
             call Fun87c7af


     Label58fdc7 ::
             fstp qword ptr [ esi + 16 ]                                     ;0x0058fdc7 :        dd5e10
             jmp Label420eae                                                 ;0x0058fdca :        e9df10e9ff


4. APPLIES TO:

     VFP 6.0.8167.0
     VFP 6.0.8961.0 (SP5)

     VFP 7.0.0.9262
     VFP 7.0.0.9465 (SP1)

     VFP 8.0.0.2521
     VFP 8.0.0.3117 (SP1)

     VFP 9.0.0.2412
     VFP 9.0.0.3504 (SP1)
     VFP 9.0.0.4611 (SP2)
     VFP 9.0.0.5015 (SP2)
     VFP 9.0.0.5411 (SP2)
     VFP 9.0.0.5721 (SP2)
     VFP 9.0.0.5815 (SP2)
     VFP 9.0.0.6303 (SP2)
     VFP 9.0.0.6602 (SP2)
     VFP 9.0.0.7423 (SP2)

     The bug has been fixed in VFP Advanced.


5. REFERENCE WEBSITES:

     1, baiyujia.com:
     http://www.baiyujia.com
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix37.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix23.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix24.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix97.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix98.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix123.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix124.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix255.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix256.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix257.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix258.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix259.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix260.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix303.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix304.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix305.asp
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix306.asp

     2, foxite.com:
     https://www.foxite.com/archives/problem-0000100367.htm
     https://www.foxite.com/archives/is-this-a-bug-0000106513.htm

     3, sunyear.com.tw:
     http://vfp.sunyear.com.tw/viewtopic.php?t=4314


6. OTHER:

     For reference only, there is no guarantees.

     Any questions or suggestions, please send me an email at ccb2000@163.com.