Here’s a quick lunchtime post on working with durations in Tableau. By duration, I mean having a result that is showing the number of seconds, minutes, hours, and/or days in the form of dd:hh:mm:ss. This isn’t quite a built-in option, there are a several ways to go about this:

- Use any duration formatting that is supported in your data source, for example by pre-computing values or using a RAWSQL function.
- Do a bunch of calculations and string manipulations to get the date to set up. I prefer to avoid these mainly because they can be over 1000x slower than numeric manipulations. If you want to see how to do this, there’s a good example on this Idea for Additional Date Time Number Formats. (If that idea is implemented and marked as Released, then you can ignore this post!)
- If the duration is less than 24 hours (86400 seconds), then you can use Tableau’s built-in date formatting. I’ll show how to do this here.
- Do some calculations and then use Tableau’s built-in number formatting. This is the brand-new solution and involves a bit of indirection.

# Durations Guaranteed To Be Less Than 24 Hours: Tableau’s Date Formatting

If you know your duration is always going to be less than 24 hours (86400 seconds), , then you can take advantage of Tableau’s built-in date formatting. The first step is to get your duration in seconds, if it’s not already. For example, for looking at the duration between two dates you can use DATEDIFF(‘second’,[Start Time], [End Time]). Once you have that number of seconds, then you can use the following calculation

If the total time is less than 24 hours, then we can use the following calculation: DATETIME([Seconds]/86400). Then we can use Tableau’s date format to set the format as **hh:nn:ss** (in this case **hh:mm:ss** will also work):

Here’s a view…take a look at what happens at 86400 seconds and beyond:

Instead of showing 24 hours, the date formatting looks just at the hours, minutes, and seconds. As long as your duration is less than 86400 seconds, everything will be simple using this technique.

# Any Duration: Using Arithmetic and Number Formatting

Though Tableau’s built-in formatting is not as powerful as Excel, we can still do quite a bit. Check out Robert Mundigl’s Custom Number Formats for a pretty exhaustive list of what can be done. (He’s also got a fantastic post on String Calculations that is worth checking out.)

For example, we can set up a custom number format of **00:00**, and that will perfectly format a number as a time…up to 59 seconds, that is:

However, this is a clue to the next step, which is that since we space out numbers by colons, all we need to do is get the right value into the right decimal place. So, for example, instead of 60 seconds (1 minute) being a value of 60, it has to have a value of 100 so the **00:00** formatting will make it **01:00**. Here’s a formula that does just that for **mm:ss** values:

//replace [Seconds] with whatever field has the number of seconds in it //and use a custom number format of 00:00:00:00 //(drop the first 0 to get rid of leading 0's for minutes) IIF([Seconds] % 60 == 60,0,[Seconds] % 60)// seconds + INT([Seconds]/60) * 100 //minutes

The formula uses the % (modulo) function to divide the number of seconds by 60 to get the remainder, the IIF statement is there to deal with what happens when the number of seconds is divisible by 60, the result of that is the number of seconds, then the number of minutes *100 is added to that. Here’s a view:

For **hh:mm:ss** the formula gets a little more complex. Just as the seconds had to be transformed to make 0-59 seconds, minutes have to do a similar transformation:

//replace [Seconds] with whatever field has the number of seconds in it //and use a custom number format of 00:00:00 (drop the first 0 to get rid of leading 0's for hours) IIF([Seconds] % 60 == 60,0,[Seconds] % 60)// seconds + IIF(INT([Seconds]/60) %60 == 60, 0, INT([Seconds]/60) %60) * 100 //minutes + INT([Seconds]/3600) * 10000 //hours

And for **dd:hh:mm:ss** there’s yet another transformation to convert hours to 0-23:

//replace [Seconds] with whatever field has the number of seconds in it //and use a custom number format of 00:00:00:00 (drop the first 0 to get rid of leading 0's for days) IIF([Seconds] % 60 == 60,0,[Seconds] % 60)// seconds + IIF(INT([Seconds]/60) %60 == 60, 0, INT([Seconds]/60) %60) * 100 //minutes + IIF(INT([Seconds]/3600) % 24 == 0, 0, INT([Seconds]/3600) % 24) * 10000 //hours + INT([Seconds]/86400) * 1000000 // days

