Seconds to hours minutes and seconds

I had a separate theory by subtracting the text of the time. I was thinking that no way that would work because anytime you work with text it takes longer. So, I was thinking that there may be other theories than just dividing the seconds into hours minutes and seconds.

come to think of it, I did try to subract the text of the time before. I think I had that idea when I was teaching the high schoolers.

What you do is align the hours minutes and seconds and you think of it as units. So, first you subtract the seconds. If you need to borrow or carry then you do that. Etc. It might work!

Later,
kel

Far out huh.

Subtracting by text!

You’ll need to map the ascii numbers to the text. man I’m thinking there was something wrong with that idea. If so, back to the drawing board.:smiley:

Hello.

In my experience it is always best to use data objects as timestamps, and then subtract one from each other, or add seconds to one, when you need to represent a time, or track some point in time.

The date object has the advantages, of always making the time difference right, when a timing starts late at night, and continue into the morning for instance. (But it won’t help you with regards to a change in time-zone, hence the gmt subtraction I used earlier.

Here is a little handler I have made for presenting time, just to give you some ideas

on fmt24HTime(aDate)
	set {hours:h, minutes:m, seconds:s} to aDate
	if h < 12 then
		set h to "0" & h
	else
		set h to "" & h
	end if
	if m < 10 then set m to "0" & m
	if s < 10 then set s to "0" & s
	return (h & ":" & m & ":" & s)
end fmt24HTime

my 2 ¢


secondsToHMS from 5240 --> "01:27:20"

on secondsToHMS from theSeconds
	tell theSeconds to return my pad(it div hours) & ":" & my pad(it mod hours div minutes) & ":" & my pad(it mod minutes)
end secondsToHMS

on pad(v)
	return text -2 thru -1 of (v + 100 as text)
end pad


Edit: replaced the literal numbers with the appropriate constants

Hello.

Stefans approach, is interesting, using div’s and mod operations is probably much faster than messaging an object anyway.

I have optimized my handler a little by removing the assignment of the date properties to a record. And I found a bug with regards to formatting.

on fmt24HTime(aDate)
	tell aDate
		set h to hours of it
		set m to minutes of it
		set s to seconds of it
	end tell
	if h < 10 then
		set h to "0" & h
	else
		set h to "" & h
	end if
	if m < 10 then set m to "0" & m
	if s < 10 then set s to "0" & s
	return (h & ":" & m & ":" & s)
end fmt24HTime

kel asked just for seconds to h:m:s, no AS date object involved

Hello Stefan

Well, it is short and readable, and I am not sure if you can gain anything, from adding statements in order to remove the modulus operations, or if that is feasible in the first place, with regards to the adding of statements. :slight_smile:

(Kel’s code wouldn’t need anyting of this anyway, as that code will execute one operation at a time. I was more thinking of formatting a large list of seconds.)

Could you explain why you want to remove the mod(ulus) command? AFAIK it’s a primitive processor instruction supported by Intel which can’t be optimized in any other way. Or does AppleScript calculate the modulo by itself?

Well, if you look beneath the assembler instruction set in general, then a div and modulus, does a lot more than a multiplication. Especially the modulus is a “high cost” operator.

So, I figured, if you have done a div already, then it will be cheaper to subtract the quantity by multiplying the quotient by the divisor.

It is easier to show it by code, what I mean. :slight_smile:

set fmtTime to secondsToHMS from 3719
--> "01:01:59"
on secondsToHMS from theSecs
	set h to theSecs div 3600
	set s to theSecs - h * 3600
	set m to s div 60
	set s to s - m * 60
	
	if h < 10 then
		set h to text -2 thru -1 of ("00" & h)
	else
		set h to h as text
	end if
	
	if m < 10 then set m to text -2 thru -1 of ("00" & m)
	if s < 10 then set s to text -2 thru -1 of ("00" & s)
	
	return (h & ":" & m & ":" & s)
end secondsToHMS

Edit
But I also wrote that the benefit would truly be eaten up the added number of statements, just for the hell of it, I made an optimized version, and it can’t beat Stefan’s for speed, even tough I have inlined his call to the pad handler.

on secondsToHMS from theSecs
	set h to theSecs div hours
	set s to theSecs - h * hours
	set m to s div minutes
	set s to s - m * minutes
	return (text -2 thru -1 of (h + 100 as text) & ":" & text -2 thru -1 of (m + 100 as text) & ":" & (s + 100 as text))
end secondsToHMS

First of all div and mod are done using 1 instruction, div instruction, the divider and remainder are both returned. A distinction between mod en and div is made in higher level programming languages like C and upwards to make programming “easier”. Functions and methods can only return one value so there is an operator mod and div separately which are in fact the same but only returns different results.

Performance-wise there is indeed a difference but how much will you gain? Divisor instruction is considered expensive compared to logical instructions who can even take less than one cycle (there is headroom for a another instruction in the same pipeline and therefore not considered to require a whole cycle). Each line (byte code) that needs to be executed in AppleScript will require hundreds of more cycles of the processor than a single divisor instruction. I mean think about the number of assembler code is required for one single AppleScript line of code (thousands easily). The overhead of AppleScript itself is too large and the netto effect would only be negative.

Hello.

I agree fully. :slight_smile:

I have done the observation/conclusion that you write in the post above. This holds true for the mod operation, it can’t be outperformed by doing a subtraction and a multiplication. There are several other aspects to this, regarding “optimization” in AppleScript the number of statements, that made it a bad idea to reuse previous results of expressions. Which you cove, I also wonder, but I won’t speculate over it, if Stefan’s “one-line” function, really just does all its work on the “call-stack” since it just consists of a return statement.

Every machine, including virtual machines, has a call stack (stack machine) which uses stack pointers and stack frames to make recursive programming available. How AppleScript’s stackmachine exactly works I don’t know and is just speculation. But looking at other programming and scripting language designs in general I don’t think AppleScript is way off or technically can’t. Logically everything between an on and end will be a single stack frame and the blueprint of the handler is copied to the stack and executed when needed. But I don’t think a single or 100 commands inside an AppleScript handler would make a difference in the call stack. The stack frame would grow in size because the sequence of opcodes is obviously longer but it still would be a single item on the call stack.

I was actually thinking more in the lines of the mechanism of tail-recurson, where I believe compilers to optimize away the whole pushing and popping of stack frames, but just let the current stack grow - and shrink, thereby saving lots of calls.

The oppositive of that is of course to inline. I inled Stefan’s handler, with the pad handler, and the optimized version were around 1 second faster when I iterated over both 50000 times.

Enjoy your day.

My mistake :). Still I don’t think anything changes or better said it even applies here. Tail recursion will only apply if the last instruction/command of the subroutine will call to itself. Then the stack frame is not removed and re-allocated again but re-used, if the compiler recognizes tail recursion and optimizes it. I don’t think that applies to Stefan’s script because the the caller and callee are not the same routine.

