Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
Precision in DateTime Arithmetic
Message
De
30/11/2012 19:33:54
Al Doman (En ligne)
M3 Enterprises Inc.
North Vancouver, Colombie Britannique, Canada
 
 
À
30/11/2012 09:13:59
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:
01558516
Vues:
41
>>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
>
An interesting way to skin the cat - thanks.
Regards. Al

"Violence is the last refuge of the incompetent." -- Isaac Asimov
"Never let your sense of morals prevent you from doing what is right." -- Isaac Asimov

Neither a despot, nor a doormat, be

Every app wants to be a database app when it grows up
Précédent
Répondre
Fil
Voir

Click here to load this message in the networking platform