How do I get the timing of an evaluation after it has already finished?

The case when the evaluation is finished

Some of my calculations take hours or even days, so I don't want to restart the entire evaluation just to add Timing[] to it.

If your code generates an Output Cell then you can find at least an upper bound of the evaluation time as the difference between last CellChangeTimes of the Output and Input Cells. It can be very close to the actual evaluation time if you edited the Input Cell just before evaluating it. In this case you can simply paste and evaluate the following code right after the Output Cell:

DateDifference @@ 
 Last /@ Flatten /@ 
   CurrentValue[PreviousCell[CellStyle -> #] & /@ {"Input", "Output"}, CellChangeTimes]

The case when the evaluation is still running

If the evaluation is still running you can try to set the EvaluationCompletionAction -> "ShowTiming" option before the evaluation has finished using The Options Inspector (Ctrl+Shift+O):

screenshot1

On the above screenshot this option is set on the $FrontEnd level ("Global Preferences"), but it is sufficient to set it only on the Notebook level for the Notebook where your evaluation is still running.

If you succeed in this, after finishing the evaluation you'll see the timing at the lower left corner of the notebook as shown in the answer by Jason B.:

screenshot2

Note that the timing includes the complete evaluation time, not the time spent after you have set the option! This proves that FrontEnd measures evaluation time even when the option isn't set, and hence it should be theoretically possible to get this information even after finishing the evaluation (but I don't know how).


Evaluate

SetOptions[$FrontEnd, EvaluationCompletionAction -> "ShowTiming"]

and then the evaluation time for the last evaluation will be shown in the lower left corner of the notebook:

enter image description here

Like many front end options, this setting is sticky. Set it once, and forget it; it also works across all versions of Mathematica installed.


This is not immediately an answer to OP's question but it does provide an initialization code which one can use in all her/his files so that they do not have to worry about forgetting inserting Timing commands.

One can simply define a new variable, say duration, and record the evaluation of each calculation to this variable in the background.

Following code is sufficient for that:

ClearAll[duration,durationTemp];
$PreRead := ((durationTemp = AbsoluteTime[]); Function[#]);
$Post := ((duration[$Line] = AbsoluteTime[] - durationTemp);Function[#]);

What it does is to record the absolute time when the input is given and calculate the time passed when the evaluation finishes. This is done for each calculation, and recorded with input line so that duration[n] gives the time spent for the calculation of Out[n].

As an example:

In[4]:= 1+1
Out[4]= 2
In[5]:= Pause[2]
In[6]:= Pause[5]
?duration

Global`duration
duration[3]=0.000351

duration[4]=0.000115

duration[5]=2.000717

duration[6]=5.000930

This is the most basic form; but one can modify duration function so that it counts in minutes instead of seconds, and it may garbage collect itself (say only keeps last 30 entries).

One can actually easily implement last idea using Associations. Specifically, below code does the same job using associations, and also only keeps last $n$ entries, where $n$ is set by durationLength:

ClearAll[duration, durationLength];
duration = <||>;
durationLength = 3;
$PreRead := (durationTemp = AbsoluteTime[]; Function[#]);
$Post := (If[KeyExistsQ[duration, $Line - durationLength], 
   KeyDropFrom[duration, $Line - durationLength]; 
   AssociateTo[duration, $Line -> AbsoluteTime[] - durationTemp], 
   AssociateTo[duration, $Line -> AbsoluteTime[] - durationTemp]]; 
   Function[#]);

As an example:

In[6]:= 1+1
Out[6]= 2
In[7]:=Pause[1]
In[8]:=Pause[2]
In[9]:=Pause[3]

?duration

Global`duration
duration=<|7->1.000416,8->2.001829,9->3.001157|>

Depending on the conditions, it may actually be a better idea to dedicate a stream to this and let it record the times to a file in the background. For example, one can use OpenWrite[] to create a temporary file per session, but I cannot imagine any scenario for which writing to a file is better than having this variable if the file is to be cleared after session ends (assuming session times are not extremely long). However, if one wants to keep a long record, then dedicating a file for this data and using OpenAppend to add these information to the same file may be useful. For example, if one has a 6 month long project and expects to have thousands of evaluation whose timing information happens to be useful data, then this may be relevant.