Aller au contenu

Photo

TimeStamp


  • Veuillez vous connecter pour répondre
20 réponses à ce sujet

#1
Epitaffio

Epitaffio
  • Members
  • 35 messages
Any of you have a function to calculate the right timestamp? I've made this function:

void TimeStamp(){
    int iSecond = GetTimeSecond();
    int iMinute = GetTimeMinute()*60;
    int iHour = (GetTimeHour()*60)*60;
    int iDay = ((GetCalendarDay()*24)*60)*60;
    int iMonth = (((GetCalendarMonth()*28)*24)*60)*60;
    int iYear = ((((GetCalendarYear()*336)*28)*24)*60)*60;

   return iSecond+iMinute+iHour+iDay+iMonth+iYear;
}


first of all, it is right that the days in a month are 28?
Secondly, this function give me bad result due to INT limitation of nwn. Take 10 as the actual year and launch the function, the right result should be 8.128.512.000, nwn have an int limitation of 2.147.483.647 (taken from the lexicon)


Any hint or correction?

#2
Failed.Bard

Failed.Bard
  • Members
  • 774 messages
I did my timestamp as a string variable, though I only did year/month/day/hour. That avoids int limitations entirely.

As for your script, I don't expect it's needed to go *336 * 28. It should probably be *336 or *28*12.

#3
Epitaffio

Epitaffio
  • Members
  • 35 messages
