[SMF] Short My Function - Seconds to string

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

[SMF] Short My Function - Seconds to string

22 Mar 2017, 09:03

Hey all,

my function do what I want. But is there any shorter way? challenge :D

Script / Function

Code: Select all

; GLOBAL SETTINGS ===================================================================

#NoEnv
#SingleInstance Force
SetBatchLines -1

; ===================================================================================

TimeArr := [59, 60, 61, 3599, 3600, 3601, 86399, 86400, 86401]

for i, v in TimeArr
    GetTime .= CalcTime(TimeArr[i]) "`n"

; GUI ===============================================================================

Gui, Margin, 5, 5
Gui, Font,, Courier New
Gui, Add, Edit, xm ym w200 h200 0x802, % GetTime
Gui, Show, AutoSize
return

; FUNCTIONS =========================================================================

CalcTime(sec)
{
    s := sec
    if (sec >= 86400)
    {
        d := floor(s / 86400)
        s := mod(s, 86400)
        o .= d "d "
    }
    if (sec >= 3600)
    {
        h := floor(s / 3600)
        s := mod(s, 3600)
        o .= (h < 9 ? " " h : h) "h "
    }
    if (sec >= 60)
    {
        m := floor(s / 60)
        s := mod(s, 60)
        o .= (m < 9 ? " " m : m) "m "
    }
    if (sec >= 1)
    {
        o .= (s < 9 ? " " s : s) "s"
    }
    return o
}

/*
CalcTimeShort(sec)
{
    s := sec
    if (sec >= 86400)
        d := floor(s / 86400), s := mod(s, 86400), o .= d "d "
    if (sec >= 3600)
        h := floor(s / 3600), s := mod(s, 3600), o .= (h < 9 ? " " h : h) "h "
    if (sec >= 60)
        m := floor(s / 60), s := mod(s, 60), o .= (m < 9 ? " " m : m) "m "
    if (sec >= 1)
        o .= (s < 9 ? " " s : s) "s"
    return o
}
*/

; EXIT ==============================================================================

GuiClose:
GuiEscape:
ExitApp

; ===================================================================================
Output:

Code: Select all

           59s    ;    59
        1m  0s    ;    60
        1m  1s    ;    61
       59m 59s    ;  3599
    1h  0m  0s    ;  3600
    1h  0m  1s    ;  3601
   23h 59m 59s    ; 86399
1d  0h  0m  0s    ; 86400
1d  0h  0m  1s    ; 86401
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: short my function

22 Mar 2017, 09:47

Spoiler
Spoiler
Cool challenge.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
garry
Posts: 3738
Joined: 22 Dec 2013, 12:50

Re: [SMF] Short My Function - Seconds to string

22 Mar 2017, 10:09

thank you , I had this (msec to > hr min sec msec )

Code: Select all

;timex millisecondx to hr-min-sec-msec
timex:=70651
;timex:=(ABS(timex))  ;- remove  minus -
;timex:=floor(timex)  ;- without dot   .

Hours        := SubStr(0 Floor(timex / 3600000), -1)
Minutes      := SubStr(0 Floor((timex - Hours * 3600000) / 60000), -1)
Seconds      := SubStr(0 Floor((timex - Hours * 3600000 - Minutes * 60000) / 1000), -1)
Milliseconds := SubStr(0 timex - Hours * 3600000 - Minutes * 60000 - Seconds * 1000, -2)
MsgBox, % Hours ":" Minutes ":" Seconds ":" Milliseconds
return
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [SMF] Short My Function - Seconds to string

22 Mar 2017, 10:17

Modified from the help file. Only tested with your test array. It differs only in spacing as far as my lazy eyes can tell :geek:

Code: Select all