Here’s a view showing all three calculations:

A little dose of math, sprinkle some custom number formatting on it, and voila, there’s some usable duration formatting. If you wanted to keep going into weeks then there would need to be another level of calculation, to get into months and years I’d probably use a different approach because the intervals (month lengths and year lengths) aren’t fixed.

Here’s the workbook on Tableau Public: Duration Formatting

If this is useful to you, or you have an alternative technique, let me know in the comments below!

# Addendum on Aggregation (July 2015)

Some people people using this technique have run into problems as seen in the comments below and on the Tableau forums. For example, if we build a view like this and sum up all the values of Seconds with the duration calc applied (see the SUM() aggregation) the numbers don’t add up. In this view the total time in mm:ss should be 44558:00 but it’s showing up as 44554:80, a non-sensical amount:

Alternatively, if we keep Seconds in the view as a dimension but add a Grand Total, the Grand Total isn’t adding up either:

The issue is with regards to order of operations. When we build the views with the grand total or by summing the measure, there’s an aggregation happening and it’s not happening at the right time vis-a-vis the formatting. I put together a series of graphics to explain what is going on.

In the original post the duration calculations are performed for each record and the results are treturned from the view. So it looks like this:

So in this case here’s what’s going on under the hood:

That’s not often used in practice, more often a view looks like this, where the mm:ss is being used as a measure and then when the original calculation is brought into the view we can see that Tableau is actually aggregating the duration calculation with the default aggregation of SUM():

However, that SUM() has no effect because the level of detail (the granularity) of the view is the same is the same as the data — in other words, the view is effectively displaying the raw data. So the order of operations is actually like this:

So even though these two views look exactly the same, under the hood they are using two different ways to get there. Where this causes problems is when we apply an aggregation that is across multiple records or in a grand total or subtotal. The duration calculation that was meant to be applied to the final result is being applied to every record and it’s that transmogrified amount that is getting summed:

The solution is pretty straightforward, we just need to do the aggregation *before* we apply the duration calculation. So instead of the [Seconds] of the original calculation we use Sum Seconds with the formula SUM([Seconds]), and the formula for mm:ss (agg) is:

//replace [Sum Seconds] with whatever field has the number of seconds in it IIF([Sum Seconds] % 60 == 60,0,[Sum Seconds] % 60)// seconds + INT([Sum Seconds]/60) * 100 //minutes

So the order of operations is now:

And here’s a view showing the inaccurate and now accurate aggregate calculations:

And a grand total:

I’ve updated the Duration Formatting workbook to reflect this addendum.

Dave WalpWow! I know I will get a lot of use out of this. Thank you for your massive contributions to the community.

Jonathan DrummeyPost authorYou’re welcome!

varawe are looking for tableau resources at Bay Aarea, CA, USA.

— texara.bigdata@gmail.com

Bobby WeaverGreat information. I’ve already pasted the posting into Evernote for safe keeping. The only tidbit I would add is that your % (modulo) function formula also supports the hh:mm format as long as you specify ‘minute’ in the DATEDIFF formula.

Jonathan DrummeyPost authorThanks, Bobby, that’s a good extra bit of info!

Pingback: Time Duration in Tableau | Data Knight Rises

Bryan AndrewsI have used the formula with success in calculating total Utilization hours for our ambulance units. Now the manager wants the format of the number to change. Basically he wants to see a whole number for the hours and the minutes and seconds shown as a decimal. In other words 198:22:15 becomes 198.37. Can I modify the formula to get that alternate format?

SabreeI wanted to get your thoughts and advice on how to handle “drive times” from certain zip codes in Tableau. I’ve been searching around for some examples of this and haven’t found any yet. Thanks

Jonathan DrummeyPost authorHI Sabree, I suggest you post something on the Tableau forums. I haven’t done work with drive-time analysis.

