Browse Source

org-table: new defcustom `org-table-duration-custom-format'.

This allows to display the output of duration computations
as a fraction of days, hours, minutes or seconds.

Thanks to Daniel E. Doherty for bringing up this need.

* org-table.el (org-table-duration-custom-format): New
defcustom to select output format of durations computations.
(org-table-time-seconds-to-string): Use the new variable.
(org-table-eval-formula): Allow `t' as a flag, on top of `T'.
`t' will use the custom output format defined in
Bastien Guerry 6 years ago
2 changed files with 51 additions and 12 deletions
  1. 16 7
  2. 35 5

+ 16 - 7

@@ -2497,7 +2497,6 @@ n3 s3 e2 f4   @r{Normal, scientific, engineering, or fixed}
 D R           @r{angle modes: degrees, radians}
 F S           @r{fraction and symbolic modes}
 N             @r{interpret all fields as numbers, use 0 for non-numbers}
-T             @r{force text interpretation}
 E             @r{keep empty fields in ranges}
 L             @r{literal}
 @end example
@@ -2534,6 +2533,9 @@ Calc also contains a complete set of logical operations.  For example
 if($1<20,teen,string(""))  @r{"teen" if age $1 less than 20, else empty}
 @end example
+Note that you can also use two org-specific flags @code{T} and @code{t} for
+durations computations @ref{Durations and time values}.
 @node Formula syntax for Lisp, Durations and time values, Formula syntax for Calc, The spreadsheet
 @subsection Emacs Lisp forms as formulas
 @cindex Lisp forms, as table formulas
@@ -2569,6 +2571,7 @@ embed them in list or vector syntax.  Here are a few examples---note how the
 @subsection Durations and time values
 @cindex Duration, computing
 @cindex Time, computing
+@vindex org-table-duration-custom-format
 If you want to compute time values use the @code{T} flag, either in Calc
 formulas or Elisp formulas:
@@ -2578,15 +2581,21 @@ formulas or Elisp formulas:
   |  Task 1 |   Task 2 |    Total |
   |    2:12 |     1:47 | 03:59:00 |
-  | 3:02:20 | -2:07:00 | 00:55:20 |
-  #+TBLFM: $3=$1+$2;T
+  | 3:02:20 | -2:07:00 |     0.92 |
+  #+TBLFM: @@2$3=$1+$2;T::@@3$3=$1+$2;t
 @end group
 @end example
-Duration values are of the form @code{[HH:MM[:SS]}, where seconds are
-optional.  The computed duration will be displayed as @code{[HH:MM:SS}.
-Negative values can be manipulated as well, and integers are considered
-as seconds in addition and subtraction.
+Input duration values must be of the form @code{[HH:MM[:SS]}, where seconds
+are optional.  With the @code{T} flag, computed durations will be displayed
+as @code{[HH:MM:SS} (see the first formula above).  With the @code{t} flag,
+computed durations will be displayed according to the value of the variable
+@code{org-table-duration-custom-format}, which defaults to @code{'hours} and
+will display the result as a fraction of hours (see the second formula in the
+example above).
+Negative duration values can be manipulated as well, and integers will be
+considered as seconds in addition and subtraction.
 @node Field and range formulas, Column formulas, Durations and time values, The spreadsheet
 @subsection Field and range formulas

+ 35 - 5

@@ -231,6 +231,18 @@ relies on the variables to be present in the list."
   :group 'org-table-calculation
   :type 'plist)
+(defcustom org-table-duration-custom-format 'hours
+  "Format for the output of calc computations like $1+$2;t.
+The default value is 'hours, and will output the results as a
+number of hours.  Other allowed values are 'seconds, 'minutes and
+'days, and the output will be a fraction of seconds, minutes or
+  :group 'org-table-calculation
+  :type '(choice (symbol :tag "Seconds" 'seconds)
+		 (symbol :tag "Minutes" 'minutes)
+		 (symbol :tag "Hours  " 'hours)
+		 (symbol :tag "Days   " 'days)))
 (defcustom org-table-formula-evaluate-inline t
   "Non-nil means TAB and RET evaluate a formula in current table field.
 If the current field starts with an equal sign, it is assumed to be a formula
@@ -2412,6 +2424,12 @@ not overwrite the stored one."
 	      (setq fmt (replace-match "" t t fmt)))
 	    (if (string-match "T" fmt)
 		(setq duration t numbers t
+		      duration-output-format nil
+		      fmt (replace-match "" t t fmt)))
+	    (if (string-match "t" fmt)
+		(setq duration t 
+		      duration-output-format org-table-duration-custom-format
+		      numbers t
 		      fmt (replace-match "" t t fmt)))
 	    (if (string-match "N" fmt)
 		(setq numbers t
@@ -2523,12 +2541,14 @@ not overwrite the stored one."
 		       (error "#ERROR"))
 		  ev (if (numberp ev) (number-to-string ev) ev)
 		  ev (if duration (org-table-time-seconds-to-string
-				   (string-to-number ev)) ev))
+				   (string-to-number ev)
+				   duration-output-format) ev))
 	  (or (fboundp 'calc-eval)
 	      (error "Calc does not seem to be installed, and is needed to evaluate the formula"))
 	  (setq ev (calc-eval (cons form modes) (if numbers 'num))
 		ev (if duration (org-table-time-seconds-to-string
-				 (string-to-number ev)) ev)))
+				 (string-to-number ev)
+				 duration-output-format) ev)))
 	(when org-table-formula-debug
 	  (with-output-to-temp-buffer "*Substitution History*"
@@ -3237,9 +3257,19 @@ If S is a string representing a number, keep this number."
      (t (setq res (string-to-number s))))
     (number-to-string res)))
-(defun org-table-time-seconds-to-string (secs)
-  "Convert a number of seconds to a time string."
-  (org-format-seconds "%.2h:%.2m:%.2s" secs))
+(defun org-table-time-seconds-to-string (secs &optional output-format)
+  "Convert a number of seconds to a time string.
+If OUTPUT-FORMAT is non-nil, return a number of days, hours,
+minutes or seconds."
+  (cond ((eq output-format 'days)
+	 (format "%.3f" (/ (float secs) 86400)))
+	((eq output-format 'hours)
+	 (format "%.2f" (/ (float secs) 3600)))
+	((eq output-format 'minutes)
+	 (format "%.1f" (/ (float secs) 60)))
+	((eq output-format 'seconds)
+	 (format "%d" secs))
+	(t (org-format-seconds "%.2h:%.2m:%.2s" secs))))
 (defun org-table-fedit-convert-buffer (function)
   "Convert all references in this buffer, using FUNCTION."