Useful Time Functions
vining
X Member
Here's some useful time functions. There are similar functions out there but I can never find them when I need them so I made these.
This uses the standard TIME keyword format so you can just pass it "TIME" and it will return that time in total amount of seconds so you can do math on it.
This uses the standard TIME keyword format so you can just pass it "TIME" and it will return that time in total amount of seconds so you can do math on it.
DEFINE_FUNCTION LONG fn24HourTimeTo_Seconds(CHAR iTime[])
{
RETURN ((((ATOI(REMOVE_STRING(iTime,"':'",1)) * 60) * 60) + ATOI(REMOVE_STRING(iTime,"':'",1)) * 60) + ATOI(iTime)) ;
}
Once you do your math on the seconds you can convert it back to the "TIME" format with this.
DEFINE_FUNCTION CHAR[8] fnSecondsTo_24HourTime(LONG iTimeInSeconds)
{
RETURN "right_string("'0',ITOA(iTimeInSeconds / 3600)",2),':',
right_string("'0',ITOA((iTimeInSeconds % 3600) / 60)",2),':',
right_string("'0',ITOA((iTimeInSeconds % 3600) % 60)",2)" ;
}
Here's a function which uses these functions to add tiime to the current time. In this case to create an expiration time 10 minutes later.
DEFINE_CONSTANT
CHAR WEB_MONTH[12][3] = {'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'} ;
DEFINE_FUNCTION fnUpdateDATE_TIME()
{
STACK_VAR CHAR cLDATE[10] ;
STACK_VAR INTEGER nMonth ;
STACK_VAR INTEGER nDay ;
STACK_VAR CHAR cYear[4] ;
cLDATE = LDATE ;
nMonth = atoi(REMOVE_STRING(cLDATE,"'/'",1)) ;
nDay = atoi(REMOVE_STRING(cLDATE,"'/'",1)) ;
cYear = cLDATE ;
cWebCurDateTime = "DAY,', ',itoa(nDay),' ',WEB_MONTH[nMonth],' ',cLDATE,' ',TIME,' EST'" ;
cWebExpDateTime = "DAY,', ',itoa(nDay),' ',WEB_MONTH[nMonth],' ',cLDATE,' ',
fnSecondsTo_24HourTime(fn24HourTimeTo_Seconds(TIME) + EXPIRES_IN_SECONDS),' EST'" ;
RETURN ;
}
In the above example EXPIRES_IN_SECONDS is a constant of 600. Which is 600 seconds or ten minutes that gets added to the current time to create the expiration time. Comments
-
You may or may not be aware but it should be noted that the posted code will generate undesirable results if the start time + the offset time roll over into a new day.
Using your example, cWebExpDateTime will not be correct if the function is called to add the 10 minutes at say 11:55 PM. The first problem (which has an easy enough fix) is that the time will come back as 24:05, an illegal time. The day of the month will definitely be wrong as will the day of the week. It?s also possible the month may be wrong and for that matter the year will also be wrong if the function is called on Dec. 31st at 11:55 PM.
Unless the application can live with these limitations the only real way to go in my mind is to work with UNIX time functions when time/date addition/subtraction come into play. -
I'll have to take a closer looke when I get a chance.
-
DEFINE_FUNCTION CHAR[6] itoa_zf(INTEGER n,INTEGER len){ // returns ASCII string representing n, that is zero filled to length len STACK_VAR CHAR result[6]; // max return size STACK_VAR INTEGER i; result = itoa(n); while(LENGTH_STRING(result)<len){ result = "'0',result"; } return result; } DEFINE_FUNCTION CHAR[8] TIME_MILITARY_TO_REAL(CHAR cT[]){ // given '13:23' returns '1:23 PM' STACK_VAR INTEGER h; STACK_VAR INTEGER m; STACK_VAR CHAR t[5]; t = cT; h = atoi("REMOVE_STRING(t,':',1)"); m = atoi("t"); if(h > 12){ // PM time return "itoa(h-12),':',itoa_zf(m,2),' PM'"; } else if(h==0){ // 12:00am-12:59am return "'12:',itoa_zf(m,2),' AM'"; } else if(h==12){ // 12:00pm-12:59pm return "'12:',itoa_zf(m,2),' PM'"; } else{ // 1:00am-11:59am return "itoa(h),':',itoa_zf(m,2),' AM'"; } return 'Never'; // unreachable } DEFINE_FUNCTION CHAR[6] TIME_MIN_TO_HRMIN(INTEGER nT){ // given 61 returns '1:01' STACK_VAR INTEGER h; STACK_VAR INTEGER m; m = nT; h = 0; while(m > 59){ m = m - 60; h++; } return "itoa(h),':',itoa_zf(m,2)"; } -
<FORMAT_PSA>
What?s wrong with the FORMAT command? It?s way more flexible and powerful and there isn?t a 6 character limitation.
Instead of this:DEFINE_FUNCTION CHAR[6] itoa_zf(INTEGER n,INTEGER len){ // returns ASCII string representing n, that is zero filled to length len STACK_VAR CHAR result[6]; // max return size STACK_VAR INTEGER i; result = itoa(n); while(LENGTH_STRING(result)<len){ result = "'0',result"; } return result; } answer = itoa_zf(number,length)
All you really need is this:answer = FORMAT("'%0',ITOA(length),'d'",number)
I?ve been hired as the 2009 FORMAT spokesperson so I was compelled to respond and spread the good word.
</FORMAT_PSA> -
Joe Hebert wrote: »<FORMAT_PSA>
What?s wrong with the FORMAT command? It?s way more flexible and powerful and there isn?t a 6 character limitation.
That's cheating.
Paul -
This function seems to solve the rollover problems but needs some more testing since I only had a couple hours this eveining to play. I included a test line in define program so you can open variable debug and just drop time in seconds into the nTestSecondsAdded variable and then set the nTestTime variable to 1 to see it print in diagnostics.
DEFINE_CONSTANT NUM_SECONDS_DAY = 86400 ; CHAR WEB_MONTH[12][3] = {'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'} ; LONG DAYS_MONTHs[12] = {31 ,28 ,31 ,30 ,31 ,30 ,31 ,31 ,30 ,31 ,30 ,31} ; LONG DAYS_LEAPMONTHs[12] = {31 ,29 ,31 ,30 ,31 ,30 ,31 ,31 ,30 ,31 ,30 ,31} ; CHAR WEB_DAYS[7][3] = {'SUN','MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'} ; DEFINE_VARIABLE //GENERAL VARS VOLATILE LONG nTestSecondsAdded ; VOLATILE INTEGER nTestTime ; DEFINE_FUNCTION CHAR[30] fnDo24hrTimeAddition(CHAR iLDate[],CHAR i24HourTime[],LONG iSecondsAdded) { STACK_VAR INTEGER nYear ; STACK_VAR INTEGER nMonth ; STACK_VAR INTEGER nLeap ; STACK_VAR CHAR c24HrTime[8] ; STACK_VAR CHAR cNewDate[10] ; STACK_VAR LONG nDay ; STACK_VAR LONG nDaysOver ; STACK_VAR LONG nSecondsRemain ; STACK_VAR LONG nTotalTimeSeconds ; nTotalTimeSeconds = fn24HourTimeTo_Seconds(i24HourTime) + iSecondsAdded ; nMonth = atoi("REMOVE_STRING(iLDATE,"'/'",1)") ; nDay = atoi("REMOVE_STRING(iLDATE,"'/'",1)") ; nYear = atoi("iLDATE") ; if(nTotalTimeSeconds > NUM_SECONDS_DAY) { STACK_VAR INTEGER i ; nDaysOver = nTotalTimeSeconds / NUM_SECONDS_DAY ; nSecondsRemain = nTotalTimeSeconds % NUM_SECONDS_DAY ; if(!(nYear % 4))//http://en.wikipedia.org/wiki/Leap_year { nLeap = 1 ; if(!(nYear % 100))//double check these rules?????? { if(nYear % 400) { nLeap = 0 ; } } } if(nLeap) { if((nDaysOver + nDay) > DAYS_LEAPMONTHs[nMonth]) { nDaysOver = nDaysOver - (DAYS_LEAPMONTHs[nMonth] - nDay) ; nMonth++ ; for(nMonth = nMonth ; nDaysOver > DAYS_LEAPMONTHs[nMonth] ; nMonth++) { nDaysOver = (nDaysOver - DAYS_LEAPMONTHs[nMonth]) ; if(nMonth == 12) { nMonth = 1 ; nYear ++ ; } } nDay = nDaysOver ; } else { nDay = nDaysOver + nDay ; } } else { if((nDaysOver + nDay) > DAYS_MONTHs[nMonth]) { nDaysOver = nDaysOver - (DAYS_MONTHs[nMonth] - nDay) ; nMonth++ ; for(nMonth = nMonth ; nDaysOver > DAYS_MONTHs[nMonth] ; nMonth++) { nDaysOver = (nDaysOver - DAYS_MONTHs[nMonth]) ; if(nMonth == 12) { nMonth = 1 ; nYear ++ ; } } nDay = nDaysOver ; } else { nDay = nDaysOver + nDay ; } } c24HrTime = fnSecondsTo_24HourTime(nSecondsRemain) ; } else { c24HrTime = fnSecondsTo_24HourTime(nTotalTimeSeconds) ; } cNewDate = "right_string("'0',ITOA(nMonth)",2),'/',right_string("'0',ITOA(nDay)",2),'/',right_string("'0',ITOA(nYear)",2)" ; RETURN "WEB_DAYS[TYPE_CAST(DAY_OF_WEEK(cNewDate))],', ',itoa(nDay),' ',WEB_MONTH[nMonth],' ',itoa(nYear),' ',c24HrTime,' EST'" ; } DEFINE_PROGRAM if(nTestTime) { SEND_STRING 0, "'WEB_DEBUG: ',fnDo24hrTimeAddition(LDATE,TIME,nTestSecondsAdded)" ; nTestTime = 0 ; } -
I took the code out for a quick spin and it looks good from here.This function seems to solve the rollover problems but needs some more testing since I only had a couple hours this eveining to play. -
Does it take into account daylight savings time, as that would change the results depending on your location, time of year and local DST rules, no?
Paul -
shouldn't we all use the i!timemanager module?
-
a_riot42 wrote:
I didn't even think of that but that should be fairly easy to impliment.Does it take into account daylight savings time, as that would change the results depending on your location, time of year and local DST rules, no?
yuri wrote:
I use it for Sunrise/Sunset and have been doing so for ever but I didn't know it did anything else. Does it? If it does I might have used it and save myself from having to think a little.shouldn't we all use the i!timemanager module?
I also wondered why there's the built in function "DAY_OF_WEEK" which can return what the day of the week is for any date you plug but there's no other standard functions for time manipulation. -
a_riot42 wrote:
I didn't even think of that but that should be fairly easy to impliment.
You're kidding right?
Paul -
I'd just need to create DATE to DAY_OF_YEAR function. Have variable for the nDST_DOY_START and nDST_DOY_END and if my DAY_OF_YEAR of the resulting date falls bewteen the start and stop while the initial date falls before the start I could adjust the resulting hour. If it spans several years or just both the start and stop days they'll cancel each other and no fuss.
To figure out these days I'll do a DAY_OF_WEEK on 03/01/cCurYear which will tell me the day of the week 1-7 that date is and I'll do math to figure out when the 2nd "1" would be. Then do the same thing for 11/01/cCurYear and then figure out when the first "1" would be.
I thinks this would work and be fairly simple but I've been wrong before...........
-
You have your work cut out for you. DST is a b*tch, since it depends on location and the DST rules that change periodically. Some locations don't have DST, some states do or have numerous time zones. Without longitude and latitude, I can't see how you can make it work for any arbitrary location and time zone. Time functions are very non-trivial to write correctly, so if you can do it, you will have accomplished something few programmers can do.
Paul -
a_riot42 wrote:
I didn't say anything about doing it correctly!Time functions are very non-trivial to write correctly
If I was to attempt DST I would just make work for my area and my needs and if others want to use it they could do the same for theirs. Otherwise it would be a real pain to make universal. Still if I did it like iTimeManager and make rules that the programmer has to fill in based on their region that still might not be so bad. DST yes/no, begins/ends. I once wanted to do a module that would figure holidays and when I started looking at Muslim holidays I had to give up since they'll change for any number of reasons like rain or just overcast skies.
As for my needs, I only wanted to add 10 minutes to the current time for a web page expiration time which I don't even need to include in my web page header. I just figured why not just for the heck of it and now we're talking DST rules for the world. :eek:
Categories
- All Categories
- 2.5K AMX General Discussion
- 922 AMX Technical Discussion
- 514 AMX Hardware
- 502 AMX Control Products
- 3 AMX Video Distribution Products
- 9 AMX Networked AV (SVSI) Products
- AMX Workspace & Collaboration Products
- 3.4K AMX Software
- 151 AMX Resource Management Suite Software
- 386 AMX Design Tools
- 2.4K NetLinx Studio
- 135 Duet/Cafe Duet
- 248 NetLinx Modules & Duet Modules
- 57 AMX RPM Forum
- 228 MODPEDIA - The Public Repository of Modules for Everyone
- 943 AMX Specialty Forums
- 2.6K AMXForums Archive
- 2.6K AMXForums Archive Threads
- 1.5K AMX Hardware
- 432 AMX Applications and Solutions
- 249 Residential Forum
- 182 Tips and Tricks
- 146 AMX Website/Forums