Seconds to hours minutes and seconds

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!

Old post, but just wanted to propose a one-line version of Stefan’s solution:

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

on secondsToHMS from theSeconds
	tell theSeconds to tell {it div hours, it mod hours div minutes, it mod minutes} to return "" & ((item 1) div 10) & ((item 1) mod 10) & ":" & ((item 2) div 10) & ((item 2) mod 10) & ":" & ((item 3) div 10) & ((item 3) mod 10)
end secondsToHMS

Nice. :slight_smile: How about .

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

on secondsToHMS from theSeconds
	tell theSeconds to tell (it div 36000 as text) & (100000 + it div hours mod 10 * 10000 + it mod hours div minutes * 100 + it mod minutes as integer) to return text 1 thru -7 & character -5 & ":" & text -4 thru -3 & ":" & text -2 thru -1
end secondsToHMS

Nigel, your one-liner executes 2.5x faster than mine in a speed test. Sweet!

And these days we can actually fulfil Kel’s original request easily enough:

use AppleScript version "2.5" -- 10.11 or later to use AppleScript dates
use framework "Foundation"
use scripting additions

set startDate to current date
set endDate to startDate + 5240 -- whatever

set df to current application's NSDateComponentsFormatter's new()
df's setAllowedUnits:((current application's NSCalendarUnitHour) + (get current application's NSCalendarUnitMinute) + (get current application's NSCalendarUnitSecond))
df's setUnitsStyle:(current application's NSDateComponentsFormatterUnitsStyleFull)
(df's stringFromDate:startDate toDate:endDate) as text

Yvan should be happy with that :slight_smile:

I thought mine might be slightly faster, but based on theoretical considerations rather than side-by-side speed tests:

[format]
BM NG
10 integer math operations 11 integer math operations
6 implicit coercions to text 2 coercions to text (1 explicit, 1 implicit)
8 text concatentations 6 text concatenations
1 list creation 1 explicit number-to-integer coercion
6 list accesses 4 extractions from text[/format]

There’d be little to chose between them in a real-life situation. :slight_smile:

I was going to criticise the script for not returning the result in the same format, but having read kel’s opening monologue several times, I can’t see anything specifying either a format or three separate figures. :confused:

Interesting script, as always.

And I was expecting that :wink: But in trying to match that format, I hit a bug. As I read the docs, this should do it:

use AppleScript version "2.5" -- 10.11 or later to use AppleScript dates
use framework "Foundation"
use scripting additions

set startDate to current date
set endDate to startDate + 5240 -- whatever

set df to current application's NSDateComponentsFormatter's new()
df's setAllowedUnits:((current application's NSCalendarUnitHour) + (get current application's NSCalendarUnitMinute) + (get current application's NSCalendarUnitSecond))
df's setZeroFormattingBehavior:(current application's NSDateComponentsFormatterZeroFormattingBehaviorPad)
(df's stringFromDate:startDate toDate:endDate) as text

The .h file for NSDateComponentsFormatter says, in part:


But in fact it doesn’t pad the leading value, and instead returns “1:27:20”. (It pads the other values fine.) And that’s when I went back to see exactly what was asked for…

Hmm. The observed behaviour’s what described in the Xcode documentation. Seems a bit limited. :confused:

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

secondsToHMS from 5240 -- whatever

on secondsToHMS from theSeconds
	set |⌘| to current application
	set df to |⌘|'s class "NSDateComponentsFormatter"'s new()
	tell df to setAllowedUnits:((|⌘|'s NSCalendarUnitHour) + (get |⌘|'s NSCalendarUnitMinute) + (get |⌘|'s NSCalendarUnitSecond))
	tell df to setZeroFormattingBehavior:(current application's NSDateComponentsFormatterZeroFormattingBehaviorPad)
	return ((df's stringFromTimeInterval:(theSeconds))'s stringByReplacingOccurrencesOfString:("^(?=[0-9]:)") withString:("0") options:(|⌘|'s NSRegularExpressionSearch) range:({0, 2})) as text
end secondsToHMS

Apologies for prolonging this thread, but here is one more one-line version of Stefan’s solution for those looking for a pure Applescript solution that perhaps wins the simplicity contest (but stills comes in second place to Nigel’s in terms of execution speed, which is about 1.4 x faster):

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

on secondsToHMS from theSeconds
	tell theSeconds to tell {"0" & it div hours, "0" & it mod hours div minutes, "0" & it mod minutes} to return item 1's text -2 thru -1 & ":" & item 2's text -2 thru -1 & ":" & item 3's text -2 thru -1
end secondsToHMS

I just open this thread today.
I was wondering what meant “Yvan should be happy with that” in message #28
I understood when I ran the script displaying :“1 heure, 27 minutes et 20 secondes”

I would not guessed because there is no reference to locale in the code.

I will put it in my library although I never use this format.

I would use the one in message #31.

The one posted by Nigel in message #32 gives the same result but I’m not fond of RegularExpression :wink: :rolleyes:

Yvan KOENIG running Sierra 10.12.4 in French (VALLAURIS, France) mardi 18 avril 2017 12:16:15

Here’s a slightly faster one, but it’s only good up to 359,999,999 seconds (595 weeks 1 days 15 hours 59 minutes 59 seconds) in El Capitan:

secondsToHMS from 0 --> "00:00:00"
secondsToHMS from 5240 --> "01:27:20"
secondsToHMS from 595 * weeks + 1 * days + 15 * hours + 59 * minutes + 59 --> "99999:59:59"

on secondsToHMS from theSeconds
	tell theSeconds to tell (it div hours / 10 + it mod hours div minutes / 10000 + it mod minutes / 1000000 + 0.0100004) as text to return text 1 thru -9 & character -7 & ":" & text -5 thru -4 & ":" & text -3 thru -2
end secondsToHMS