CalcTime(sec) {
    t:=19990101
    t+=sec, seconds
    FormatTime, t, % t, %  "H:m:s"
	t:=(sec>=3600*24 ? sec//(3600*24) . "d ":"") . t
    for k, v in ["h ","m "]
		t:=StrReplace(t,":",v,,1), t:=RegExReplace(t,"^0" . v)
	return t . "s"
}
just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [SMF] Short My Function - Seconds to string

22 Mar 2017, 10:21

Code: Select all

CalcTime(sec) {
   s := (d := sec // 86400) ? Mod(sec, 86400) : sec
   f := (sec < 60) ? "s's'" : (sec < 3600) ? "m'm 's's'" : "H'h 'm'm 's's'"
   t := A_YYYY
   t += s, S
   FormatTime, r, %t%, %f%
   Return (d ? d . "d " : "") . r
}
Are you sure about if (sec >= 1)
Rohwedder
Posts: 7551
Joined: 04 Jun 2014, 08:33
Location: Germany

Re: [SMF] Short My Function - Seconds to string

22 Mar 2017, 10:51

Hallo,
my version:

Code: Select all

CalcTime(sec) {
		t = 20000101
		t += %Sec%, seconds
		FormatTime, t, %t%, H'h	'm'm	's's'
		t := Sec//86400 "d	" t
		Loop, 3
			t:= RegExReplace(t,"^0\D	")
		Return t
	}
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [SMF] Short My Function - Seconds to string

22 Mar 2017, 12:22

Rohwedder wrote:Hallo,
my version:

Code: Select all

CalcTime(sec) {
		t = 20000101
		t += %Sec%, seconds
		FormatTime, t, %t%, H'h	'm'm	's's'
		t := Sec//86400 "d	" t
		Loop, 3
			t:= RegExReplace(t,"^0\D	")
		Return t
	}
I like this one :thumbup:
just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [SMF] Short My Function - Seconds to string

22 Mar 2017, 12:23

Hi Rohwedder,

shortened your version:

Code: Select all

CalcTime(sec) {
   t := 2000
   t += %sec%, s
   FormatTime, t, %t%, H'h 'm'm 's's'
   Return RegExReplace((Sec // 86400) . "d " . t, "^(0\D ){1,3}")
}
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [SMF] Short My Function - Seconds to string

22 Mar 2017, 12:34

just me wrote:

Code: Select all

 "^(0\D ){1,3}
I wouldn't have thought of that, i.e., the combination of ^ and {min,max}. :thumbup:
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: [SMF] Short My Function - Seconds to string

22 Mar 2017, 13:50

you can shorten that further?

Code: Select all

"^(0\D )*"
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: [SMF] Short My Function - Seconds to string

22 Mar 2017, 14:34

Don't forget those awkward extra spaces, which can happen even at the start of the string, when h or m or s are <= 9.

Code: Select all

t := "1d 1h 1m 1s"
MsgBox % RegExReplace(t, "(^| )\d[hms]", " $0")

;59s
; 1m  0s
; 1m  1s
;59m 59s
; 1h  0m  0s
; 1h  0m  1s
;23h 59m 59s
;1d  0h  0m  0s
;1d  0h  0m  1s
Btw to the OP:
Are you sure about that? <?

Code: Select all

;        o .= (h < 9 ? " " h : h) "h "
;        o .= (m < 9 ? " " m : m) "m "
;        o .= (s < 9 ? " " s : s) "s"
MsgBox % Clipboard := CalcTime(119349) ;1d 9h 9m 9s
MsgBox % Clipboard := CalcTime(115688) ;1d  8h  8m  8s
[600th post ftw]
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: [SMF] Short My Function - Seconds to string

23 Mar 2017, 03:24

Thanks for all Input =)
Not sure why I forgot this function ^^

GetDurationFormat function

Code: Select all

; GLOBAL SETTINGS ===================================================================

#NoEnv
#SingleInstance Force
SetBatchLines -1

; ===================================================================================

TimeArr := [59, 60, 61, 3599, 3600, 3601, 86399, 86400, 86401]

for i, v in TimeArr
    GetTime .= GetDurationFormat(TimeArr[i]) "`n"

; GUI ===============================================================================

Gui, Margin, 5, 5
Gui, Font,, Courier New
Gui, Add, Edit, xm ym w200 h200 0x802, % GetTime
Gui, Show, AutoSize
return

; FUNCTIONS =========================================================================

GetDurationFormat(sec)
{
    format := (sec >= 86400) ? "d'd ' hh'h ' mm'm ' ss's'" : (sec >= 3600) ? "h'h ' mm'm ' ss's'" : (sec >= 60) ? "m'm ' ss's'" : "s's'"
    if !(size := DllCall("GetDurationFormat", "uint", 0x0800, "uint", 0, "ptr", 0, "int64", sec * 10000000, "wstr", format, "ptr", buf, "int", 0))
        throw Exception("GetDurationFormat", -1)
    VarSetCapacity(buf, size << 1, 0)
    if !(DllCall("GetDurationFormat", "uint", 0x0800, "uint", 0, "ptr", 0, "int64", sec * 10000000, "wstr", format, "wstr", buf, "int", size))
        throw Exception("GetDurationFormat", -1)
    return buf
}

StrFromTimeInterval(sec)
{
    size := VarSetCapacity(buf, 256, 0)
    DllCall("shlwapi.dll\StrFromTimeInterval", "str", buf, "uint", size, "uint", sec * 1000, "int", 6)
    return buf
}

; EXIT ==============================================================================

GuiClose:
GuiEscape:
ExitApp

; ===================================================================================
Output is a bit different from what I want (0 instead of of space), but its ok

Code: Select all

           59s    ;    59
        1m 00s    ;    60
        1m 01s    ;    61
       59m 59s    ;  3599
    1h 00m 00s    ;  3600
    1h 00m 01s    ;  3601
   23h 59m 59s    ; 86399
1d 00h 00m 00s    ; 86400
1d 00h 00m 01s    ; 86401
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [SMF] Short My Function - Seconds to string

23 Mar 2017, 03:50

It's not the 'shortest' one! ;)
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: [SMF] Short My Function - Seconds to string

23 Mar 2017, 03:57

Shorter :P

Code: Select all

GetDurationFormat2(s) {
    f:=(s>=86400)?"d'd ' hh'h ' mm'm ' ss's'":(s>=3600)?"h'h ' mm'm ' ss's'":(s>=60)?"m'm ' ss's'":"s's'"
    VarSetCapacity(b,256),DllCall("GetDurationFormat","uint",2048,"uint",0,"ptr",0,"int64",s*10000000,"wstr",f,"wstr",b,"int",256)
    return b
}

/*
GetDurationFormat(sec)
{
    format := (sec >= 86400) ? "d'd ' hh'h ' mm'm ' ss's'" : (sec >= 3600) ? "h'h ' mm'm ' ss's'" : (sec >= 60) ? "m'm ' ss's'" : "s's'"
    if !(size := DllCall("GetDurationFormat", "uint", 0x0800, "uint", 0, "ptr", 0, "int64", sec * 10000000, "wstr", format, "ptr", buf, "int", 0))
        throw Exception("GetDurationFormat", -1)
    VarSetCapacity(buf, size << 1, 0)
    if !(DllCall("GetDurationFormat", "uint", 0x0800, "uint", 0, "ptr", 0, "int64", sec * 10000000, "wstr", format, "wstr", buf, "int", size))
        throw Exception("GetDurationFormat", -1)
    return buf
}
*/
But pretty sure, one of the fastes


Found some cryptic stuff here (http://www.autohotkey.com/board/topic/1 ... s/?p=87852)
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: [SMF] Short My Function - Seconds to string

23 Mar 2017, 04:06

Re. 'Output is a bit different from what I want'. Never settle for less than the best:

Code: Select all

q:: ;add s p a c e because it's a e s t h e t i c
t = ;continuation section
(Join`r`n

           59s    ;    59
        1m 00s    ;    60
        1m 01s    ;    61
       59m 59s    ;  3599
    1h 00m 00s    ;  3600
    1h 00m 01s    ;  3601
   23h 59m 59s    ; 86399
1d 00h 00m 00s    ; 86400
1d 00h 00m 01s    ; 86401
)
MsgBox % Clipboard := RegExReplace(t, "(^| )0(\d[hms])", "$1 $2")
Return

;           59s    ;    59
;        1m  0s    ;    60
;        1m  1s    ;    61
;       59m 59s    ;  3599
;    1h  0m  0s    ;  3600
;    1h  0m  1s    ;  3601
;   23h 59m 59s    ; 86399
;1d  0h  0m  0s    ; 86400
;1d  0h  0m  1s    ; 86401
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [SMF] Short My Function - Seconds to string

23 Mar 2017, 04:48

Multi-statements aren't really 'shorter' for me. But now we're equal (I overlooked the extra spaces):

Code: Select all

CalcTime(sec) {
   t := 2000
   t += %sec%, s
   FormatTime, t, %t%, HH'h 'mm'm 'ss's'
   Return RegExReplace((Sec // 86400) . "d " . RegExReplace(t, "0(\d)", " $1"), "^(0\D +){1,3}")
}
;)
4GForce
Posts: 553
Joined: 25 Jan 2017, 03:18
Contact:

Re: [SMF] Short My Function - Seconds to string

23 Mar 2017, 09:09

jNizM wrote: But is there any shorter way?
I'll post this before reading the rest of the post ...

Code: Select all

CalcTime(sec) {
	timestamp := "2017"
	timestamp += sec, Seconds
	format .= (sec >= 3600) ? "HH'h'" : ""
	format .= (sec >= 60 ) ? "mm'm'" : ""
	FormatTime hms, % timestamp, % format . "ss's'"
	Return (sec >= 86400) ? floor(sec/86400) . "d" . hms : hms
}
Close enough ?

Edit:
jNizM wrote:But pretty sure, one of the fastes
DllCall faster than FormatTime ?
This makes me wonder ... is FormatTime performing a DllCall in the back end ?
Cause I would've thought math operation performed by FormatTime would be faster than a DllCall :?:

Edit2:
Confirmed, yours is about 14% faster than mine :(
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: [SMF] Short My Function - Seconds to string

23 Mar 2017, 10:04

Just benchmark it. But I used a single DllCall and FormatTime in the background is more than just a single call, but should be fast enough for the most tasks.

A pure mathematical function (with mod / floor /... maybe some bithacks or magic numbers if possible) would be nice too see (but without FormatTime / Env... / SubStr / RegEx...)
like this (but with the space integrated)

Code: Select all

CalcTime(s)
{
    d := (s >= 86400) ?     s // 86400      "d " : ""
    h := (s >=  3600) ? mod(s //  3600, 60) "h " : ""
    m := (s >=    60) ? mod(s //    60, 60) "m " : ""
    s :=                mod(s,          60) "s "
    return d h m s
}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
just me
Posts: 9423
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [SMF] Short My Function - Seconds to string

23 Mar 2017, 11:02

A modified version of jeeswg's function:

Code: Select all

CalcTime(sec) {
   Return (d := sec // 86400) ? d . Format("d {:2}h {:2}m {:2}s", Mod(sec, 86400) // 3600, Mod(sec, 3600) // 60, Mod(sec, 60))
        : (h := Mod(sec, 86400) // 3600) ? h . Format("h {:2}m {:2}s", Mod(sec, 3600) // 60, Mod(sec, 60))
        : (m := Mod(sec, 3600) // 60) ? m . Format("m {:2}s", Mod(sec, 60))
        : sec . "s"
}
4GForce
Posts: 553
Joined: 25 Jan 2017, 03:18
Contact:

Re: [SMF] Short My Function - Seconds to string

23 Mar 2017, 16:18

jNizM wrote:A pure mathematical function (with mod / floor /... maybe some bithacks or magic numbers if possible) would be nice too see (but without FormatTime / Env... / SubStr / RegEx...)
Is there a wrong answer ?

Code: Select all

CalcTime(sec) {
	static values := [{symbol: "d", val: 86400, modulus: 365}, {symbol: "h", val: 3600, modulus: 24}, {symbol: "m", val: 60, modulus: 60}, {symbol: "s", val: 1, modulus: 60}]
	for i, v in values {
		result .= " " . ((sec >= v.val) ? (0 != x := Mod(sec // v.val, v.modulus)) ? x > 9 ? x . v.symbol : " " . x . v.symbol : " 0" . v.symbol : "")
	}
	Return result
}
Benchmarks are looking good ... vs jNizM's DllCall and vs just me's modified jeeswg's function ... didn't take the time to test all the others.

Edit: Slight upgrade ( I added the extra space at last second to match your output without thinking about the processing impact ... so pushing it beyond the 1st condition should be at least a nanosecond faster )

Code: Select all

		result .= ((sec >= v.val) ? " " . (0 != x := Mod(sec // v.val, v.modulus)) ? x > 9 ? x . v.symbol : " " . x . v.symbol : " 0" . v.symbol : "")

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: marypoppins_1, Rohwedder, Spawnova and 152 guests