Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Format number of seconds to days, hours, minutes, seconds


  • Please log in to reply
32 replies to this topic
PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
I needed this for AC/Battery status, but I thought it would be nice to give it an independent life. I added days, probably not necessary for a battery load time...

I searched if somebody else has done a similar work, I found Date/Time convert to String (e.g. Seconds > 1:09:15.123) but since the format of output is different, I think I can go on.

/*
// Take a number of seconds, and format it in a readable
// way, like 11 days 14 hours 3 minutes 21 seconds.
// If a number is zero, skip it: 2 hours 3 seconds.
// Put correct plural: 1 hour 1 minute.
*/
GetFormatedTime(_seconds)
{
	local d, h, m, s, t

	d := _seconds // 86400
	_seconds -= d * 86400
	h := _seconds // 3600
	_seconds -= h * 3600
	m := _seconds // 60
	s := _seconds - m * 60
	If (d > 1)
		t := d . " days"
	Else If (d = 1)
		t := "1 day"
	If (t != "" and h + m + s > 0)
		t := t . " "
	If (h > 1)
		t := t . h . " hours"
	Else If (h = 1)
		t := t . "1 hour"
	If (t != "" and m + s > 0)
		t := t . " "
	If (m > 1)
		t := t . m . " minutes"
	Else If (m = 1)
		t := t . "1 minute"
	If (t != "" and s > 0)
		t := t . " "
	If (s > 1)
		t := t . s . " seconds"
	Else If (s = 1)
		t := t . "1 second"
	Else If (t = "")
		t := "0 seconds"

	Return t
}
Test:

MsgBox %
( Join
 GetFormatedTime(11001001) . "`n" .
 GetFormatedTime(1001001) . "`n" .
 GetFormatedTime(101001) . "`n" .
 GetFormatedTime(11001) . "`n" .
 GetFormatedTime(3661) . "`n" .
 GetFormatedTime(1001) . "`n" .
 GetFormatedTime(100) . "`n" .
 GetFormatedTime(10) . "`n" .
 GetFormatedTime(1) . "`n" .
 GetFormatedTime(0) . "`n" .
 ""
)

Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
There is a shorter solution posted here and here. Just replace A_TickCount/1000 with the seconds.

If you want "1 second" instead of "1 seconds", StringReplace.

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
You missed the point. It is long because it handles special cases, ie. it won't display 1 hours 0 minutes 10 seconds but 1 hour 10 seconds.
I prefer this format, but your solution is better for a more "regular" format, I suppose.
Choice is good, as always. :-)
Thanks for reminding your code, I wouldn't have searched inside a Ask for Help topic...

BTW, using StringReplace here doesn't seem to offer a big advantage over a test... Even more if I must replace 1 seconds and 0 seconds! Gaining a few lines here isn't important for me.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

Gaining a few lines here isn't important for me.

You might be right, but the shorter code could be easier to maintain. This is what I mean:
GetFormatedTime(_seconds) {

   DH = day|hour|minute|second

   T = 2000

   T += _seconds,Seconds

   FormatTime S, %T%, H 'hours' m 'minutes' s 'seconds'

   FormatTime T, %T%, YDay

   T := " " T-1 " days " S

   Loop Parse, DH, |

      StringReplace T, T, %A_Space%0 %A_LoopField%s

   Loop Parse, DH, |

      StringReplace T, T, %A_Space%1 %A_LoopField%s, %A_Space%1 %A_LoopField%

   IfEqual T,, Return " 0 seconds"

   Return T

}


polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012
This is less than half the size and does exactly the same thing:
gft(t4) {
	loop 3 {
		x := (60 ** (1 + (a_index < 3))) * ((a_index = 1) * 24 + (a_index != 1))
		t%a_index% := t4 // x
		t4 -= t%a_index% * x
	}
	w = day.hour.minute.second
	stringsplit w, w, .
	loop 4
		if t%a_index% or a_index = 4
			m := m . t%a_index% . " " . w%a_index% . Chr((t%a_index% != 1) * 115) . " "
	return m
}

You can make it even shorter by replacing the first loop with:
t1 := t4 // 86400
	t4 -= t1 * 86400
	t2 := t4 // 3600
	t4 -= t2 * 3600
	t3 := t4 // 60
	t4 -= t3 * 60

Edit: I did not see Laszlo's post... but this is still shorter ;)

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

but this is still shorter ;)

True. Titan is the champ!

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
This code
w = day.hour.minute.second 

   stringsplit w, w, . 

   loop 4 

      if t%a_index% or a_index = 4 

         m := m . t%a_index% . " " . w%a_index% . Chr((t%a_index% != 1) * 115) . " " 

could be shortened to
w = day.hour.minute.second 

   loop, parse, w, .

      if t%a_index% or a_index = 4 

         m := m . t%a_index% . " " . %A_LoopField% . Chr((t%a_index% != 1) * 115) . " " 


Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
Laszlo, why do you have this line "T = 2000"? With this line T will never be empty, thus never "0 seconds".
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005

