Is there a way to format time in variable units?

JenniferMurphy

Well-known Member
Joined
Jul 23, 2011
Messages
2,535
Office Version
  1. 365
Platform
  1. Windows
I would like to be able to format a time value so that it is displayed in the smallest units that are less than "1" of the next larger unit. That is, use seconds up to 1 minute, then minutes up to 1 hour, hours up to 1 day, etc. I would also like to be able to specify the number of decimal points to display, which complicates things.

Here are some examples:

C/R
ABCD
1ValueUnitsDPResult
21.75sec02 secs
31.75sec11.8 secs
459.49sec159.5 secs
559.50sec159.5 secs
659.50sec01 mins
759.95sec
259.95 secs
859.95sec11 mins
923.49hour123.5 hours
1023.49hour023 hours
1123.50hour123.5 hours
1223.50hour01 days

<tbody>
</tbody>


I started writing a UDF, but it quickly got complicated. Is there an easy way to do this?

If not, I'll post my UDF if I ever get it working.
 
The following UDF returns the expected results for the dataset from Post # 1:
Code:
Public Function FmtTime(ByVal pTime As Double, _
                Optional ByVal pInUnits As String = "Days", _
                Optional ByVal pDP As Byte = 1, _
                Optional ByVal pNegOK As Boolean = False) As String
    If pTime < 0 And Not pNegOK Then FmtTime = CVErr(xlErrValue): Exit Function
    prf = Sgn(pTime)
    pTime = Round(Abs(pTime), pDP)
    Select Case Left(UCase(pInUnits), 1)
        Case "S": curr = " secs": thr = 60: nxt = " mins"
        Case "M": curr = " mins": thr = 60: nxt = " hours"
        Case "H": curr = " hours": thr = 24: nxt = " days"
        Case "D": curr = " days": thr = 30: nxt = " months"
    End Select
    If pTime < thr Then
        FmtTime = prf * pTime & curr
    Else
        FmtTime = prf * Round(pTime / thr, pDP) & nxt
    End If
End Function
 
Upvote 0

Excel Facts

Lock one reference in a formula
Need 1 part of a formula to always point to the same range? use $ signs: $V$2:$Z$99 will always point to V2:Z99, even after copying
i tried using formula

Code:
Value	Units	DP	Result       	using formula
1.75	sec	0	2 secs       	2 secs
1.75	sec	1	1.8 secs	1.8 secs
59.49	sec	1	59.5 secs	59.5 secs
59.5	sec	1	59.5 secs	59.5 secs
59.5	sec	0	1 mins       	1 mins
59.95	sec	2	59.95 secs	59.95 secs
59.95	sec	1	1 mins      	1 mins
23.49	hour	1	23.5 hours	23.5 hours
23.49	hour	0	23 hours	23 hours
23.5	hour	1	23.5 hours	23.5 hours
23.5	hour	0	1 days       	1 days
160.5	sec	1       		2.7 mins
200.5	sec	0      	        	3 mins
61.7	sec	1       		1 mins
12.6	hour	1              		12.6 hours
25.6	hour	1               	1.1 days
30.2	hour	1              		1.3 days
180.2	sec	1              		3 mins
98	sec	10	        	1.6333333333 mins
101.5	hour	5	         	4.22917 days
76.367	hour	17	        	3.18195833333333 days
42	hour	4	        	1.75 days
140.777	sec	2	        	2.35 mins


cell under "using formula" column is
Code:
=IF(B2="sec",(IF(QUOTIENT(ROUND(A2,C2),60)<1, ROUND(A2,C2)&" secs",QUOTIENT(ROUNDUP(A2,C2),60)+IF(ROUND(MOD(A2,60)/60,C2)<1,ROUND(MOD(A2,60)/60,C2),0)&" mins")),IF(B2="min",IF(QUOTIENT(ROUND(A2,C2),60)<1, ROUND(A2,C2)&" mins",QUOTIENT(ROUNDUP(A2,C2),60)+IF(ROUND(MOD(A2,60)/60,C2)<1,ROUND(MOD(A2,60)/60,C2),0)&" hours"),IF(B2="hour",IF(QUOTIENT(ROUND(A2,C2),24)<1, ROUND(A2,C2)&" hours",QUOTIENT(ROUNDUP(A2,C2),24)+IF(ROUND(MOD(A2,24)/24,C2)<1,ROUND(MOD(A2,24)/24,C2),0)&" days"))))

this doesnt account for units in days though
 
Upvote 0
Thanks to everyone for their comments. Unless I made a mistake, the code form both Mike E and Tetra have bugs related to rounding. I believe the problem is that they round before converting the units. Based on all of this, I completed my UDF, which I have posted below. Here are the results of the sample data for the three solutions:

R/C
ABCD
EFG
1ValueUnitsDPResult
MikeETetraJM
21.75sec02 secs
0. Hr.2 secs2 sec
31.75sec11.8 secs1.8 Sec1.8 secs1.8 sec
459.49sec159.5 secs59.5 Sec59.5 secs59.5 sec
559.50sec159.5 secs59.5 Sec59.5 secs59.5 sec
659.50sec01 mins0. Hr.1 mins1 min
759.95sec259.95 secs59.95 Sec59.95 secs59.95 sec
859.95sec11.0 mins0.0 Hr.1 mins1.0 min
923.49hour123.5 hours
1409.4 Min23.5 hours23.5 hrs
1023.49hour023 hours23. Hr.23 hours23 hrs
1123.50hour123.5 hours23.5 Hr.23.5 hours23.5 hrs
1223.50hour01 days24. Hr.1 days1 dys

