Thread Tools Display Modes
11-20-10, 07:57 AM   #1
gorillaz09
A Murloc Raider
Join Date: Nov 2010
Posts: 8
Time formatting noob question

Hi, let's say I have the total seconds 150 and I want to display it as minutes and seconds, if I divide by 60 I get the minutes but how do I get the remaining seconds?
  Reply With Quote
11-20-10, 08:05 AM   #2
Humbedooh
A Defias Bandit
AddOn Author - Click to view addons
Join Date: Nov 2010
Posts: 3
Originally Posted by gorillaz09 View Post
Hi, let's say I have the total seconds 150 and I want to display it as minutes and seconds, if I divide by 60 I get the minutes but how do I get the remaining seconds?
One example:
Code:
local seconds = 150;
local m,s = math.floor(seconds/60), math.fmod(seconds, 60) 
print(m,s) -- prints 2, 30.
Another example:
Code:
local seconds = 150; -- for educational purposes
local duration =  date("%M:%S", seconds) -- %M:%S means "Minutes:Seconds"
print(duration) -- prints 02:30

Last edited by Humbedooh : 11-20-10 at 08:09 AM.
  Reply With Quote
11-20-10, 09:08 AM   #3
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
And another one

Code:
print(string.format(SecondsToTime(150)))
prints '2 Min 30 Sec'
  Reply With Quote
11-20-10, 05:02 PM   #4
gorillaz09
A Murloc Raider
Join Date: Nov 2010
Posts: 8
Thanks a lot!
  Reply With Quote
11-20-10, 09:03 PM   #5
Ketho
A Pyroguard Emberseer
 
Ketho's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,026
And another one too. This code is very customizable, but very bulky though.
For example:
  • show smaller significant time values like [days + hours + minutes]
  • change strings to your liking: e.g. different language / L["minutes"], abbreviated, singular/plural grammar
Code:
-- Upvalues
local floor = floor -- math.floor
local mod = mod -- math.fmod

function MyAddon_TimetoString(time)
	local seconds = mod(floor(time),60)
	local minutes = mod(floor(time/60),60)
	local hours = mod(floor(time/3600),24)
	local days = floor(time/86400)
	if time >= 0 and time < 60 then
		if seconds == 1 then return seconds.." second"
		else return seconds.." seconds" end
	elseif time >= 60 and time < 3600 then
		if minutes >= 2 and seconds >= 2 then return minutes.." minutes, "..seconds.." seconds"
		elseif minutes == 1 and seconds >= 2 then return minutes.." minute, "..seconds.." seconds"
		elseif minutes >= 2 and seconds == 1 then return minutes.." minutes, "..seconds.." second"
		elseif minutes == 1 and seconds == 1 then return minutes.." minute, "..seconds.." second"
		elseif minutes == 1 and seconds == 0 then return minutes.." minute"
		elseif minutes >= 2 and seconds == 0 then return minutes.." minutes" end
	elseif time >= 3600 and time < 86400 then
		if hours >= 2 and minutes >= 2 then return hours.." hours, "..minutes.." minutes"
		elseif hours == 1 and minutes >= 2 then return hours.." hour, "..minutes.." minutes"
		elseif hours >= 2 and minutes == 1 then return hours.." hours, "..minutes.." minute"
		elseif hours == 1 and minutes == 1 then return hours.." hour, "..minutes.." minute"
		elseif hours == 1 and minutes == 0 then return hours.." hour"
		elseif hours >= 2 and minutes == 0 then return hours.." hours" end
	elseif time >= 86400 then
		if days >= 2 and hours >= 2 then return days.." days, "..hours.." hours"
		elseif days == 1 and hours >= 2 then return days.." day, "..hours.." hours"
		elseif days >= 2 and hours == 1 then return days.." days, "..hours.." hour"
		elseif days == 1 and hours == 1 then return days.." day, "..hours.." hour"
		elseif days == 1 and hours == 0 then return days.." day"
		elseif days >= 2 and hours == 0 then return days.." days" end
	end
