Function Repository Resource:

RelativeTimeString

Source Notebook

Convert a date to a human-readable string relative to the current time

Contributed by: Richard Hennigan (Wolfram Research)

ResourceFunction["RelativeTimeString"][date]

gives a human-readable string representation of date relative to the current time.

ResourceFunction["RelativeTimeString"][base,date]

uses base instead of the current time.

Details and Options

The value for date can either be a Quantity of time or a valid DateObject specification.
If date is a Quantity object, then it is interpreted as a time offset relative to the current time.
ResourceFunction["RelativeTimeString"][date] is effectively equivalent to ResourceFunction["RelativeTimeString"][Now,date] when date corresponds to a DateObject specification.
Dates can be specified as any of the following:
DateObject[]a DateObject
{y,m,d,h,m,s}a DateList specification
timean AbsoluteTime specification
"string"a DateString specification
{"string",fmt}a date string formed from the specified format
ResourceFunction["RelativeTimeString"][Quantity[]] is effectively equivalent to ResourceFunction["RelativeTimeString"][Now+Quantity[]].
A valid time Quantity has UnitDimensions of {{"TimeUnit",1}}.

Examples

Basic Examples (3) 

Get a simple text representation of a date relative to the current time:

In[1]:=
ResourceFunction["RelativeTimeString"][
 DateObject[{2022, 6, 20, 13, 42, 2.1677494049072266`}, "Instant", "Gregorian", -4.`]]
Out[1]=
In[2]:=
ResourceFunction["RelativeTimeString"][Now + Quantity[1, "Hours"]]
Out[2]=
In[3]:=
ResourceFunction["RelativeTimeString"][Tomorrow]
Out[3]=

Get a relative time string for a Quantity object:

In[4]:=
ResourceFunction["RelativeTimeString"][Quantity[42, "Seconds"]]
Out[4]=
In[5]:=
ResourceFunction["RelativeTimeString"][-Quantity[42, "Seconds"]]
Out[5]=
In[6]:=
ResourceFunction["RelativeTimeString"][Quantity[31536000, "Seconds"]]
Out[6]=
In[7]:=
ResourceFunction["RelativeTimeString"][-Quantity[10, "Nanoseconds"]]
Out[7]=

A sample of relative times in the future:

In[8]:=
ResourceFunction["RelativeTimeString"][Quantity[#, "Seconds"]] & /@ PowerRange[1, 2^28, 2]
Out[8]=

A sample of relative times in the past:

In[9]:=
ResourceFunction["RelativeTimeString"][-Quantity[#, "Seconds"]] & /@ PowerRange[1, 2^28, 2]
Out[9]=

Scope (6) 

Specify the base time:

In[10]:=
ResourceFunction["RelativeTimeString"][
 DateObject[{2022, 6, 20, 13, 42, 2.1677494049072266`}, "Instant", "Gregorian", -4.`], DateObject[{2022, 6, 27, 16, 6, 2.1677494049072266`}, "Instant", "Gregorian", -4.`]]
Out[10]=
In[11]:=
ResourceFunction["RelativeTimeString"][Now, Now - Quantity[1, "Weeks"]]
Out[11]=

Use an absolute time:

In[12]:=
ResourceFunction["RelativeTimeString"][3864567796]
Out[12]=

Compare:

In[13]:=
Now - DateObject[3864567796]
Out[13]=

Strings are interpreted as dates:

In[14]:=
ResourceFunction["RelativeTimeString"]["2022 12-15"]
Out[14]=

RelativeTimeString accepts any Quantity that corresponds to a time unit:

In[15]:=
ResourceFunction["RelativeTimeString"][Quantity[7, "DogYears"]]
Out[15]=
In[16]:=
ResourceFunction["RelativeTimeString"][-Quantity["AcademicQuarters"]]
Out[16]=
In[17]:=
ResourceFunction["RelativeTimeString"][Quantity["Fortnights"]]
Out[17]=

Quantity intervals:

In[18]:=
ResourceFunction["RelativeTimeString"][
 Quantity[Interval[{3, 5}], "Seconds"]]
Out[18]=
In[19]:=
ResourceFunction[
 "RelativeTimeString"][-Quantity[Interval[{3, 5}], "Seconds"]]
Out[19]=
In[20]:=
ResourceFunction["RelativeTimeString"][
 Quantity[Interval[{-3, 500}], "Seconds"]]
Out[20]=

Date intervals:

In[21]:=
ResourceFunction["RelativeTimeString"][
 DateInterval[{Now + Quantity[3, "Seconds"], Now + Quantity[5, "Seconds"]}]]
Out[21]=
In[22]:=
ResourceFunction["RelativeTimeString"][
 DateObject[{2022, 6, 20, 20, 59, 28.4283995`9.206327322677087}, "Instant", "Gregorian", -4.`], DateInterval[{{{2022, 6, 20, 20, 59, 23.428}, {2022, 6, 20, 20, 59, 25.428}}}, "Instant", "Gregorian", -4.]]
Out[22]=

Applications (1) 

Express the age of the current kernel in plain text:

In[23]:=
$kernelAge := StringTemplate["This `1` kernel started `2`."][
  ToLowerCase[
   ResourceFunction["FromCamelCase"][$EvaluationEnvironment]],
  ResourceFunction[
   "RelativeTimeString"][-Quantity[SessionTime[], "Seconds"]]
  ]
In[24]:=
$kernelAge
Out[24]=
In[25]:=
CloudEvaluate[$kernelAge]
Out[25]=
In[26]:=
ParallelEvaluate[$kernelAge, 1]
Out[26]=

Properties and Relations (5) 

Some outputs are dependent on the current time:

In[27]:=
ResourceFunction["RelativeTimeString"][
 DateObject[{2022, 6, 20, 8, 0, 0}, "Instant", "Gregorian", -4.`]]
Out[27]=

Equivalently:

In[28]:=
ResourceFunction["RelativeTimeString"][Now, DateObject[{2022, 6, 20, 8, 0, 0}, "Instant", "Gregorian", -4.`]]
Out[28]=
In[29]:=
Now
Out[29]=

If the current time were closer, a more reasonable approximation would be given instead:

In[30]:=
ResourceFunction["RelativeTimeString"][
 DateObject[{2022, 6, 20, 13, 0, 0}, "Instant", "Gregorian", -4.`], DateObject[{2022, 6, 20, 8, 0, 0}, "Instant", "Gregorian", -4.`]]
Out[30]=

This avoids suddenly switching to outputs like "yesterday" just after midnight for relatively small differences:

In[31]:=
ResourceFunction["RelativeTimeString"][
 DateObject[{2022, 6, 21, 0, 3, 0}, "Instant", "Gregorian", -4.`], DateObject[{2022, 6, 20, 23, 58, 0}, "Instant", "Gregorian", -4.`]]
Out[31]=

See a timeline of some of these number-free outputs for the current time of day:

In[32]:=
dates = DateRange[Now - Quantity[36, "Hours"], Now + Quantity[36, "Hours"], "Hour"];
TimelinePlot[
 DateInterval@*MinMax /@ KeySelect[GroupBy[dates, ResourceFunction["RelativeTimeString"]], StringFreeQ[DigitCharacter]]]
Out[33]=

Possible Issues (2) 

RelativeTimeString gives approximations with varying precision:

In[34]:=
ResourceFunction["RelativeTimeString"][Quantity[6.789, "Days"]]
Out[34]=
In[35]:=
ResourceFunction["RelativeTimeString"][-Quantity[67.89, "Days"]]
Out[35]=

Results may also be sensitive to the current time:

In[36]:=
ResourceFunction["RelativeTimeString"][Quantity[12.3456, "Hours"]]
Out[36]=

For more predictable and precise strings (at the cost of some readability), consider using SecondsToQuantity:

In[37]:=
relTimeString[q_Quantity] := With[{str = ToString[ResourceFunction["SecondsToQuantity"][Abs[q]]]}, If[TrueQ[Positive[q]], "in " <> str, str <> " ago"]];
In[38]:=
relTimeString[Quantity[6.789, "Days"]]
Out[38]=
In[39]:=
relTimeString[-Quantity[67.89, "Days"]]
Out[39]=
In[40]:=
relTimeString[Quantity[12.3456, "Hours"]]
Out[40]=

Values smaller than one second are considered insignificant:

In[41]:=
ResourceFunction["RelativeTimeString"][Quantity[0.999, "Seconds"]]
Out[41]=
In[42]:=
ResourceFunction["RelativeTimeString"][Quantity[0, "Seconds"]]
Out[42]=
In[43]:=
ResourceFunction["RelativeTimeString"][Quantity[1.0, "Seconds"]]
Out[43]=

If negative, the output reflects that it represents a time in the past:

In[44]:=
ResourceFunction["RelativeTimeString"][-Quantity[0.999, "Seconds"]]
Out[44]=

Neat Examples (1) 

Group files by relative dates:

In[45]:=
Column[KeyValueMap[Column[Prepend[#2, Style[#1, Bold]]] &, Map[FileNameTake, GroupBy[ReverseSortBy[
     FileNames[All, FileNameJoin[{$UserBasePacletsDirectory, "Repository"}]], FileDate], ResourceFunction["RelativeTimeString"]@*FileDate], {2}]], Spacings -> 1, Dividers -> Center]
Out[45]=

Version History

  • 1.0.0 – 27 June 2022

Related Resources

License Information