However to be sure that AppleScript doesn’t optimize tail calls at all I have here a script that proves it:

global currentLevel

set currentLevel to 0
try
	recurse()
end try
set r1 to currentLevel

set currentLevel to 0
try
	tailRecurse()
end try
set r2 to currentLevel

return {r1, r2}

on recurse()
	set currentLevel to currentLevel + 1
	recurse()
	-- to avoud tail call
	void()
end recurse

on tailRecurse()
	set currentLevel to currentLevel + 1
	tailRecurse()
end tailRecurse

on void()
end void

As you can see both recursions break at the same level, the stack size. If tail calls were optimized in AppleScript the number of recursions where much higher for tail recursion, r2 would contain a much higher value before the stack overflow error or run infinite.

However even if it doesn’t apply to StefanK’s example, it’s still an interesting question. :slight_smile:

Hello DJ.

It is interesting to check out such stuff. :slight_smile: I did write in line of, meaning that the same technique could have been used, but that too was mere speculations. And now you have proved that it isn’t the case anyway. :slight_smile:

I am or I was, more into believing that the compiler copies in a handler into the compiled script where it is called, and then readresses all variable within that handler, (that once the compiler has compiled the code, it works more like a linkage editor), much have happend to AppleScript since I played with such ideas. (Tiger)

Since then I have learnt that it pays off to think that the Applescript compiler is as smart as a 70’s unoptimizing C-compiler. :slight_smile:

Hi everybody,

Very informative as usual. I’ll have to go back and read through all the posts. Been working on the timer and finally got all the logic down. Getting down to the split times, final time, and cleaning up the notification text. I missed a lot of things.

Thanks a lot,
kel

Hi everybody,

A lot of good info from everybody.

What I got is that it’s inconclusive. There are two ways to get the seconds. You can get the seconds through AppleScript or through Objective c with the interval. If you get it through the interval, then you need to convert with Objective C the interval into an integer. On the other hand, if you get the seconds through AppleScript, then you can directly convert through Applescript.

AppleScript is slower when converting seconds to hours, minutes and seconds. So overall what you lose is just the time for using the speed of Objective c when you need to coerce the interval into seconds. How much speed you gain by using AppleScript is unknown and hence it’s a tossup.

Lastly, whatever you are comfortible in using might be the best way to go and you need choose whatever method that is easiest for you. The differences in time are minute (less than a second). But is you want better accuracy, then you might use AppleScript Objective C.

Stefan’s script uses built in AppleScript functions and that is ok if you don’t need millisecond accuracy. That’s a far cry from seconds. That’s the main point I think.

Edited: and so, just get the hours, minutes, and seconds with AppleScript mod and rem if you’re just dealing with seconds. Although, I’m still thinking about that thousands times comment by DJ or was it hundred times.

Think I got it now and again,
kel

Hi Stefan,

And btw nice script. I didn’t know that is you’re writing a string you could start the concatenation with an integer. Let me look at that again!:smiley:

Thanks a lot,
kel

I see now. You did start with a string. Disregard.

Edited: nice puzzle!