Converting milliseconds or seconds to additive military time with >24 hours in the hours bucket involves division, modulo division and orders of operations in equation creation. I want these to be additive measures, hence the inner SUM. For milliseconds we first convert them to seconds with /1000, so both formulas are essentially the same structure.
This is something I first did back in 2012 while consulting for Tableau onsite in Indianapolis, and I have meant to blog it ever since. The time is now.

I have included a Tableau TWBX from 2019.4.0 here if you want to reverse engineer.
TLDR; Just Give me the Equation
//Hours
STR(INT((SUM([milliseconds])/1000/60/60)))
//Delimiter
+ ":" +
//Minutes with Leading 0
IF LEN(STR(INT((SUM([milliseconds])/1000)/60%60)))=1 THEN
"0" + STR(INT((SUM([milliseconds])/1000)/60%60))
ELSE
STR(INT((SUM([milliseconds])/1000)/60%60))
END
//Delimiter
+ ":" +
//Seconds with Leading 0
IF LEN(STR(INT((SUM([milliseconds])/1000)%60)))=1 THEN
"0" + STR(INT((SUM([milliseconds])/1000)%60))
ELSE
STR(INT((SUM([milliseconds])/1000)%60))
END
//Delimiter
+ "." +
RIGHT(STR(1000+SUM([milliseconds])),3)
Breaking Down the Equation
//Hours
STR(INT((SUM([milliseconds])/1000/60/60)))
- (SUM(milliseconds)/1000)
- Use a Sum so the label is additive and flexible depending on the level of detail in the sheet.
- Convert to seconds from milliseconds
- /60/60
- The first /60 creates minutes from the seconds and the next /60 converts the minutes to hours
- Alternatively you could just divide the milliseconds by 3,600,000 but I wanted to really break it down
- INT()
- Round out the division results to a 0 decimal integer to avoid data type inconsistencies for outer string conversion
- STR()
- Wrap the hours statement in a string because this is a label and I want concatenation with the “+” operator and not adding hours to minutes.
//Minutes with Leading 0
IF LEN(STR(INT((SUM([milliseconds])/1000)/60%60)))=1 THEN
"0" + STR(INT((SUM([milliseconds])/1000)/60%60))
ELSE
STR(INT((SUM([milliseconds])/1000)/60%60))
END
- (SUM(milliseconds)/1000)
- Use a Sum so the label is additive and flexible depending on the level of detail in the sheet.
- Convert to seconds from milliseconds
- /60%60
- Dividing by 60 converts the seconds to minutes
- Modulo division by 60 (%) results in the remaining minutes that could not be transfered to the hours place after converting the minutes to hours
- INT()
- Round out the division results to a 0 decimal integer to avoid data type inconsistencies for outer string conversion
- STR()
- Wrap the minutes expression in a string because this is a label and I want concatenation with the “+” operator and not adding minutes to seconds
- “0” +
- Add a leading 0 to the string when resulting minutes is only a single digit
- IF LEN() = 1
- Wrap the minutes expression in an IF clause to find cases where a leading 0 is necessary, else the expression just returns the double digit minutes
//Seconds with Leading 0
IF LEN(STR(INT((SUM([milliseconds])/1000)/60%60)))=1 THEN
"0" + STR(INT((SUM([milliseconds])/1000)/60%60))
ELSE
STR(INT((SUM([milliseconds])/1000)/60%60))
END
- (SUM(milliseconds)/1000)
- Use a Sum so the label is additive and flexible depending on the level of detail in the sheet.
- Convert to seconds from milliseconds
- %60
- Modulo division by 60 (%) results in the remaining seconds that could not be transferred to the minutes place after converting the seconds to minutes
- INT()
- Round out the division results to a 0 decimal integer to avoid data type inconsistencies for outer string conversion
- STR()
- Wrap the seconds expression in a string because this is a label and I want concatenation with the “+” operator and not adding seconds to minutes
- “0” +
- Add a leading 0 to the string when resulting seconds is only a single digit
- IF LEN() = 1
- Wrap the seconds expression in an IF clause to find cases where a leading 0 is necessary, else the expression just returns the double digit seconds
//Milliseconds to right of decimal
RIGHT(STR(1000+SUM([milliseconds])),3)
- SUM(milliseconds)
- Use a Sum so the label is additive and flexible depending on the level of detail in the sheet.
- 1000+
- This is a handy trick to avoid having to do more verbose nested IF statements to add 1 and 2 leading zeros respectively. Just add 1000 to the milliseconds to pad in the 0 or 00 for the outer statements
- STR()
- Wrap the milliseconds expression in a string because this is a label and I want concatenation with the “+” operator and not adding milliseconds to seconds
- RIGHT(,3)
- Pull the 3 digit milliseconds with leading zeros to the right of the decimal
Hey David. Why does everyone call it military time? It’s simply a 24-hour clock 😉
LikeLike
Great question, I think this comes down to a US bias. In the US we commonly say 2:00pm instead of 14:00 like most other places in the world. However, in the military even US soldiers would say 14:00. Hence the nickname Military time. In this post the hours are additive past 24 hours, not sure what to call that?
LikeLiked by 1 person