Method for keeping time
Blitz3D Forums/Blitz3D Programming/Method for keeping time
| ||
Hey!, the project i'm working on has faced me with a great task, i knew it was coming, it was in the plans, anyways: Lets say my program keeps track of plant growth. my user chooses a grape plant to grow like so: you just planet a grape, will be fully grown in 5 days! i store a time in a .txt file, when he opens the program 4 days later i want the program to know: your grape still needs 1 day to grow how would i go about doing something like this? obviosly i have to store a time in a .txt file, so it can read off that when it starts up next. i got that much. |
| ||
You could use CurrentDate$() to read the current date, and compare it to the date stored in the file. A user could put back his computer clock/date or he could return after 15 days, while the plant needs 5 days to grow. It could be sensible to take these situations in account. So: 0) get currentdate$ 1) if filetype = 0 then new file, write date (new plant) 2) if filetype = 1 then open file, read date (old plant) 3) substract old date from new date, result is age of plant 4) if age < 0 then .. if age > 5 then .. 5) print 'your plant is ' + age + 'days old' |
| ||
how would i substract the old date from the new date like for example this program doesnt work for obviose reasons..Graphics 800,600,16,2 date$=CurrentDate() olddate$ = "20 Jul 2007" Print date$-olddate$ Delay 6000 the rest is pretty straight forword.. |
| ||
Duh.Graphics 800,600,16,2 date$=CurrentDate() olddate$ = "20 Jul 2007" int_date%=Left(date,2) int_olddate%=Left(olddate,2) Print int_date-int_olddate Delay 6000 Awsome. thanks for the help b32! |
| ||
Hmm, is CurrentDate's month return always the first 3 letters of a month? i need to be sure before i write this function |
| ||
ok, now i'm trying to get a hour value, lets pretend "Gas" is a fuel that runs per hour burning 450 units per hour.. heres the function i'm using to return how many days of 'gas' you have left. Function daysleft(fueltype$,amount) days=0 Select fueltype$ Case "Gas" days=amount/10800 End Select Return days End Function this functions pretty straight forword, you punch in Gas as your fuel, and it devides the amount of fuel you punched in by a days worth a fuel(for gas) and returns the result. i need the same thing but returns how many hours (ontop of the days) you have left.. so that i can display this as like You have DD days left and HH hours left of Gas i cant just write the same function but instead of days=amount/10800 put days=amount/450 because that would return the total amount of hours of gas i have, not what i'm looking for.. so i tried somthing like this with a float: Function hoursleft$(fueltype$,amount#) tmp# = 0.0 hours=0 tmp2$="" Select fueltype$ Case "Gas" tmp#=amount/10800 End Select tmp2$=tmp# hours% = Mid(tmp2,2,1) Return hours End Function to extract the first decimal of a float of days (that would be the hours) but for some reason it doesnt seem accurate.. what am i doing wrong? or am i going about it wrong, if so any ideas on how to do this? |
| ||
i don't get this even the simplest function is incorrect:Function hoursleft$(amount#) amount=amount / 10800 Return amount End Function if you enter 450, that would be 1 hour of the 24 hours, so it should return 0.1 can anyone explain why this isnt working? |
| ||
Your function works. But dividing 450 by 10800 will not return 0.1, that's simple math. |
| ||
no it doesnt, take this small program for example:houramount# = 450.0 proof# = houramount*24 daysamount# = proof# Print houramount / daysamount Delay 6000 should display "0.1" but it displays 0.04and a bunch of numbers.. |
| ||
oi, duh, i put it backwords. Edit and you changed your reply :D |
| ||
As for the remaining hours, I think you could use the Mod operator. It returns the remainder of a division. Ie: days = amount / 100 --> division with integers will return only whole numbers hours = amount mod 100 In this example, if 'amount' is 201, 'days' will be 2 and 'hours' 1 |
| ||
Yeah, i'm tried, i think this mod thing might be what i'm looking for. i'll try it |
| ||
hmm, it seems mod returns the total number in this case? i use: days=11250/ 10800 to return the days(1) and now using hours = 11250 Mod 10800 and it returns 11250? am i doing somthing wrong? as soon as i get this one i'm going to bed |
| ||
Yes, I think so ? Because when I try it, I get 450:Print 11250 Mod 10800 WaitKey() |
| ||
Duh, i see what went wrong! thanks b32! |
| ||
You might find dates a lot simpler to work with if you convert them to the number of seconds since X. X is conventionally January 1, 1970, but you could very easily use January 1, 2000 or (perhaps better) the date/time that the current game was started. If you do this, all the math becomes trivial addition and subtraction. |
| ||
By the way Yahfree, I just posted a small collection of my date functions in the code archive, if you are interested. Currently, there are no example code, but if people are really struggling, I'll try to find time to make a couple examples. http://www.blitzbasic.com/codearcs/codearcs.php?code=2081 Cheers. |
| ||
Very useful, thanks _33, octhothorp, that might be easy, but i don't see any functions that return the current date/month/year/hour/minute/second in seconds.. |
| ||
That is because Blitz uses 32 bit long integers (a standard integer is 16 bits, also known as a "short" integer), time in seconds (such as how Windows stores creation/modification dates for files) is stored in 64 bit integers(not sure what they are normally called, "double long integers" maybe?). 32 bits is just not enough to store that much data. A 32 bit signed int will work for 68 years, a 64 bit signed int will work for 292,471,208,677 years either side of your starting date (which is enough to store the age of the earth, even if you believe in an old earth) If you want the current date and time, try this: date$=CurrentDate$() time$=CurrentTime$() year%=Right$(date$,4) month$=Mid$(date$,4,3) day%=Left$(date$,2) hour%=Left$(time$,2) minutes%=Mid$(time$,3,2) seconds%=Right$(time$,2) If you want months in an integer then change the "month$=" to "m$=" and add the following: Select m$ Case "JAN":month%=1 Case "FEB":month%=2 Case "MAR":month%=3 Case "APR":month%=4 Case "MAY":month%=5 Case "JUN":month%=6 Case "JUL":month%=7 Case "AUG":month%=8 Case "SEP":month%=9 Case "OCT":month%=10 Case "NOV":month%=11 Case "DEC":month%=12 Default: month%=1 End Select |
| ||
yep, i wrote some functions to return ints of date ect ect here they are if they seem useful... |
| ||
Yuck, i got a problem, i'll try to explain the best i can. To put it into propective i'll use a pretend plant program as an example. In this plant program, people can share information on how old their plants are. the program reads a plant information file, in txt, thats how they share the plant information.. so person A is from a different timezone then person B person A wants to show person B on how his plant is doing. Person B takes the information file from person A the program then takes the old time marked on the file, and compares it with his 'new time' because Person B is 2 hours ahead of Person A, his program takes Person A's file and reads Person A's time.. when the program grabs Person Bs current time, it calculates the plant to be 2 hours older then it should be! thats my problem, But, i wrote my program so when it opens the first time, it subtracts everything and writes it back to the file. in this messed up case, it would write the plant data back to the file with the information that the plant is 2 hours older then it should be. after it writes back what it thinks is the correct data, the program then updates the time. my update time function updates the time based on the computer clock, so it would fix this issue. but i cant use it before i update the data, otherwise it wouldnt subtract how old the plant is correctly, it would think no time has passed, and it would take any time off the plant. i hope i was clear enough, how would i solve this problem? |
| ||
Maybe you could read out what timezone the user is, and convert the system time to GMT before using it ? Here is how to use the api, not sure if the daylight saving time stuff works correctly though. It was based on this info in the msdn: http://msdn2.microsoft.com/en-us/library/ms885646.aspx |
| ||
Ohh, interesting, if i could convert everyones time into gmt time so the program only has to worry about 1 time, that would solve the problem, heres a dumb question, being the kid i am, different timezones can only be plus from gmt? like for example is there any timezone that GMT-2 or any negitives? |
| ||
Errrrmmm .. offcourse I know that .. (googlegoogle) .. http://wwp.greenwichmeantime.com/info/timezone.htm They seem to go from -12 to +12 |
| ||
Then how do you know if: Print "Your time is GMT+" is + or minus? if it was minus would that line be: "Your time is GMT+-"+time? Edit, i wasnt very clear, would time be normal int for plus I.E. 6 and a negitive int for minus I.E. -6? |
| ||
Also, what would i have to do to add that feature? my guess would be: somthing like this: to get the new time i use this: (i would modify my functions above): function ReturnHourInt() bank = CreateBank(255) tmp = api_GetTimeZoneInformation(bank) tmp2 = PeekInt(bank, 0) tmp2=tmp2/60 temp$ = CurrentTime() temp2% = Left(temp$,2) temp2%=temp2%-tmp2 Return temp2 End Function or somthing like that? right idea? wrong idea? or failing horribly? |
| ||
Erm .. yes, you're right .. 'bias' would be negative in such an area. The 'daylightbias' is a bit more difficult. The structure also contains two dates, that indicate the start/end date for the daylight saving time. Before the first date, the clock is set normally to GMT+bias However, between the two dates, the clock is set to GMT+bias+daylightbias. I think the 'timezone' structure is now read properly, however it could be good to test it a bit. |
| ||
Ow .. missed your last post .. Ehm, something like that should work, first extract hours/mins, then add 'bias' en if the date is in the 'timesave' period, add 'daylightbias' too time$ = CurrentTime$() Print time$ hour = Mid$(time$, 1, 2) min = Mid$(time$, 4, 2) sec = Mid$(time$, 7, 2) Print hour Print min Print sec WaitKey() |
| ||
mm k... but i thought the built in computer clock grabs 'daylightbias' anyways? so if its in daylightbias, it should subtract more anyways correct? |
| ||
how do i figure the date in GMT time? i mean the month doesnt matter, because the most difference between your time and gmt time cant differ up to months.. Edit, also, why doesnt this work? Function ReturnHourInt%() bank = CreateBank(255) tmp = api_GetTimeZoneInformation(bank) tmp2 = PeekInt(bank, 0) tmp2=tmp2/60 temp$ = CurrentTime() temp2% = Left(temp$,2) If tmp2 > 0 temp2%=temp2%-tmp2 If tmp2 < 0 temp2%=temp2%+tmp2 Return temp2 End Function should return the hour in GMT time no? well to double check i switched my computer clock to a different timezone ... and the time was different! it should be the same, as the function should compensate for that. |
| ||
Have you also reset the clock when changing the timezone ? I tried the following with a few timezones and the result in 'minutes' was allways the same. However, it is still not fullproof. The returned daylight-dates don't seem to be right and I'm not sure if the test I made for daylightsaving is full-proof. So I would keep it in a Function, so it is easier to upgrade later on. |
| ||
hmm, i'm confused, i'm trying to get the hour in gmt time to start with, but my atempts differ one the time zone set on my computer clock means its not working correctly.. the plan is no matter what time the users clock is based on, it does the math to convert the user current time into the current gmt time. how would i do this? ok lets simplefy this, how would i create 2 functions that return the current hour and current date in gmt time, i ausume it would be close to the functions i wrote above (ReturnHourInt, ReturnDateInt) as shown above i tried to modify ReturnHourInt to return the GMT time but i failed horribly.. any ideas? Edit, and i tried your example above, and a +8 time zone would return 1000 somthing and a -8 time zone would return 300 somthing 'minutes' Edit2, Just to clear things up a little bit, the prototype i'm building doesnt accuratly respond to hours.. it doesnt grab the current minute, for example: if you planted your plant seed at 14:59 in 1 minute it will consider it 1 hour old. i plan to change this after i get this working. |
| ||
Okay, I gave it another try. This time I tested it more properly, so now it should be better. I tried writing a function that converts a given time into GMT-time: |
| ||
THATS PERFECT! You didnt have to make it for me :\ a simple point in the right direction woulda done! thanks anyways, the only thing remaining is a function that returns the same thing as CurrentDate() but in GMT time, then it should go in the archive, how would you go about doing this? and wheres the documents on what each byte is on this bank? like how do you know: bias = -PeekInt(bank, 0) is at 0? oh and to clean up that function a bit you can put Date/Time in the function... IE Function MakeGMTTime$() date$ = CurrentDate$() time$ = CurrentTime$() then it only becomes: Graphics 800, 600, 0, 2 SetBuffer BackBuffer() Repeat yourtime$ = CurrentTime$() Cls Text 0, 0, "now:" + yourtime$ Text 0, 20, "GMT:" + MakeGMTTime$() Flip Until KeyHit(1) End Function MakeGMTTime$() date$ = CurrentDate$() time$ = CurrentTime$() ;split date day = Mid$(date$, 1, 2) mon = (Instr("JanFebMarAprMayJunJulAugSepOctNovDec", Mid$(date$, 4, 3)) + 2) / 3 bank = CreateBank(255) ;retreive timezone info api_GetTimeZoneInformation(bank) ;offset in minutes for the timezone bias = -PeekInt(bank, 0) ;date when 'normal' time starts month1 = PeekShort(bank, 70);month day1 = PeekShort(bank, 74);day hour1 = PeekShort(bank, 76);hour ;date when 'normal' time starts month2 = PeekShort(bank, 154);month day2 = PeekShort(bank, 158);day hour2 = PeekShort(bank, 160);hour ;amount of minutes offset in summer daylightbias = PeekInt(bank, 168) FreeBank bank ;test for daylightsaving test = 0 If (mon >= month2) And (mon <= month1) Then If (mon <> month1) And (mon <> month2) Then test = 1 If (day >= day2) And (mon = month2) Then test = 1 If (day <= day1) And (mon = month1) Then test = 1 End If If test Then bias = bias - daylightbias hour = Int(Mid$(time$, 1, 2)) - (bias / 60.0) If hour < 0 Then hour = hour + 24 If hour > 23 Then hour = hour - 24 min = Int(Mid$(time$, 4, 2)) sec$ = Right$(time$, 2) time$ = hour + ":" + min + ":" + sec Return time$ End Function |
| ||
About the date, first add the bias to the time. And if the new time is before 0:00 or after 23:59, then add or substract a day. With that new 'day', you can do the same thing towards months. If it is below zero or greater than the numbers of days in a month, substract or add a month. Then the same from month->years About the bias, on the msdn page about this command: http://msdn2.microsoft.com/en-us/library/ms885646.aspx is a link to the TIME_ZONE_INFORMATION 'typedef': typedef struct _TIME_ZONE_INFORMATION { LONG Bias; WCHAR StandardName[32]; SYSTEMTIME StandardDate; LONG StandardBias; WCHAR DaylightName[32]; SYSTEMTIME DaylightDate; LONG DaylightBias; } TIME_ZONE_INFORMATION; That is the information that will be stored in the bank. 'Long' in this case is the same as an Integer/Int (4 bytes), and -after testing- I thought that WChar[32] is a 64 bytes string. 'Bias' is the first element of this type, that is why it is at zero. SYSTEMTIME is also a type: typedef struct _SYSTEMTIME { WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; } SYSTEMTIME; And a Word is 2 byte, I used PokeShort/PeekShort for this. |
| ||
If it is below zero or greater than the numbers of days in a month How do i get the number of days in each month? then store it some way to be able to compare it with the current month? |
| ||
I would make a string containing all the max. days in the months, each 2 characters, and then use Mid$() to get the appropriate value for the current month. Then, I believe a leapyear can be found by this (year mod 4 = 0) I would multiply that with (month = 2) and add it to the number of days found with Mid$ |
| ||
hmm, can you give me a small example? i havent seen this type of technque before i think its the same as this line:mon = (Instr("JanFebMarAprMayJunJulAugSepOctNovDec", Mid$(date$, 4, 3)) + 2) / 3 |
| ||
:D Yes .. it is a bit weird I supposemaxdays = Int(Mid$("312831303130313130313031", month * 2 - 1, 2)) + ((month = 2) * (year Mod 4 = 0)) |
| ||
interesting, looks very strange.. i'll mess with it thanks! |
| ||
Question, in your code above, month would be int 1-12 correct? and year would be the full year IE 2007? |
| ||
Yes, although I'm not really certain about these leapyears. 2000 was a leapyear, right ? 2008..2004..2000 .. yes .. I think it is correct. And month is 1-12, integer, indeed |
| ||
Well heres the final function, let me know what you think:;-------------------------------------------- ; MakeGMTDate$() ;-------------------------------------------- Function MakeGMTDate$() date$ = CurrentDate$() time$ = CurrentTime$() day = Mid$(date$, 1, 2) mon = (Instr("JanFebMarAprMayJunJulAugSepOctNovDec", Mid$(date$, 4, 3)) + 2) / 3 year = Mid(date$,8,4) maxdays = Int(Mid$("312831303130313130313031", mon * 2 - 1, 2)) + ((mon = 2) * (year Mod 4 = 0)) hour = Int(Mid$(time$, 1, 2)) min = Int(Mid$(time$, 4, 2)) bank = CreateBank(255) ;retreive timezone info api_GetTimeZoneInformation(bank) ;offset in minutes for the timezone bias = -PeekInt(bank, 0) ;date when 'normal' time starts month1 = PeekShort(bank, 70);month day1 = PeekShort(bank, 74);day hour1 = PeekShort(bank, 76);hour ;date when 'normal' time starts month2 = PeekShort(bank, 154);month day2 = PeekShort(bank, 158);day hour2 = PeekShort(bank, 160);hour ;amount of minutes offset in summer daylightbias = PeekInt(bank, 168) FreeBank bank test = 0 If (mon >= month2) And (mon <= month1) Then If (mon <> month1) And (mon <> month2) Then test = 1 If (day >= day2) And (mon = month2) Then test = 1 If (day <= day1) And (mon = month1) Then test = 1 End If If test Then bias = bias - daylightbias ;If the hour is greater then 23 (24+) then day would be 1 more in GMT If hour+bias/60 > 23 day=day+1 ;If the hour is lesser then 0 (-1 and below) then the day would be 1 less in GMT If hour+bias/60 < 0 day=day-1 ;If the day exceeds the max amount of days in the month, then the month would be 1 more in GMT If day > maxdays mon=mon+1 ;if the day is less then 1 the month would be 1 less in GMT, reset maxdays so it reads the new month.. ; And set the day to the max days in the month (1 less from the next month) If day < 1 mon=mon-1 maxdays = Int(Mid$("312831303130313130313031", mon * 2 - 1, 2)) + ((mon = 2) * (year Mod 4 = 0)) day=maxdays End If ;If the month exceeds 12 (months in a year) set months to 1 If mon > 12 year=year+1 mon = 1 ;If the month is less then 1, set months to 12, drop year by 1 If mon < 1 year=year-1 mon = 12 Select mon Case 12: f_mon="Dec" Case 11: f_mon="Nov" Case 10: f_mon="Oct" Case 9: f_mon="Sep" Case 8: f_mon="Aug" Case 7: f_mon="Jul" Case 6: f_mon="Jun" Case 5: f_mon="May" Case 4: f_mon="Apr" Case 3: f_mon="Mar" Case 2: f_mon="Feb" Case 1: f_mon="Jan" End Select Return day + " " + f_mon + " " + year End Function looks alright to me, but i might of missed somthing/screwed somthing up :D off to testing |
| ||
Two minor thingies: f_mon isn't defined as a string, so it returns a zero now instead of Aug. And 'day' should allways return 2 digits, even if it is below 10. So best is, to make that a string first, f_day, then add a zero to it if day<10. But for the rest: it looks nice. I also hope it works okay. |
| ||
ok it seems to work alright, thanks for pointing that out, and thanks for all the help, heres the final functions with a example: CurrentGMTTime(Fixed a display issue) CurrentGMTDate Example: I'll go code Archive these gems |
| ||
Hmm, maybe all is not well? run the example under different timezone settings on your computer clock, the GMT time seems to change? any ideas? |
| ||
Hmm, I tried that, but it seems to work correctly ? I tested your last posted code under 'example'. In every timezone, I got 15:43 |
| ||
Hmm, set your timezone to somthing that has a halfhour thrown in it... like GMT + 9:30 or GMT - 4:30 |
| ||
I see the problem.. when the bias is applied, it is divided by 60 in an integer division. That is the reason half hours 'dissapear' from this calculation. After the line If test Then bias = bias - daylightbiasit should go like this: 1. get hours and minutes 2. convert both to single time in minutes from midnight minutes = hours * 60 + minutes 3. apply bias to that number -if below zero, add 1440 minutes (=24hour) -use Mod 1440 4. finally, divide it by 60 again to get the hours, and use Mod 60 to get the minutes. That should work better. |
| ||
cant i just use: Minutes = bias mod 60 ? then use bias as normal and add minutes to minutes? edit: somthing like this would work? minutebias = - (bias Mod 60) min = Int(Mid$(time$, 4, 2)) - (minutebias) If min < 1 Then min = min + 60 hour=hour-1 If min > 59 Then min = min - 60 hour=hour+1 |
| ||
It looks like it should work. Have you tried it allready ? |
| ||
Tried it... hmm not working it seems: what am i doing wrong? |
| ||
I think the order of calculating hour/min went wrong. First, you substract or add one to 'hour' (when checking the minutes) Then, you define 'hour' again, discarding the previous value of 'hour'. |
| ||
I don't think i get it.. the order you discribed sounds exactly how it looks in the above example? |
| ||
Yes, I tried to describe what went wrong :) First you say: If min < 1 Then min = min + 60 hour=hour-1 If min > 59 Then min = min - 60 hour=hour+1 <- So 'hour' is 1 or -1 at this point -> Then: hour = Int(Mid$(time$, 1, 2)) - (bias / 60.0) ^ Here, any previous changes made to 'hour' dissapear |
| ||
ahh i see, i made the changes, and it still doesnt seem to work :( any ideas? function as of now: |
| ||
Maybe the minutebias ? It is negative, and later on it is substracted, resulting in a positive value. |
| ||
I don't know if you've already done this, I'm too lazy to look through the fourm... You should encrypt the date in case someone tries to change the text file. |
| ||
Seems to be working now, thanks b32. Wazzup, may be a possiblilty for the future, but at the moment if the users want to screw up their own data files they can be my guest :D |