VHDL: How to change the resolution of time printed using "now" in VHDL to file or terminal
In IEEE Std 1076-2008 16.4 Package TEXTIO:
procedure WRITE (L: inout LINE; VALUE: in TIME;
                 JUSTIFIED: in SIDE:= RIGHT; FIELD: in WIDTH := 0;
                 UNIT: in TIME:= ns);


...
For each predefined data type there is one or more WRITE procedure declared in package TEXTIO. Each of these has at least two parameters: L, the line to which to write, and VALUE, the value to be written. The additional parameters JUSTIFIED, FIELD, DIGITS, FORMAT, and UNIT control the formatting of output data. Each write operation appends data to a line formatted within a field that is at least as long as required to represent the data value. Parameters FIELD and JUSTIFIED specify the desired field width and justification, as for the JUSTIFY operation. For the predefined type BIT_VECTOR, there is likewise one OWRITE and one HWRITE procedure, with similar parameters.
...
Parameter UNIT specifies how values of type TIME are to be formatted. The value of this parameter shall be equal to one of the units declared as part of the declaration of type TIME; the result is that the TIME value is formatted as an integer or real literal representing the number of multiples of this unit, followed by the name of the unit itself. The name of the unit is formatted using only lowercase characters. Thus the procedure call WRITE(Line, 5 ns, UNIT=&gt;us) would result in the string value &quot;0.005 us&quot; being appended to the string value designated by Line, whereas WRITE(Line, 5 ns) would result in the string value &quot;5 ns&quot; being appended (since the default UNIT value is ns).

You can specify the format either through named association of the parameter list or by positional association (providing the entire set of parameters, including those that have defaults).
6.6.7 Association lists, 6.5.7.1 General

An association element is said to be named if the formal designator appears explicitly; otherwise, it is said to be positional. For a positional association, an actual designator at a given position in an association list corresponds to the interface element at the same position in the interface list.
Named associations can be given in any order, but if both positional and named associations appear in the same association list, then all positional associations shall occur first at their normal position. Hence once a named association is used, the rest of the association list shall use only named associations.

Which tells us you could
write (some_line, some_time_value, UNIT =&gt; ms);

This is supported as early as -1987.
For to_string operations:
5.7 String representations

When forming the string representation for a WRITE procedure in STD.TEXTIO (see Clause 16) or for an implicitly defined TO_STRING operation, except where otherwise specified for an overloaded TO_STRING operation:
...

For a value of a physical type, when forming the string representation for a TO_STRING operation, the abstract literal is a decimal literal that is an integer literal, there is no exponent, and there is a single SPACE character between the abstract literal and the unit name. If the physical type is TIME, the unit name is the simple name of the resolution limit (see 5.2.4.2); otherwise, the unit name is the simple name of the primary unit of the physical type. When forming the string representation for the WRITE procedure for type TIME, the physical literal is as described in 16.4.