# How to override DisplayForm of (mixed) time Quantity

What's the best approach to overriding DisplayForm for specific types of Quantity eg time especially w/ mixed units?

Current is too verbose, eg:

Would rather have control as follows:

Quantity[MixedMagnitude@{0, 2, 3},
MixedUnit@{"Hours", "Minutes", "Seconds"}]


0 h 2 min 3 s

1. Would prefer either:

:02:03

Or

02:03s

even if not standard, ie hide hours if zero.

1. Quantity[2,"Minutes"] show as m rather than min - which is used to disambiguate from unit Meters, but it's often obvious from context that it's time units.

2. Finally, to display even 0 time, which currently doesn't have a DisplayForm:

Quantity[MixedMagnitude@{0, 0, 0}, MixedUnit@{"Hours", "Minutes", "Seconds"}]

What's the best approach, eg UpSet?

Code

The function QuantityUnitsPrivateQuantityUnitBox handles the display form of quantities. We modify only the definition related to mixed magnitudes and mixed units:

(* From a fresh kernel *)

SystemQuantity;

Unprotect[QuantityUnitsPrivateQuantityUnitBox];

QuantityUnitsPrivateQuantityUnitBox[
QuantityUnitsPrivateQuantityUnitBoxq :
Quantity[
QuantityUnitsPrivateQuantityUnitBoxm_MixedMagnitude,
QuantityUnitsPrivateQuantityUnitBoxu_MixedUnit,
QuantityUnitsPrivateQuantityUnitBoxopts___?OptionQ
],
QuantityUnitsPrivateQuantityUnitBoxform_
] /; QuantityQ[QuantityUnitsPrivateQuantityUnitBoxq] := With[

{q = QuantityUnitsPrivateQuantityUnitBoxq,
form = QuantityUnitsPrivateQuantityUnitBoxform,
m = First@QuantityUnitsPrivateQuantityUnitBoxm,
u = First@QuantityUnitsPrivateQuantityUnitBoxu},

If[u === {"Hours", "Minutes", "Seconds"} || u === {"Minutes", "Seconds"},
myQuantityDisplay[m, u],
QuantityUnitsPrivateToMixedUnitQuantityTemplateBox[q, form]
]

];

Protect[QuantityUnitsPrivateQuantityUnitBox];


Compared to the original version, we just added an If statement with a test on the form of the mixed units. The function myQuantityDisplay will fire for OP's requirements only, otherwise the standard display will be kept.

(To change the display of any time quantities, probably UnitDimensions and TimeUnit could be used in some way for the test.)

We are left with the definition of myQuantityDisplay

myQuantityDisplay[{m_, s_}, {"Minutes", "Seconds"}] :=
IntegerString[m, 10, 2] <> ":" <> IntegerString[s, 10, 2] <> "s";

myQuantityDisplay[{0, m_, s_}, {"Hours", "Minutes", "Seconds"}] :=
IntegerString[m, 10, 2] <> ":" <> IntegerString[s, 10, 2] <> "s";

myQuantityDisplay[{h_, m_, s_}, {"Hours", "Minutes", "Seconds"}] :=
IntegerString[h, 10, 2] <> ":" <> IntegerString[m, 10, 2] <> ":" <>
IntegerString[s, 10, 2] <> "s";


The above modification only affects the display form, so that we can still perform any operation or standard evaluation on mixed quantites. Also, as mentioned, only the mixed units specifications given in the If statement are concerned.

(See Comments below for point 3 of OP's question.)

A few examples

a) Modified display

Quantity[MixedMagnitude[{1, 2, 3}], MixedUnit[{"Hours", "Minutes", "Seconds"}]]
% // FullForm


b) Standard display

Quantity[MixedMagnitude[{14, 35}], MixedUnit[{"Hours", "Minutes"}]]


c) Arithmetic operations

q = Quantity[MixedMagnitude[{14, 35}], MixedUnit[{"Minutes", "Seconds"}]]
3 q


The definitions of the function QuantityUnitsPrivateQuantityUnitBox can be accessed with PrintDefinitions. Otherwise, from the PrintDefinitions of Quantity, one has to search for the function QuantityUnitsQuantityBox in

MakeBoxes[x : Quantity[_, u_?QuantityUnitsPrivateLooksLikeAUnitQ, ___], fmt_] ...


and from its definitions look at the second cell.

Among all the definitions of QuantityUnitsPrivateQuantityUnitBox, we can see one responsible for the format of mixed quantities (modified above), and one that concerns the display (or lack of it) for repeated zeros in the mixed magnitude. So to achieve point 3 of OP's question, simply do

QuantityUnitsPrivate\$ShowZero = True;


Note that the function myQuantityDisplay should have definitions that are within the scope of MakeBoxes (as we can see from above). I think we can get more fancy outputs than the one I gave by tweaking instead the functions used by QuantityUnitsPrivateToMixedUnitQuantityTemplateBox, though this requires more spelunking.

• Xavier, thank you for this info, this more involved than I thought it would be. Does every expression with a DisplayForm have its own _UnitBox? Mar 27 '16 at 21:01

This might give you a start. You will need to Unprotect MixedMagnitude and MixedUnit, so the usual caveats apply.

Unprotect[MixedMagnitude, MixedUnit];

Quantity[HoldPattern@MixedMagnitude[x_List],
MixedUnit[{"Hours", "Minutes", "Seconds"}]] ^:=
StringRiffle[
IntegerString[#, 10, 2] & /@ If[x[[1]] == 0, Rest[x], x], ":"]

Quantity[MixedMagnitude@{0, 2, 3},
MixedUnit@{"Hours", "Minutes", "Seconds"}]
(* "02:03" *)

Quantity[MixedMagnitude@{10, 20, 30},
MixedUnit@{"Hours", "Minutes", "Seconds"}]
(* "10:20:30" *)