comparison lisp/calendar/timeclock.el @ 89909:68c22ea6027c

Sync to HEAD
author Kenichi Handa <handa@m17n.org>
date Fri, 16 Apr 2004 12:51:06 +0000
parents 375f2633d815
children 4c90ffeb71c5
comparison
equal deleted inserted replaced
89908:ee1402f7b568 89909:68c22ea6027c
1 ;;; timeclock.el --- mode for keeping track of how much you work 1 ;;; timeclock.el --- mode for keeping track of how much you work
2 2
3 ;; Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc. 3 ;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
4 4
5 ;; Author: John Wiegley <johnw@gnu.org> 5 ;; Author: John Wiegley <johnw@gnu.org>
6 ;; Created: 25 Mar 1999 6 ;; Created: 25 Mar 1999
7 ;; Version: 2.6 7 ;; Version: 2.6
8 ;; Keywords: calendar data 8 ;; Keywords: calendar data
58 ;; 58 ;;
59 ;; To cancel this modeline display at any time, just call 59 ;; To cancel this modeline display at any time, just call
60 ;; `timeclock-modeline-display' again. 60 ;; `timeclock-modeline-display' again.
61 61
62 ;; You may also want Emacs to ask you before exiting, if you are 62 ;; You may also want Emacs to ask you before exiting, if you are
63 ;; current working on a project. This can be done either by setting 63 ;; currently working on a project. This can be done either by setting
64 ;; `timeclock-ask-before-exiting' to t using M-x customize (this is 64 ;; `timeclock-ask-before-exiting' to t using M-x customize (this is
65 ;; the default), or by adding the following to your .emacs file: 65 ;; the default), or by adding the following to your .emacs file:
66 ;; 66 ;;
67 ;; (add-hook 'kill-emacs-query-functions 'timeclock-query-out) 67 ;; (add-hook 'kill-emacs-query-functions 'timeclock-query-out)
68 68
92 "*The length of a work period." 92 "*The length of a work period."
93 :type 'integer 93 :type 'integer
94 :group 'timeclock) 94 :group 'timeclock)
95 95
96 (defcustom timeclock-relative t 96 (defcustom timeclock-relative t
97 "*When reporting time, make it relative to `timeclock-workday'? 97 "*Whether to maken reported time relative to `timeclock-workday'.
98 For example, if the length of a normal workday is eight hours, and you 98 For example, if the length of a normal workday is eight hours, and you
99 work four hours on Monday, then the amount of time \"remaining\" on 99 work four hours on Monday, then the amount of time \"remaining\" on
100 Tuesday is twelve hours -- relative to an averaged work period of 100 Tuesday is twelve hours -- relative to an averaged work period of
101 eight hours -- or eight hours, non-relative. So relative time takes 101 eight hours -- or eight hours, non-relative. So relative time takes
102 into account any discrepancy of time under-worked or over-worked on 102 into account any discrepancy of time under-worked or over-worked on
105 :group 'timeclock) 105 :group 'timeclock)
106 106
107 (defcustom timeclock-get-project-function 'timeclock-ask-for-project 107 (defcustom timeclock-get-project-function 'timeclock-ask-for-project
108 "*The function used to determine the name of the current project. 108 "*The function used to determine the name of the current project.
109 When clocking in, and no project is specified, this function will be 109 When clocking in, and no project is specified, this function will be
110 called to determine what the current project to be worked on is. 110 called to determine what is the current project to be worked on.
111 If this variable is nil, no questions will be asked." 111 If this variable is nil, no questions will be asked."
112 :type 'function 112 :type 'function
113 :group 'timeclock) 113 :group 'timeclock)
114 114
115 (defcustom timeclock-get-reason-function 'timeclock-ask-for-reason 115 (defcustom timeclock-get-reason-function 'timeclock-ask-for-reason
116 "*A function used to determine the reason for clocking out. 116 "*A function used to determine the reason for clocking out.
117 When clocking out, and no reason is specified, this function will be 117 When clocking out, and no reason is specified, this function will be
118 called to determine what the reason is. 118 called to determine what is the reason.
119 If this variable is nil, no questions will be asked." 119 If this variable is nil, no questions will be asked."
120 :type 'function 120 :type 'function
121 :group 'timeclock) 121 :group 'timeclock)
122 122
123 (defcustom timeclock-get-workday-function nil 123 (defcustom timeclock-get-workday-function nil
124 "*A function used to determine the length of today's workday. 124 "*A function used to determine the length of today's workday.
125 The first time that a user clocks in each day, this function will be 125 The first time that a user clocks in each day, this function will be
126 called to determine what the length of the current workday is. If 126 called to determine what is the length of the current workday. If
127 the return value is nil, or equal to `timeclock-workday', nothing special 127 the return value is nil, or equal to `timeclock-workday', nothing special
128 will be done. If it is a quantity different from `timeclock-workday', 128 will be done. If it is a quantity different from `timeclock-workday',
129 however, a record will be output to the timelog file to note the fact that 129 however, a record will be output to the timelog file to note the fact that
130 that day has a different length from the norm." 130 that day has a length that is different from the norm."
131 :type '(choice (const nil) function) 131 :type '(choice (const nil) function)
132 :group 'timeclock) 132 :group 'timeclock)
133 133
134 (defcustom timeclock-ask-before-exiting t 134 (defcustom timeclock-ask-before-exiting t
135 "*If non-nil, ask if the user wants to clock out before exiting Emacs. 135 "*If non-nil, ask if the user wants to clock out before exiting Emacs.
136 This variable only has an effect if set with \\[customize]." 136 This variable only has effect if set with \\[customize]."
137 :set (lambda (symbol value) 137 :set (lambda (symbol value)
138 (if value 138 (if value
139 (add-hook 'kill-emacs-query-functions 'timeclock-query-out) 139 (add-hook 'kill-emacs-query-functions 'timeclock-query-out)
140 (remove-hook 'kill-emacs-query-functions 'timeclock-query-out)) 140 (remove-hook 'kill-emacs-query-functions 'timeclock-query-out))
141 (setq timeclock-ask-before-exiting value)) 141 (setq timeclock-ask-before-exiting value))
149 (defvar display-time-hook) 149 (defvar display-time-hook)
150 (defvar timeclock-modeline-display) 150 (defvar timeclock-modeline-display)
151 151
152 (defcustom timeclock-use-display-time t 152 (defcustom timeclock-use-display-time t
153 "*If non-nil, use `display-time-hook' for doing modeline updates. 153 "*If non-nil, use `display-time-hook' for doing modeline updates.
154 The advantage to this is that it means one less timer has to be set 154 The advantage of this is that one less timer has to be set running
155 running amok in Emacs' process space. The disadvantage is that it 155 amok in Emacs' process space. The disadvantage is that it requires
156 requires you to have `display-time' running. If you don't want to use 156 you to have `display-time' running. If you don't want to use
157 `display-time', but still want the modeline to show how much time is 157 `display-time', but still want the modeline to show how much time is
158 left, set this variable to nil. Changing the value of this variable 158 left, set this variable to nil. Changing the value of this variable
159 while timeclock information is being displayed in the modeline has no 159 while timeclock information is being displayed in the modeline has no
160 effect. You should call the function `timeclock-modeline-display' with 160 effect. You should call the function `timeclock-modeline-display' with
161 a positive argument to force an update." 161 a positive argument to force an update."
238 (defvar timeclock-discrepancy nil 238 (defvar timeclock-discrepancy nil
239 "A variable containing the time discrepancy before the last event. 239 "A variable containing the time discrepancy before the last event.
240 Normally, timeclock assumes that you intend to work for 240 Normally, timeclock assumes that you intend to work for
241 `timeclock-workday' seconds every day. Any days in which you work 241 `timeclock-workday' seconds every day. Any days in which you work
242 more or less than this amount is considered either a positive or 242 more or less than this amount is considered either a positive or
243 negative discrepancy. If you work in such a manner that the 243 a negative discrepancy. If you work in such a manner that the
244 discrepancy is always brought back to zero, then you will by 244 discrepancy is always brought back to zero, then you will by
245 definition have worked an average amount equal to `timeclock-workday' 245 definition have worked an average amount equal to `timeclock-workday'
246 each day.") 246 each day.")
247 247
248 (defvar timeclock-elapsed nil 248 (defvar timeclock-elapsed nil
252 worked so far today. Also, if `timeclock-relative' is nil, this value 252 worked so far today. Also, if `timeclock-relative' is nil, this value
253 will be the same as `timeclock-discrepancy'.") ; ? gm 253 will be the same as `timeclock-discrepancy'.") ; ? gm
254 254
255 (defvar timeclock-last-period nil 255 (defvar timeclock-last-period nil
256 "Integer representing the number of seconds in the last period. 256 "Integer representing the number of seconds in the last period.
257 Note that you shouldn't access this value, but should use the function 257 Note that you shouldn't access this value, but instead should use the
258 `timeclock-last-period' instead.") 258 function `timeclock-last-period'.")
259 259
260 (defvar timeclock-mode-string nil 260 (defvar timeclock-mode-string nil
261 "The timeclock string (optionally) displayed in the modeline. 261 "The timeclock string (optionally) displayed in the modeline.
262 The time is bracketed by <> if you are clocked in, otherwise by [].") 262 The time is bracketed by <> if you are clocked in, otherwise by [].")
263 263
341 \(non-nil, but not a number), 0 is assumed (working on a holiday or 341 \(non-nil, but not a number), 0 is assumed (working on a holiday or
342 weekend). *If not called interactively, ARG should be the number of 342 weekend). *If not called interactively, ARG should be the number of
343 _seconds_ worked today*. This feature only has effect the first time 343 _seconds_ worked today*. This feature only has effect the first time
344 this function is called within a day. 344 this function is called within a day.
345 345
346 PROJECT as the project being clocked into. If PROJECT is nil, and 346 PROJECT is the project being clocked into. If PROJECT is nil, and
347 FIND-PROJECT is non-nil -- or the user calls `timeclock-in' 347 FIND-PROJECT is non-nil -- or the user calls `timeclock-in'
348 interactively -- call the function `timeclock-get-project-function' to 348 interactively -- call the function `timeclock-get-project-function' to
349 discover the name of the project." 349 discover the name of the project."
350 (interactive 350 (interactive
351 (list (and current-prefix-arg 351 (list (and current-prefix-arg
444 (message status) 444 (message status)
445 status))) 445 status)))
446 446
447 ;;;###autoload 447 ;;;###autoload
448 (defun timeclock-change (&optional arg project) 448 (defun timeclock-change (&optional arg project)
449 "Change to working on a different project, by clocking in then out. 449 "Change to working on a different project.
450 With a prefix ARG, consider the previous project as having been 450 This clocks out of the current project, then clocks in on a new one.
451 finished at the time of changeover. PROJECT is the name of the last 451 With a prefix ARG, consider the previous project as finished at the
452 project you were working on." 452 time of changeover. PROJECT is the name of the last project you were
453 working on."
453 (interactive "P") 454 (interactive "P")
454 (timeclock-out arg) 455 (timeclock-out arg)
455 (timeclock-in nil project (interactive-p))) 456 (timeclock-in nil project (interactive-p)))
456 457
457 ;;;###autoload 458 ;;;###autoload
458 (defun timeclock-query-out () 459 (defun timeclock-query-out ()
459 "Ask the user before clocking out. 460 "Ask the user whether to clock out.
460 This is a useful function for adding to `kill-emacs-query-functions'." 461 This is a useful function for adding to `kill-emacs-query-functions'."
461 (and (equal (car timeclock-last-event) "i") 462 (and (equal (car timeclock-last-event) "i")
462 (y-or-n-p "You're currently clocking time, clock out? ") 463 (y-or-n-p "You're currently clocking time, clock out? ")
463 (timeclock-out)) 464 (timeclock-out))
464 ;; Unconditionally return t for `kill-emacs-query-functions'. 465 ;; Unconditionally return t for `kill-emacs-query-functions'.
548 (floor (mod seconds 65536)) 549 (floor (mod seconds 65536))
549 (floor (* (- seconds (ffloor seconds)) 1000000)))) 550 (floor (* (- seconds (ffloor seconds)) 1000000))))
550 551
551 ;; Should today-only be removed in favour of timeclock-relative? - gm 552 ;; Should today-only be removed in favour of timeclock-relative? - gm
552 (defsubst timeclock-when-to-leave (&optional today-only) 553 (defsubst timeclock-when-to-leave (&optional today-only)
553 "Return a time value representing at when the workday ends today. 554 "Return a time value representing the end of today's workday.
554 If TODAY-ONLY is non-nil, the value returned will be relative only to 555 If TODAY-ONLY is non-nil, the value returned will be relative only to
555 the time worked today, and not to past time." 556 the time worked today, and not to past time."
556 (timeclock-seconds-to-time 557 (timeclock-seconds-to-time
557 (- (timeclock-time-to-seconds (current-time)) 558 (- (timeclock-time-to-seconds (current-time))
558 (let ((discrep (timeclock-find-discrep))) 559 (let ((discrep (timeclock-find-discrep)))
563 0.0))))) 564 0.0)))))
564 565
565 ;;;###autoload 566 ;;;###autoload
566 (defun timeclock-when-to-leave-string (&optional show-seconds 567 (defun timeclock-when-to-leave-string (&optional show-seconds
567 today-only) 568 today-only)
568 "Return a string representing at what time the workday ends today. 569 "Return a string representing the end of today's workday.
569 This string is relative to the value of `timeclock-workday'. If 570 This string is relative to the value of `timeclock-workday'. If
570 SHOW-SECONDS is non-nil, the value printed/returned will include 571 SHOW-SECONDS is non-nil, the value printed/returned will include
571 seconds. If TODAY-ONLY is non-nil, the value returned will be 572 seconds. If TODAY-ONLY is non-nil, the value returned will be
572 relative only to the time worked today, and not to past time." 573 relative only to the time worked today, and not to past time."
573 ;; Should today-only be removed in favour of timeclock-relative? - gm 574 ;; Should today-only be removed in favour of timeclock-relative? - gm
850 archiving old log data, when a debt must be carried forward. 851 archiving old log data, when a debt must be carried forward.
851 The COMMENT here is the number of seconds of debt. 852 The COMMENT here is the number of seconds of debt.
852 853
853 h Set the required working time for the given day. This must 854 h Set the required working time for the given day. This must
854 be the first entry for that day. The COMMENT in this case is 855 be the first entry for that day. The COMMENT in this case is
855 the number of hours that must be worked. Floating point 856 the number of hours in this workday. Floating point amounts
856 amounts are allowed. 857 are allowed.
857 858
858 i Clock in. The COMMENT in this case should be the name of the 859 i Clock in. The COMMENT in this case should be the name of the
859 project worked on. 860 project worked on.
860 861
861 o Clock out. COMMENT is unnecessary, but can be used to provide 862 o Clock out. COMMENT is unnecessary, but can be used to provide
1142 (setcar (nthcdr 1 decoded) 0) 1143 (setcar (nthcdr 1 decoded) 0)
1143 (setcar (nthcdr 2 decoded) 0) 1144 (setcar (nthcdr 2 decoded) 0)
1144 (apply 'encode-time decoded))) 1145 (apply 'encode-time decoded)))
1145 1146
1146 (defun timeclock-geometric-mean (l) 1147 (defun timeclock-geometric-mean (l)
1147 "Compute the geometric mean of the list L." 1148 "Compute the geometric mean of the values in the list L."
1148 (let ((total 0) 1149 (let ((total 0)
1149 (count 0)) 1150 (count 0))
1150 (while l 1151 (while l
1151 (setq total (+ total (car l)) 1152 (setq total (+ total (car l))
1152 count (1+ count) 1153 count (1+ count)
1156 0))) 1157 0)))
1157 1158
1158 (defun timeclock-generate-report (&optional html-p) 1159 (defun timeclock-generate-report (&optional html-p)
1159 "Generate a summary report based on the current timelog file. 1160 "Generate a summary report based on the current timelog file.
1160 By default, the report is in plain text, but if the optional argument 1161 By default, the report is in plain text, but if the optional argument
1161 HTML-P is non-nil html markup is added." 1162 HTML-P is non-nil, HTML markup is added."
1162 (interactive) 1163 (interactive)
1163 (let ((log (timeclock-log-data)) 1164 (let ((log (timeclock-log-data))
1164 (today (timeclock-day-base))) 1165 (today (timeclock-day-base)))
1165 (if html-p (insert "<p>")) 1166 (if html-p (insert "<p>"))
1166 (insert "Currently ") 1167 (insert "Currently ")
1361 ;; make sure we know the list of reasons, projects, and have computed 1362 ;; make sure we know the list of reasons, projects, and have computed
1362 ;; the last event and current discrepancy. 1363 ;; the last event and current discrepancy.
1363 (if (file-readable-p timeclock-file) 1364 (if (file-readable-p timeclock-file)
1364 (timeclock-reread-log)) 1365 (timeclock-reread-log))
1365 1366
1367 ;;; arch-tag: a0be3377-deb6-44ec-b9a2-a7be28436a40
1366 ;;; timeclock.el ends here 1368 ;;; timeclock.el ends here