I've thinked too to set the variables as string, but then i can't compare two timestamps with an if/else statement :(

Thanks anyway with the multiplication error, misspelling when debugging the function.. (like the void declaration)

#4
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
http://social.biowar...4495419#4495419

#5
Failed.Bard

Failed.Bard
  • Members
  • 774 messages
I hadn't realized it didn't overwrite strings. A quick look at my timestamp database put it at 2.1 megs for storing a 13 digit string. Is it just strings it does this with, or will it do it with floats as well?

#6
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages

Failed.Bard wrote...

I hadn't realized it didn't overwrite strings. A quick look at my timestamp database put it at 2.1 megs for storing a 13 digit string. Is it just strings it does this with, or will it do it with floats as well?



It will do it with any Non-fixed length data type.  

There are only two of them that can be stored in the DB.  Strings and Objects.

All of the other ones just over write the 128 byte buffer in the original record. 

If the data type is larger or even has a chance of being larger then 182 bytes, it stores a pointer to the data in the 128 byte buffer.    When the data is overwritten with this system, it appends the new data to the end of the data file and writes a new pointer to it in the 128 byte data field.    The old data is just left where ever it was at and ingnored.

#7
Epitaffio

Epitaffio
  • Members
  • 35 messages

Lightfoot8 wrote...

http://social.biowar...4495419#4495419


whoa, it's a long reading :o

But the thread is regarding the writing of the time in the db (i don't use the bio db) and i can't reproduce that for a time stamp function (newbie with the modulo operator here!)

I think i will use the time stamp as a string variable and i will create 3 function, encode (transform actual year, month etc in a string with some special character divider) , decode (that accept what type of return) and a compare one

Modifié par Epitaffio, 14 juillet 2011 - 04:10 .


#8
CID-78

CID-78
  • Members
  • 1 124 messages
a int is fastest and easiest unless you want to go down into microseconds you can either shift the numbers in place or multiply them. but if you multiply them start with the largest, that way you will save multiplication operations and you only need one variable.

multiplication uses a maximum range while shift is slighly faster, not any speed you will notice.

#9
CID-78

CID-78
  • Members
  • 1 124 messages
aslong as each shift make the number larger then the max value the time part can take a simple logic test against it will work.

ie Min*60 is perfect but Min<<6 (same Min*64) will give the same result when doing compare results. you only waste some number ranges.

#10
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
The Int with multiply is best. IT will allow you to add and subtract your time stamps from one another.

I also note that you are multiplying your minutes by 60 to get the number of hours. Nwn hours do not have 60 minutes in them. The number of minutes in a nwn hour is set in the module properties. Standard is 2. minutes and below are real time. hours and above are game time.

#11
Epitaffio

Epitaffio
  • Members
  • 35 messages
Ok so, after some quick testing, what do you think about to use the float instead of the int?

#12
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
My first thought is that it is pointless. If NWN used double precision floating point values it would be mor viable. but since NWScript only ise single precision floating point values there is too much of a chance for inaccuracy. But to really give an opinion on it I would have to know how you where planning on encoding the date/time into the flaot, to be able to see if the 6.5 digits of precision is able to handle it or not.

#13
Epitaffio

Epitaffio
  • Members
  • 35 messages
This is my latest version of the function, with the float variables (no code tag = hate)

    float iMinPerHour = HoursToSeconds(1)/60;  //20
    float iMinPerDay = 24 * iMinPerHour;    //480
    float iMinPerMonth = 28 * iMinPerDay;   //13440
    float iMinPerYear = 12* iMinPerMonth;   //161280

    float iMinute  = IntToFloat(GetTimeMinute());        //0
    float iHour    = (GetTimeHour()+1) * iMinPerHour;      //(23+1)*20     480
    float iDay     = GetCalendarDay() * iMinPerDay;      //28*480        13440
    float iMonth   = GetCalendarMonth() * iMinPerMonth;  //12*13440      161280
    float iYear    = GetCalendarYear() * iMinPerYear;    //1305*161280   210470400

    float iTimestamp = iMinute + iHour + iDay + iMonth + iYear; //210645600


Next of each row, there is an example of the max value (for the year i think we will have only 3 digit, but for testing i've just used the 4 one). I hope it's this what you asked me (i'm not english mother language, so sometimes i misunderstand :whistle: )

#14
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages

Epitaffio wrote...

This is my latest version of the function, with the float variables (no code tag = hate)

    float iMinPerHour = HoursToSeconds(1)/60;  //20
    float iMinPerDay = 24 * iMinPerHour;    //480
    float iMinPerMonth = 28 * iMinPerDay;   //13440
    float iMinPerYear = 12* iMinPerMonth;   //161280

   
Next of each row, there is an example of the max value (for the year i think we will have only 3 digit, but for testing i've just used the 4 one). I hope it's this what you asked me (i'm not english mother language, so sometimes i misunderstand :whistle: )


changed this section just a tad.  the -1 is to make te numbers 0 based. this makes it easier to exstract your original times back out.

 
    float iMinute  = IntToFloat(GetTimeMinute() -1 );        //0
    float iHour    = GetTimeHour()  * iMinPerHour;      //(24)*20     480
    float iDay     = (GetCalendarDay()-1 )* iMinPerDay;      //28*480        13440
    float iMonth   = (GetCalendarMonth()-1 ) * iMinPerMonth;  //12*13440      161280
    float iYear    = GetCalendarYear() * iMinPerYear;    //1305*161280   210470400
 



Yes that is what I needed.   So it looks like you are running a server with 20min/hour.  
To answer your question: no this will not work.   Here is the reasion why. 

the single precison float(32 bit) format  that nwn uses has only 6 1/2 digits of precision. this means that you can only rely on the value of the 6 most significent digits in the number.  lets look at this in relation to your number. 

If we have the date/ time

year  6
month 1
day 1
time 0:00
 your time stamp would be
   6 years *161280min/year  
+ (1-1)months  * 480min/month
+ (1-1)day *  13440min/day
+  0hour * 20min/hour
+ 0min
=  967,680min

So for 6 years we have a time stamp of 967,680 minutes.   This is no problem and within the limitations of the nwn float.   
  
lets see what year 7 looks like 
  7 years *161280min/year = 1,128,960
now we have a problem, our number is 7 digits long.   the last digit in the number only has a 50% chance of being accurate.   This means that if you added a single minute to your time stamp.  It might get add it might not.  Or it could even add 2 minutes instead of the one your where trying to add.


once you go out to year 70 you would then have  8 digits in the number and adding minutes in blocks of less the 10 would most likely have no effect on your stamp at all.   minutes in quanites of less then 100 would have inacurate results but would at least have a chance to effect the stamp.  


So the short answer here is No.   the float is a bad solution for this method,. 

the int on the other hand will give you  a number that can go all the way up to 2,147,483,648   with being accurate.  that is 9.2 digits of accuracy.  

with the method above you coud accuratly store 13,315 years into the int and  less then 7 years into the float.  

#15
Epitaffio

Epitaffio
  • Members
  • 35 messages
Hum.. i see your point

So, finally.. i can't use float for the accuracy... if i use int with seconds, i will reach the int limit.

The only solution i can see is to use int without seconds, it's right?


Just a last thing, you have corrected my script with the -1 to use a 0 based values, but in case of the first XXX, where XXX is one of the -1 value, i will have a 0 result. Why this will help me to extract the initial result? It's modulo related?

#16
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages
Or, if you're running NWNX, you can use MySQL and leave the ints in string form in nwscript, doing the calcs in MySQL - it's 64 bit, rather than 32. Frankly though, you're WAY overthinking this.

Funky

Modifié par FunkySwerve, 17 juillet 2011 - 10:29 .


#17
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
traditionally when you are talking about a time stamp, you are talking about an amount of time from a given date.  For example here are few of the systems currently in use.   

 UNIX Timestamp:  seconds since Jan 1 1970    ex.   Jan 1 1970   1:00am =  3600  or  60*60 (Min *Sec)
 Mac Timestamp:  seconds since Jan 1 1904     es    Jan 1 1904   2.00am  = 7200 or  120*60 ( (min*Sec)
both of  thies are stright forward  where the time stamp is an unsinged intenger of the number of seconds from the given date. .



here is the Mircrosoft time stamp.
Microsoft Timestamp:  days since Dec 31 1899

note:  mircrosoft does not use the number of seconde from the given date.  Instead it it the number of days.   inorder to get an acurate time they use a double pricesion float, where the mumber of days is represented by whole numbers and the time during the day is representsd the fraction of the number.   so:

January 1, 1900  12:00Pm  would have a time stamp of    0.5  or   half after december 31 1989.
January 2, 1900  6:00Pm  would have a time stamp of    1.75   or 1 and three quraters of a day  after december 31 1989.


The time stamp you are devloping is doing basicly the same thing, you just have not added a way for a starting date that is higher then  jan 1 year 0.  but I have not really answered you question yet.  

to simplify it a little lets just look at a stamp for nwn that would be the number of days  and we will still use year 0 for simplisity.   So we would have. 

//multiplyers:
int nmlDay     =    1;   //there is 1 day per day.
int nmlMonth = 28;  //There are 28 days per month.
int nmlyear    =436  // there are 336 days per year.  

// now lets create a time stamp with this without using the -1's that I included.  lets take: 
year 0.
month 12 
day 28

Our time stamp is :  12 * 28  + 28  =  364 

now lets try and get our number of years, months and days back out of the stamp.  

lets see if we devide our number by the number of years we should get our  year.   

364 / 336    =  1 with a remainde of  28.     so we have 1 year. 

 now if we take the remainder and devide it by the number of days per month we should get the month. with the remainder being the number of days.    

28/28 =   1 remainder  0 

so pulling our date back out of the stamp we get 
year 1 
month 1 
day 0 

Hmm it does really what we where looking for.    The problem is that we are using a day of 1 to 28 in our equasions   where 28 is also 1 month.  and using  1-12 months  where 12 months is also 1 year.    So that is how they are returned to us.  not to mention that our numbering system  is somehow missing the fact that I can be one be  28 day away from my start date.   

Again for simplicity lets look a a different date to find the problem.  lets say: 

year 0 
month 1 
day 1 
hour 12:00pm  // yea I know I gave  it a time.   

with the date given above what shoud our time stamp be if it is the number of days form year 0.  
well it is still in the first day.   If we had decimal places  it would be 0.5,  half a day.   The fact is that on day 1 month 1  a day has not yet passed and a month surly has not yet passed.   To simplify getting the same date out of a time stamp that we put into the time stamp we change the way the months and days are numbered from  days: 1-28  to days 0 -27.  or just day-1  
and for months from   1- 12  to 0-11  
notice that  1-12 and 0 -11 still has the same nunber of  members in the set.  { 1,2,3,4,5,6,7,8,9,10,11,12] and [0,1,2,3,4,5,6,7,8,9,10,11]  both sets have 12 members.   the 0-11 is the preferred usage because it is 0 based  making it so the upper limit does not (11)  does not get confused with a full year like the upper limit of the other set (12) would.   


so lets look back at our orginal try that returned the wrong date when we tryed to convert it back from the stamp.  
year 0.
month 12 
day 28 

if we are in month 12 , 12 months have not yet passed .  11 months have passed putting us in the 12 month.  
on day 28 only 27 days have fully passed.  

 so we now have 
(12-1) *28 + (28-1)  = 335 days since year 0 

ok let convert it nack to a year/ month/day 

stamp /  the number days in a year should give us the number of years with a remainder of days into the year.  

335/ 336 = 0 remainder of 336.   
ok so far so goor we get year 0.  

now when we divide the 'days into the year'  by the number of days in a month we should get the number of  month that have passed.  with a remander of days that have passed into the month.   

335/28 =  11  with a remainder of 27  

now that is not  quite the number we started with.   Just keep in mind what the 11 and 27 are.  they are the munber months and days that have passed.   if 11 months have already passed  we are not in month 11, we are in month 12.    So the month we are in will always be  "the months that have passed +1"   same thing with the days.  

so we now have 
(335/28) +1  = our month.  
 our day is the remainder (27 +1) =  day 28.  


now let me try and work in the modulo '%" operator.  

the only thing the modulo does is return the remainder of the division.  

so in our last division there where we had the nimber of days into the year.   335 of them 

335 / 28 = 11  
now if we need to find the remainder for our number of days  wy can either  muntiply 28 by 11 and then subtract it from our original 335  
335 -  (28*11)  = 27 

or we can just use the modulo to give us the remainder. 

335 % 28  = 27


I hope that explains everything. 
L8   



#18
Epitaffio

Epitaffio
  • Members
  • 35 messages
Woah, long and perfect, thanks for the time L8!

#19
Epitaffio

Epitaffio
  • Members
  • 35 messages
I think i must share the last edited function for future reference


    int iMinPerHour = FloatToInt(HoursToSeconds(1)/60);
    int iMinPerDay = 24*iMinPerHour;
    int iMinPerMonth = 28*iMinPerDay;
    int iMinPerYear = 12*iMinPerMonth;

    int iMinute  = GetTimeMinute();
    int iHour    = GetTimeHour() * iMinPerHour;
    int iDay     = (GetCalendarDay()-1) * iMinPerDay;
    int iMonth   = (GetCalendarMonth()-1) * iMinPerMonth;
    int iYear    = GetCalendarYear() * iMinPerYear;

    int iTimestamp = iMinute + iHour + iDay + iMonth + iYear;



Here the decoding:

    int iTestYear = iTimestamp/iMinPerYear;
    iTimestamp = iTimestamp%iMinPerYear;

    int iTestMonth = iTimestamp/iMinPerMonth +1;
    iTimestamp = iTimestamp%iMinPerMonth;

    int iTestDay = iTimestamp/iMinPerDay +1;
    iTimestamp = iTimestamp%iMinPerDay;

    int iTestOre = iTimestamp/iMinPerHour;
    iTimestamp = iTimestamp%iMinPerHour;

    int iTestMinuti = iTimestamp;

#20
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
looks good.

#21
henesua

henesua
  • Members
  • 3 867 messages
 Since this was linked to recently I thought it would be worth while to share my time functions:
http://pastebin.com/xnJMcHFR

I saw the comment above that game hours are not necessarily equalt to 60 game minutes. This is true. I create a constant in my modules that represents a conversion from game minutes to real minutes. So if a game hour is only 2 game minutes, the value of my constant is 30 (meaning 30 real minutes per game minute).