HrvojeThank you for the post Jerremy. But when I tried to aggregate values I had something like 23:80:10. To seconds are more than sixty. Is there any fix for that ?

Jonathan DrummeyPost authorHi Hrvoje,

I’m Jonathan, not Jerremy. 🙂 Without seeing your calc, I can’t help you. Try posting a packaged workbook with some sample data to the Tableau forums, then link back to it here and I’ll take a look.

Jonathan

Pingback: Tinkering with FLOAT() and Durations « Tableau Tinkering

AleksandarHello everyone,

I’ve tried:

For hh:mm:ss the formula gets a little more complex. Just as the seconds had to be transformed to make 0-59 seconds, minutes have to do a similar transformation:

//replace [Seconds] with whatever field has the number of seconds in it

//and use a custom number format of 00:00:00 (drop the first 0 to get rid of leading 0’s for hours)

IIF([Seconds] % 60 == 60,0,[Seconds] % 60)// seconds

+ IIF(INT([Seconds]/60) %60 == 60, 0, INT([Seconds]/60) %60) * 100 //minutes

+ INT([Seconds]/3600) * 10000 //hours

But as result I get, for example 11:98:56….

I don’t no what I did wrong.

If anyone knows what is the problem please post it.

Aleksandar

Jonathan DrummeyPost authorHi Aleksandar, is that the exact calculation you are using in your workbook? It looks like you copied and pasted the text from the blog post, so I can’t be sure. Also, are you looking at a value in a detail row or a Grand Total? Grand Totals introduce an additional complication where you have to use an aggregate measure for the seconds in place of a record-level of seconds. What would make it easiest for me to help you is if you posted a link to either a Tableau Public viz or a Tableau packaged workbook file that the calc and some sample data.

Jonathan

AleksandarHi Jonathan,

I’ve copied an pasted the text and replace [Seconds] with my measure [total_talk_time] which is in seconds (ex.15456).

I have a thousands of agents with different talk time and I want to see total of talk time in one month per agent but in format hh:mm:ss(but I have examples where there is overlap of 24 hours). I am very familiar with tableau but I dont exactly understand this calculation and therefore i dont know if i need to change something more.

Thank you.

Aleksandar

Jonathan DrummeyPost authorThis is a follow-up, Aleksandar and I had a conversation over email. The solution turned out to be using an aggregate calculation in place of [Seconds] in the calculation, I’ve added a note to that effect above.

MariaThank you! this is awesome

Jonathan DrummeyPost authorYou’re very welcome!

Pingback: Tableau Tips,Tricks,Best Practices - Formatting - Jenny (Xiao) Zhang

Brandi BealsSo helpful! Thank you!

Jonathan DrummeyPost authorYou’re welcome!

ashokHi Jonathan,

This is super. But my scenario requires me to aggregate the time and it does not work with that. if i sum it up this gives me values like 01:70: 32:79. Please explain if there is any way to overcome this issue.

Jonathan DrummeyPost authorHi Ashok,

I’m guessing that you’ll need to aggregate the underlying measure and *then* apply the calculation to set the formatting.

Rody ZakovichHello Jonathan,

Thank you for pointing this out in the Forum. This is a fantastic workaround to a problem that I did not think was possible (Showing Duration in Measure Values)

Love your blog and everything you do for the community!

Regards,

Rody

Erik WassonHi Jonathan,

Would you be able to give me a walkthrough of how to have it display as h:mm?

Jonathan DrummeyPost authorHi Erik,

Please see the https://public.tableau.com/views/durationformatting/DurationstotheMinute?:embed=y&:display_count=yes&:showTabs=y worksheet in the Duration Formatting workbook. If you’re starting with seconds you have to make a choice about rounding seconds to minutes, the worksheet has calculations for both. The worksheet shows hh:mm calcs, to change them to h:mm all you need to do is use a custom format of #:##. Let me know if you have any more questions!

Jonathan

AnitaHi ,

I have a date field which give total duration spent by a person on particular task. The hour field has values lik , ” 0:45 : 34″ , ” 99:30:00″ , “203:56:45” etc. When I drag the filed to tableau , it shows data with date which converts the hours to below 23 number.