end

Last edited by Ketho : 11-20-10 at 09:24 PM.
  Reply With Quote
11-20-10, 09:49 PM   #6
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
That's a bit too much work for the singular / plural form Ketho

Code:
string.format("%d |4"..L["minute"]..":"..L["minutes"]..";",minutes)
will do the same without all those if-elseif chains
  Reply With Quote
11-20-10, 10:07 PM   #7
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,326
Originally Posted by gorillaz09 View Post
Hi, let's say I have the total seconds 150 and I want to display it as minutes and seconds, if I divide by 60 I get the minutes but how do I get the remaining seconds?
To add another answer to the initial question and explain the function, you use a mathematical operator called Modulus. This returns the remainder left after a division. Lua allows access to this function through the math library as math.fmod(). More recently, Lua also registers this function for the operator '%'. The WoW API also has a link to it in the global scope, mod().

The following examples are 3 ways you can get the result of a Modulus operation, the first is preferred.
Code:
150%60
mod(150,60)
math.mod(150,60)


Originally Posted by Dridzt View Post
Code:
print(string.format(SecondsToTime(150)))
string.format() doesn't need to be called in this situation and is bad practice to do on a string as the sole argument. Errors are likely to occur when the string contains a formatting identifier. The function will expect additional arguments to insert in for each identifier and will throw a "Bad argument to function" error.



Originally Posted by Ketho View Post
  • change strings to your liking: e.g. different language / L["minutes"], abbreviated, singular/plural grammar
The global table L doesn't actually exist in the Lua core or in the WoW API, it has to be defined in an addon.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 11-20-10 at 10:15 PM.
  Reply With Quote
11-20-10, 10:37 PM   #8
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
I was actually looking at the SecondsToTimeAbbrev() - which returns a format string and a number - function and I pasted the wrong one.

However string.format is just redundant in the example above, it will never cause an error in this specific case.

Last edited by Dridzt : 11-20-10 at 10:39 PM. Reason: syntax
  Reply With Quote
11-20-10, 10:40 PM   #9
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,326
Originally Posted by Dridzt View Post
That might be so if SecondsToTime() was returning just a string.
I don't post examples on public forums without running them in-game.
Maybe you should try it
My in-game dump function reports the following
Processing: SecondsToTime(150)
Argument Length: 1
[1]=(string) 2 Min 30 Sec
Note: This dump function was written to support multiple returns



Also, here's the source code to SecondsToTime() as defined in UIParent.lua
lua Code:
  1. function SecondsToTime(seconds, noSeconds, notAbbreviated, maxCount)
  2.     local time = "";
  3.     local count = 0;
  4.     local tempTime;
  5.     seconds = floor(seconds);
  6.     maxCount = maxCount or 2;
  7.     if ( seconds >= 86400  ) then
  8.         tempTime = floor(seconds / 86400);
  9.         if ( notAbbreviated ) then
  10.             time = format(D_DAYS,tempTime);
  11.         else
  12.             time = format(DAYS_ABBR,tempTime);
  13.         end
  14.         seconds = mod(seconds, 86400);
  15.         count = count + 1;
  16.     end
  17.     if ( seconds >= 3600  ) then
  18.         if ( time ~= "" ) then
  19.             time = time..TIME_UNIT_DELIMITER;
  20.         end
  21.         tempTime = floor(seconds / 3600);
  22.         if ( notAbbreviated ) then
  23.             time = time..format(D_HOURS, tempTime);
  24.         else
  25.             time = time..format(HOURS_ABBR, tempTime);
  26.         end
  27.         seconds = mod(seconds, 3600);
  28.         count = count + 1;
  29.     end
  30.     if ( count < maxCount and seconds >= 60  ) then
  31.         if ( time ~= "" ) then
  32.             time = time..TIME_UNIT_DELIMITER;
  33.         end
  34.         tempTime = floor(seconds / 60);
  35.         if ( notAbbreviated ) then
  36.             time = time..format(D_MINUTES, tempTime);
  37.         else
  38.             time = time..format(MINUTES_ABBR, tempTime);
  39.         end
  40.         seconds = mod(seconds, 60);
  41.         count = count + 1;
  42.     end
  43.     if ( count < maxCount and seconds > 0 and not noSeconds ) then
  44.         if ( time ~= "" ) then
  45.             time = time..TIME_UNIT_DELIMITER;
  46.         end
  47.         seconds = format("%d", seconds);
  48.         if ( notAbbreviated ) then
  49.             time = time..format(D_SECONDS, seconds);
  50.         else
  51.             time = time..format(SECONDS_ABBR, seconds);
  52.         end
  53.     end
  54.     return time;
  55. end
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
11-20-10, 10:46 PM   #10
Ketho
A Pyroguard Emberseer
 