This code [...] could be shortened to [...]

Well, it doesn't work...
I appreciate the compactness of Titan's code, but frankly, "the shorter code could be easier to maintain", I doubt it... :-)
Let's take an average programmer needing to do a change in the code.
How much time will he take to understand what my code does, and to understand what Titan's code does? The gft(t4) function signature won't help either...
Next discussion on obfuscated code in AutoHotkey, I will refer to this topic... :-D Don't take it bad, Titan, your efforts are really appreciated, and as I wrote, choice is good. No doubt Goyyah will choose your solution! ;-)

Laszlo, I would test the special case of 0 value on the first line of the function. And I admit your solution is still quite readable and using well AutoHotkey's resources (built-in calculations). Probably slower, doing operations to undo them later...
Let's skip the loop, it would be faster... :-D
GetFormatedTime(_seconds)
{
	local t, timeString

	If _seconds = 0
		Return "0 seconds"
	t := 2000	; Arbitrary date (year)
	t += _seconds, Seconds
	FormatTime timeString, %t%, H 'hours' m 'minutes' s 'seconds'
	FormatTime t, %t%, YDay
	timeString := RegExReplace((t - 1) . " days " . timeString, "\b0 (\w+)\b ?")
	timeString := RegExReplace(timeString, "\b1 (\w+?)s\b", "1 $1")
	Return timeString
}
Of course, you can shorten it of at least 4 lines... But I keep my style. ;-)
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012

True. Titan is the champ!

w00t! you made my day :)

could be shortened to ... loop, parse, w, .

Thanks toralf, I must've missed that because I wrote the w/stringsplit bit right towards the end.

I appreciate the compactness of Titan's code, but frankly, "the shorter code could be easier to maintain", I doubt it...

My code is easier to maintain, you just need to change the loop number (or use the parse method like toralf suggested) and add words to the list, e.g. 'years.months. ... .miliseconds'. If you understand the maths, which is simply (60 ** 2,2,1) * 1,1,24 = 60,3600,86400, there should really be no problem.

How much time will he take to understand what my code does

I was tempted to put comments but that would defeat the objective of posting a smaller variant :?
btw. I don't see this as a difficult script anyway, if you want a challenge try to understand how Laszlo's tea algorithm works without wiking (been there done that before you ask).

No doubt Goyyah will choose your solution!

I'm sure Goyyah will prefer Laszlo's code, it's more readable after all.

Next discussion on obfuscated code in AutoHotkey, I will refer to this topic...

Maths and arrays are obfuscated? I don't know what to say...

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005

Maths and arrays are obfuscated? I don't know what to say...

Code like Chr((t%a_index% != 1) * 115) is typical of obfuscated programs... ;-) :-P
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012

Code like Chr((t%a_index% != 1) * 115) is typical of obfuscated programs...

No that's just a mathematical (or an inline-if) way to determine if the word should be plural. (t%a_index% != 1) is 0 when the quantity is 1 and 0 * 115 = 0 = Asc: null, otherwise it would be 1 * 115 = 115 = Asc: s. English plurals are relatively simple, French is another story.

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
I wanted this function! :shock:

Terrific contribution! I am/was very much interested in writing such a function & was postponing it ( I am glad about it now! ). If I had written one, my logic would have been much similar to PhiLho's except for the coding style:

If (d > 1) 
      t := d . " days" 
   Else If (d = 1) 
      t := "1 day"

The above would have been coded shorter ( & slower & ugly & unreadable ) like:

IfGreater,d,0, SetEnv,t,% d . " days"
IfEqual,d,1, StringTrimRight,t,t,1

Since I understand the subject well, I have chosen to use Titan's code with the URL to this topic included as a comment!

I feel so lucky having the choice of choosing between code written by PhiLho/Laszlo/Titan. :D

Best Regards, :)
kWo4Lk1.png

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
Titan, I understood how it works, but obfuscated programs love this kind of shortcut/purpose hidding... :-)
It isn't depreciative, people writing obfuscated code are often very clever and of high programming level.

Goyyah, "The above would have been coded shorter ( & slower & ugly & unreadable )", you are learning... :-) ;-) (not necessarily slower, though).
"I have chosen to use Titan's code". Uh, not! :-D
Just joking, of course, I knew it would be your choice...
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

Laszlo, why do you have this line "T = 2000"? With this line T will never be empty, thus never "0 seconds".

T must contain a valid date, otherwise the next line will use today. 2000 is a shorthand for 20000101000000, midnight of January 1st. If you add seconds to it, the current date/time in that year is the formatted version of the seconds added. Adding 0 leaves T as 20000101000000, that is, the seconds, minutes, hours will be 0, day = 1, so we need day-1 in the return value.

Your simplification has an extra pair of percent sign around A_LoopField. Remove it:
loop, parse, w, .
      if t%a_index% or a_index = 4
         m := m  t%a_index%  " "  A_LoopField  Chr((t%a_index% != 1) * 115)  " "