<tbody>
</tbody>

Here's my code. Comments appreciated.

Code:
Public Function FmtTime(ByVal pTime As Double, _
                        Optional ByVal pInUnits As String = "Secs", _
                        Optional ByVal pDP As Byte = 1, _
                        Optional ByVal pNegOK As Boolean = False) As String

Const MaxSec As Double = 60   'Cutoff for converting over to minutes
Const MaxMin As Double = 60   'Cutoff for converting over to hours
Const MaxHrs As Double = 24   'Cutoff for converting over to days
Const MaxDys As Double = 14   'Cutoff for converting over to weeks
Const MaxWks As Double = 52   'Cutoff for converting over to years
Dim OutTime As Double         'The working time value
Dim temp As Double            'Temporary time variable

' Check for negative time
If pTime < 0 Then         'If the time is negative,
  If Not pNegOK Then        'And that is not OK,
    FmtTime = CVErr(xlErrValue) 'Return a Value error
    Exit Function
  End If
End If
OutTime = Abs(pTime)      'Convert to positive for formatting

'Convert everything to seconds
Select Case UCase(pInUnits)      'Process the pInUnits argument
  Case "S", "SEC", "SECS", "SECOND", "SECONDS"  'If in seconds, no conversion
  Case "M", "MIN", "MINS", "MINUTE", "MINUTES"  'If in minutes,
    OutTime = OutTime * 60                        'Convert to seconds
  Case "H", "HRS", "HOUR", "HOURS"              'If in hours,
    OutTime = OutTime * 60 * 60                   'Convert to seconds
  Case "D", "DYS", "DAY", "DAYS"                'If in days,
    OutTime = OutTime * 60 * 60 * 24              'Convert to seconds
  Case "W", "WKS", "WEEK", "WEEKS"              'If in weeks,
    OutTime = OutTime * SecsPerWeek               'Convert to seconds
  Case "Y", "YRS", "YEAR", "YEARS"              'If in years,
    OutTime = OutTime * SecsPerYear               'Convert to seconds
  Case Else                                     'If none on the above.
    FmtTime = CVErr(xlErrValue)                   'Return Value error
    Exit Function
End Select

'Will it be seconds?
temp = Round(OutTime, pDP)      'Round to specified decimal places
If temp < MaxSec Then           'If < max secs, do it in seconds
  FmtTime = FormatNumber(OutTime, pDP) & " sec"
  GoTo Done
End If

'Will it be minutes?
OutTime = OutTime / 60          'Convert from seconds to minutes
temp = Round(OutTime, pDP)      'Round to specified decimal places
If temp < MaxMin Then           'If < max mins, do it in minutes
  FmtTime = FormatNumber(OutTime, pDP) & " min"
  GoTo Done
End If

'Will it be hours?
OutTime = OutTime / 60          'Convert from minutes to hours
temp = Round(OutTime, pDP)      'Round to specified decimal places
If temp < MaxHrs Then           'If < max hours, do it in hours
  FmtTime = FormatNumber(OutTime, pDP) & " hrs"
  GoTo Done
End If

'Will it be days?
OutTime = OutTime / 24          'Convert from hours to days
temp = Round(OutTime, pDP)      'Round to specified decimal places
If temp < MaxDys Then           'If < max days, do it in days
  FmtTime = FormatNumber(OutTime, pDP) & " dys"
  GoTo Done
End If

'Will it be weeks?
OutTime = OutTime / 7           'Convert from days to weeks
temp = Round(OutTime, pDP)      'Round to specified decimal places
If temp < MaxWks Then           'If < max weeks, do it in weeks
  FmtTime = FormatNumber(OutTime, pDP) & " wks"
  GoTo Done
End If

'It has to be years
OutTime = OutTime / 365         'Convert it to years
FmtTime = FormatNumber(OutTime, pDP) & " yrs"

Done:
If pTime < 0 Then FmtTime = "-" & FmtTime 'If it was negative, add negative sign

End Function
 
Upvote 0
ok - not exactly the prettiest solution, but tell me what you think about this:
cell E2:
Code:
=IF(B2="sec",A2,IF(B2="min",A2*60,IF(B2="hour",A2*60*60,IF(B2="day",A2*60*60*24,IF(B2="week",A2*60*60*24*7,IF(B2="month",A2*60*60*24*7*30,IF(B2="year",A2*60*60*24*7*30*12,0)))))))

cell F2:
Code:
=IF(ROUND(E2,C2)<60,"sec",IF(ROUND(E2,C2)<3600,"min",IF(ROUND(E2,C2)<86400,"hour",IF(ROUND(E2,C2)<604800,"day",IF(ROUND(E2,C2)<2592000,"week",IF(ROUND(E2,C2)<31104000,"month","year"))))))

cell G2:
Code:
=ROUND(IF(F2="sec",E2,IF(F2="min",E2/60,IF(F2="hour",E2/3600,IF(F2="day",E2/86400,IF(F2="week",E2/604800,IF(F2="month",E2/2592000,E2/31104000)))))),C2)&" "&F2

then hide columns E & F?
 
Upvote 0
ok - not exactly the prettiest solution, but tell me what you think about this:

Thanks, Mike, but I really want a UDF solution. Even if the cell formula works, I have to remember it and copy it without making a mistake. It's just too messy. :eek:
 
Upvote 0

Forum statistics

Threads
1,215,379
Messages
6,124,607
Members
449,174
Latest member
ExcelfromGermany

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top