I want to extract the total hours for a participant in hours. How Can I do that ?

Say for “99:30:00” = 99.5 hours.

Thanks,

Anita.

Jonathan DrummeyPost authorHi Anita,

Since Tableau doesn’t have a built-in notion of duration it automatically interprets those fields as dates as you’ve discovered. In order for to convert the h:mm:ss duration into a decimal number of hours we need to do some string manipulation. Here’s a formula that works on most data sources using the FINDNTH() function introduced in Tableau v9. If you are on a data source that doesn’t support FINDNTH() that could be replaced with a combination of LEFT() and LEN(). There’s likely a regex-based solution as well.

//assumes a duration string of format h:mm:ss where 34 seconds is 0:00:34 return the decimal number of hours

//hours

INT(LEFT([myField], FIND([myField],’:’)-1))

// minutes turned into hours

+ INT(MID([myField], FIND([myField],’:’)+1, FINDNTH([myField],’:’,2) – FIND([myField],’:’) – 1)) / 60

// seconds turned into hours

+ INT(RIGHT([myField], 2)) / 3600

Jonathan

AnitaThank you Jonathan. The actual problem with my data was Tableau converting the hours >24 to days automatically, that’s why I was not able to get the correct Hours from Date field by datepart function. Now I have converted the days also to hours to get correct total hours.

mdeutschmtlAnother hat tip from up on Montreal… I had to depict large numbers of elapsed seconds as ‘hh:mm:ss’ and found this very clear and well explained. Thanks, Jonathan! 🙂

Jonathan DrummeyPost authorYou’re welcome!

Don WiseHi Jonathan,

Thank you for the work here; it’s great! I think it’s resolving my issue with supplying a “dd” format to my data, but I’m seeing an issue with my results. We’re using Tableau to produce monthly reports for our local Fire Departments.

Normally we only deal with incident durations of less than 24 hours so our results have never been in question. However, now we’re in need of determining an ambulance and fire engine total duration compared to the number of incidents they respond on each month. So we’re entering into a need to compute in a “dd:hh:mm:ss” format.

For the majority of the units incident duration being measured, it looks good. But two of them that have less than 100 incidents per month are resulting in the following result(s): Engine 38 = 31:00:35:42 and Engine 39 = 30:19:48:28

I’ve tried removing “/86400” from my original Incident Duration calc in order to use just the resulting record level decimal number and then used your formula separately for formatting, but achieved even stranger results. Is it possible our date formats that we’re using are differently structured?

Thoughts? And thanks in advance for any insight…Don

Don WiseHi Jonathan,

I re-read your post about order of operations and got it worked out; thank you! Don

semaozJorgeHi Jonathan,

How would you, based on a date/time field build a filter that excludes overtime? The filter should be a simple “yes/no” type.

Jonathan DrummeyPost authorHi semaozJorge, this totally depends on how your data is set up. Is there one record with a duration value, are there multiple records that each have a start & end time, are there 2x that number of records where each record has an employee ID and a start time or an employee ID and an end time? How much of the duration calculation we have to do in Tableau has a huge impact on what we do for the filter calculation.

Jonathan

MIHHi Jonathan,

This is fantastic, thank you! I was struggling with the nonsensical outcomes when subtracting time durations for a year over year comparison, and the Sum(seconds) substitution worked like a charm.

My only problem now is for each of the two years I’m comparing, I’m only able to aggregate as a sum in the grand total column, when I would want to see an average instead. To further explain, I have one row of data with average time durations for each month last year, and another row with average durations for each month this year. My third row subtracts last year from this year’s duration each month to provide the variance. I want the grand total column in the end to give me the average for each year, and the variance between the two, but it will now only add all months for each year.

Any idea how to get around this issue? Thanks!

Jonathan DrummeyPost authorHi,

Without seeing exactly how you constructed the view I can’t say, you could send me screenshot or a Tableau packaged workbook at jonathan(dot)drummey(at)gmail and I can take a look.

Jonathan