Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
Precision in DateTime Arithmetic
Message
De
30/11/2012 09:13:59
 
 
À
29/11/2012 18:45:46
Information générale
Forum:
Visual FoxPro
Catégorie:
Codage, syntaxe et commandes
Versions des environnements
Visual FoxPro:
VFP 9 SP2
OS:
Windows 7
Divers
Thread ID:
01558431
Message ID:
01558467
Vues:
64
>Suppose you have 2 different datetime values t1 and t2.
>
>If you subtract them e.g. t2 - t1, you get the time difference in seconds. Actually it seems to be the FLOOR() of the difference i.e.
>
>- anything less than 1 second returns 0
>- anything less than 2 seconds, but greater to or equal to 1 second, returns 1
>- etc.
>
>My understanding is that as an 8-byte type, DateTime values are stored with considerable precision, of the order of about 10 milliseconds (?) Is there any way to calculate differences with more precision?
>
>I understand SECONDS() can be used to get more precision, but what I'm dealing with are DateTime values stored in tables.

Not sure where I found this, but it uses the SYS(2015) function to retreive the time with milliseconds.
    PROCEDURE DateTimeMilli()
        LPARAMETERS lAsNumber AS Boolean

        *LPARAMETERS nString,nMilliSecs,nCentury,nRollover
        LOCAL nString, nMilliSecs, nCentury, nRollover
        nString = SYS(2015)
        * If the Century and Rollover aren't supplied, fill them with the VFP defaults.
        IF VARTYPE(nCentury) <> 'N'
            nCentury = SET('CENTURY', 1)
        ENDIF
        IF VARTYPE(nRollover) <> 'N'
            nRollover = SET('CENTURY', 2)
        ENDIF

        *The Sys2015 command returns a string of 10 characters.
        *The first one is always an underscore '_'
        *The following 9 characters are always from the range 0-9 or A-Z.
        *The value per char they represent is 0=0, 1=1, ..., 9-9, A=10, B=11, ... , Z=35
        *From the first 9 characters, the first 3 characters represent the days,
        *the rest represent the (milli)seconds.
        *
        *The value of the days can be found this way:
        *When you have the string of 3 characters, you must convert them from base36 to base10,
        *where the MSB is in the first char.
        *Unfortenately the century's are not in SYS(2015) so you can only extract the years 00-99.
        *Now you have a number of the Days, where:
        *Jan 1st '00 = 1
        *Jan 2st '00 = 2
        *Jan 1st '01 = 368
        *etc
        *
        *You see the years have 367 days with no day 0.
        *This way you can find the year and days since jan 1st.
        *Because this routine returns a datetime, the century is filled with the century together with rollover.
        *If the default VPF Century and Rollover settings are not correct for you, you can supply them to this routine
        *by giving them as the 3rd and 4th parameter. (This is optional)
        *
        *Now the time:
        *When you have the string of 6 characters, you must convert them from base36 to base10,
        *where the MSB is in the first char.
        *Now you have the time in millisecs since midnight.
        *Because the datetime cannot return milliseconds, you can get the millisecs of the datetime by using the following syntax:
        *nDateTime=CONVERT2015(cSys2015,@nMillisecs)
        *nDateTime will have the Datetime, nMillisecs will have the milliSecs of this datetime
        LOCAL nVal1, nVal2, nVal3, nVal4, nVal5, nVal6, nVal7, nVal8, nVal9, nDay
        * Convert each char from '0-9,A-Z' to 0-35
        nVal1 = ASC(SUBSTR(nString, 2)) - IIF(ASC(SUBSTR(nString, 2)) < 65, 48, 55)
        nVal2 = ASC(SUBSTR(nString, 3)) - IIF(ASC(SUBSTR(nString, 3)) < 65, 48, 55)
        nVal3 = ASC(SUBSTR(nString, 4)) - IIF(ASC(SUBSTR(nString, 4)) < 65, 48, 55)
        nVal4 = ASC(SUBSTR(nString, 5)) - IIF(ASC(SUBSTR(nString, 5)) < 65, 48, 55)
        nVal5 = ASC(SUBSTR(nString, 6)) - IIF(ASC(SUBSTR(nString, 6)) < 65, 48, 55)
        nVal6 = ASC(SUBSTR(nString, 7)) - IIF(ASC(SUBSTR(nString, 7)) < 65, 48, 55)
        nVal7 = ASC(SUBSTR(nString, 8)) - IIF(ASC(SUBSTR(nString, 8)) < 65, 48, 55)
        nVal8 = ASC(SUBSTR(nString, 9)) - IIF(ASC(SUBSTR(nString, 9)) < 65, 48, 55)
        nVal9 = ASC(SUBSTR(nString, 10)) - IIF(ASC(SUBSTR(nString, 10)) < 65, 48, 55)

        *Convert the day from BASE36 to BASE10
        nDay = nVal1 * 1296 + nVal2 * 36 + nVal3
        nDay2 = nDay

        *In the SYS(2015) world, every year has 367 days
        nYear = INT(nDay / 367)

        *Add the right century to this year, because SYS(2015) only has years 0-99
        nYear = nCentury * 100 + IIF(nYear < nRollover OR nYear = 0, 100, 0) + nYear

        *Strip the year off, so you only have the days since Jan 1st
        nDay = MOD(nDay, 367)

        *Convert the millisecs from BASE36 to BASE10
        nSeconds = (nVal4 * 60466176 + nVal5 * 1679616 + nVal6 * 46656 + nVal7 * 1296 + nVal8 * 36 + nVal9)
        nSeconds2 = nSeconds

        *Get the Millisecs from the seconds.
        nMilliSecs = MOD(nSeconds, 1000)

        *Strip the millisecs from the seconds
        nSeconds = INT(nSeconds / 1000)

        * NDay must be substracted by 1 because nDay=1 is Jan 1st, not day 0
        IF lAsNumber
            RETURN (nDay2 * (24 * 60 * 60)) + (nSeconds2 / 1000.0)
        ELSE
            RETURN TRANSFORM(DTOT(DATE(nYear, 1, 1) + nDay - 1) + nSeconds) + '.' + PADL(nMilliSecs, 3, '0')
        ENDIF
    ENDPROC
Greg Reichert
Précédent
Suivant
Répondre
Fil
Voir

Click here to load this message in the networking platform