Ketho's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,026
Originally Posted by Dridzt View Post
Code:
string.format("%d |4"..L["minute"]..":"..L["minutes"]..";",minutes)
will do the same without all those if-elseif chains
Wow! I will definitely try that out! O.o

Code:
D_MINUTES = "%d |4Minute:Minutes;";
MINUTES = "|4Minute:Minutes;";
Actually I tried using the global variables from GlobalStrings.lua before..
But it failed in a SendChatMessage(), I think, due to UI escape sequencing
I still have/had no clue what %d is or how it works, but I think your code will explain it now

Originally Posted by SDPhantom View Post
The global table L doesn't actually exist in the Lua core or in the WoW API, it has to be defined in an addon.
Sorry, I should've mentioned AceLocale with it too ><

Edit:
My "debugged" /dump returned:
"2 |4Min:Min; 30 |4Sec:Sec;"

Last edited by Ketho : 11-20-10 at 10:51 PM.
  Reply With Quote
11-20-10, 10:53 PM   #11
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
I hate to edit my replies while another poster "might" reply to my original text,
but it inadvertently happens when you post at 6am local time.

It was a copy paste error maybe you'd like to post the SecondsToTimeAbbrev source function as well
  Reply With Quote
11-20-10, 11:05 PM   #12
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
@Ketho try it like this:
Code:
/run print(string.format("%d \1244minute:minutes;",3))
Also you are correct about SendChatMessage()
(didn't realize we were talking about sending it in a message)
but you can work around that like this:
Code:
/run local b=CreateFrame("Button");SendChatMessage(b:GetText(b:SetFormattedText("%d \1244minute:minutes;",3)),"SAY")
This is just a temporary frame you'll never show but re-use to get back the formatted text without the escape codes for sending safely as a message.
  Reply With Quote
11-20-10, 11:06 PM   #13
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,326
Originally Posted by Ketho View Post
I still have/had no clue what %d is or how it works, but I think your code will explain it now
It's a format identifier for string.format() that places in an integer value.
It's practically the C function sprintf() run on the string and the output buffer is returned.

See sprintf - C++ Reference for format identifier reference.



Originally Posted by Ketho View Post
My "debugged" /dump
I wrote my own /dump function from scratch, avoiding recursive calling so it doesn't increase the call stack, and supports UI names, circular/repeat pointer references, multiple queries/return values, and return passthrough as an API call.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 11-20-10 at 11:08 PM.
  Reply With Quote
11-21-10, 01:37 AM   #14
Ketho
A Pyroguard Emberseer
 
Ketho's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,026
@Dridzt: thanks for showing me this workaround
@SDPhantom: and thanks for telling and linking about the format identifier ..

Originally Posted by SDPhantom View Post
I wrote my own /dump function from scratch, avoiding recursive calling so it doesn't increase the call stack, and supports UI names, circular/repeat pointer references, multiple queries/return values, and return passthrough as an API call.
Actually my "/dump" is just the same as a normal ingame /dump, except for frame debugging... nvm that
But that is some crazy /dump function, I don't understand any part of that sentence ><

I guess trying to help others only make me end up getting helped xD
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Time formatting noob question


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off