Function: timeclock-log-data

timeclock-log-data is a byte-compiled function defined in timeclock.el.gz.

Signature

(timeclock-log-data &optional RECENT-ONLY FILENAME)

Documentation

Return the contents of the timelog file, in a useful format.

If the optional argument RECENT-ONLY is non-nil, only show the contents from the last point where the time debt (see below) was set. If the optional argument FILENAME is non-nil, it is used instead of the file specified by timeclock-file.

A timelog contains data in the form of a single entry per line. Each entry has the form:

  CODE YYYY/MM/DD HH:MM:SS [COMMENT]

CODE is one of: b, h, i, o or O. COMMENT is optional when the code is i, o or O. The meanings of the codes are:

  b Set the current time balance, or "time debt". Useful when
     archiving old log data, when a debt must be carried forward.
     The COMMENT here is the number of seconds of debt.

  h Set the required working time for the given day. This must
     be the first entry for that day. The COMMENT in this case is
     the number of hours in this workday. Floating point amounts
     are allowed.

  i Clock in. The COMMENT in this case should be the name of the
     project worked on.

  o Clock out. COMMENT is unnecessary, but can be used to provide
     a description of how the period went, for example.

  O Final clock out. Whatever project was being worked on, it is
     now finished. Useful for creating summary reports.

When this function is called, it will return a data structure with the following format:

  (DEBT ENTRIES-BY-DAY ENTRIES-BY-PROJECT)

DEBT is a floating point number representing the number of seconds
“owed” before any work was done. For a new file (one without a b
entry), this is always zero.

The two entries lists have similar formats. They are both alists, where the CAR is the index, and the CDR is a list of time entries. For ENTRIES-BY-DAY, the CAR is a textual date string, of the form YYYY/MM/DD. For ENTRIES-BY-PROJECT, it is the name of the project worked on, or t for the default project.

The CDR for ENTRIES-BY-DAY is slightly different than for ENTRIES-BY-PROJECT. It has the following form:

  (DAY-LENGTH TIME-ENTRIES...)

For ENTRIES-BY-PROJECT, there is no DAY-LENGTH member. It is simply a list of TIME-ENTRIES. Note that if DAY-LENGTH is nil, it means whatever is the default should be used.

A TIME-ENTRY is a recorded time interval. It has the following format
(although generally one does not have to manipulate these entries
directly; see below):

  (BEGIN-TIME END-TIME PROJECT [COMMENT] [FINAL-P])

Anyway, suffice it to say there are a lot of structures. Typically the user is expected to manipulate to the day(s) or project(s) that he or she wants, at which point the following helper functions may be used:

  timeclock-day-required
  timeclock-day-length
  timeclock-day-debt
  timeclock-day-begin
  timeclock-day-end
  timeclock-day-span
  timeclock-day-break
  timeclock-day-projects

  timeclock-day-list-required
  timeclock-day-list-length
  timeclock-day-list-debt
  timeclock-day-list-begin
  timeclock-day-list-end
  timeclock-day-list-span
  timeclock-day-list-break
  timeclock-day-list-projects

  timeclock-entry-length
  timeclock-entry-begin
  timeclock-entry-end
  timeclock-entry-project
  timeclock-entry-comment

  timeclock-entry-list-length
  timeclock-entry-list-begin
  timeclock-entry-list-end
  timeclock-entry-list-span
  timeclock-entry-list-break
  timeclock-entry-list-projects

A few comments should make the use of the above functions obvious:

  required is the amount of time that must be spent during a day, or
  sequence of days, in order to have no debt.

  length is the actual amount of time that was spent.

  debt is the difference between required time and length. A
  negative debt signifies overtime.

  begin is the earliest moment at which work began.

  end is the final moment work was done.

  span is the difference between begin and end.

  break is the difference between span and length.

  project is the project that was worked on, and projects is a
  list of all the projects that were worked on during a given period.

  comment, where it applies, could mean anything.

There are a few more functions available, for locating day and entry lists:

  timeclock-day-alist LOG-DATA
  timeclock-project-alist LOG-DATA
  timeclock-current-debt LOG-DATA

See the documentation for the given function if more info is needed.

Source Code

;; Defined in /usr/src/emacs/lisp/calendar/timeclock.el.gz
(defun timeclock-log-data (&optional recent-only filename)
  "Return the contents of the timelog file, in a useful format.
If the optional argument RECENT-ONLY is non-nil, only show the contents
from the last point where the time debt (see below) was set.
If the optional argument FILENAME is non-nil, it is used instead of
the file specified by `timeclock-file.'

A timelog contains data in the form of a single entry per line.
Each entry has the form:

  CODE YYYY/MM/DD HH:MM:SS [COMMENT]

CODE is one of: b, h, i, o or O.  COMMENT is optional when the code is
i, o or O.  The meanings of the codes are:

  b  Set the current time balance, or \"time debt\".  Useful when
     archiving old log data, when a debt must be carried forward.
     The COMMENT here is the number of seconds of debt.

  h  Set the required working time for the given day.  This must
     be the first entry for that day.  The COMMENT in this case is
     the number of hours in this workday.  Floating point amounts
     are allowed.

  i  Clock in.  The COMMENT in this case should be the name of the
     project worked on.

  o  Clock out.  COMMENT is unnecessary, but can be used to provide
     a description of how the period went, for example.

  O  Final clock out.  Whatever project was being worked on, it is
     now finished.  Useful for creating summary reports.

When this function is called, it will return a data structure with the
following format:

  (DEBT ENTRIES-BY-DAY ENTRIES-BY-PROJECT)

DEBT is a floating point number representing the number of seconds
“owed” before any work was done.  For a new file (one without a `b'
entry), this is always zero.

The two entries lists have similar formats.  They are both alists,
where the CAR is the index, and the CDR is a list of time entries.
For ENTRIES-BY-DAY, the CAR is a textual date string, of the form
YYYY/MM/DD.  For ENTRIES-BY-PROJECT, it is the name of the project
worked on, or t for the default project.

The CDR for ENTRIES-BY-DAY is slightly different than for
ENTRIES-BY-PROJECT.  It has the following form:

  (DAY-LENGTH TIME-ENTRIES...)

For ENTRIES-BY-PROJECT, there is no DAY-LENGTH member.  It is simply a
list of TIME-ENTRIES.  Note that if DAY-LENGTH is nil, it means
whatever is the default should be used.

A TIME-ENTRY is a recorded time interval.  It has the following format
\(although generally one does not have to manipulate these entries
directly; see below):

  (BEGIN-TIME END-TIME PROJECT [COMMENT] [FINAL-P])

Anyway, suffice it to say there are a lot of structures.  Typically
the user is expected to manipulate to the day(s) or project(s) that he
or she wants, at which point the following helper functions may be
used:

  timeclock-day-required
  timeclock-day-length
  timeclock-day-debt
  timeclock-day-begin
  timeclock-day-end
  timeclock-day-span
  timeclock-day-break
  timeclock-day-projects

  timeclock-day-list-required
  timeclock-day-list-length
  timeclock-day-list-debt
  timeclock-day-list-begin
  timeclock-day-list-end
  timeclock-day-list-span
  timeclock-day-list-break
  timeclock-day-list-projects

  timeclock-entry-length
  timeclock-entry-begin
  timeclock-entry-end
  timeclock-entry-project
  timeclock-entry-comment

  timeclock-entry-list-length
  timeclock-entry-list-begin
  timeclock-entry-list-end
  timeclock-entry-list-span
  timeclock-entry-list-break
  timeclock-entry-list-projects

A few comments should make the use of the above functions obvious:

  `required' is the amount of time that must be spent during a day, or
  sequence of days, in order to have no debt.

  `length' is the actual amount of time that was spent.

  `debt' is the difference between required time and length.  A
  negative debt signifies overtime.

  `begin' is the earliest moment at which work began.

  `end' is the final moment work was done.

  `span' is the difference between begin and end.

  `break' is the difference between span and length.

  `project' is the project that was worked on, and `projects' is a
  list of all the projects that were worked on during a given period.

  `comment', where it applies, could mean anything.

There are a few more functions available, for locating day and entry
lists:

  timeclock-day-alist LOG-DATA
  timeclock-project-alist LOG-DATA
  timeclock-current-debt LOG-DATA

See the documentation for the given function if more info is needed."
  (let ((log-data (list 0.0 nil nil))
	(now (current-time))
	last-date-limited last-date-seconds last-date
	(line 0) last beg day entry event)
    (with-temp-buffer
      (insert-file-contents (or filename timeclock-file))
      (when recent-only
	(goto-char (point-max))
	(unless (re-search-backward "^b\\s-+" nil t)
	  (goto-char (point-min))))
      (while (or (setq event (timeclock-read-moment))
		 (and beg (not last)
		      (setq last t event (list "o" now))))
	(setq line (1+ line))
	(pcase (car event)
          ("b"
	   (setcar log-data (string-to-number (nth 2 event))))
	  ("h"
	   (setq last-date-limited (timeclock-time-to-date (cadr event))
		 last-date-seconds (* (string-to-number (nth 2 event))
				      3600.0)))
	  ("i"
	   (if beg
	       (error "Error in format of timelog file, line %d" line)
	     (setq beg t))
	   (setq entry (list (cadr event) nil
			     (and (> (length (nth 2 event)) 0)
				  (nth 2 event))))
	   (let ((date (timeclock-time-to-date (cadr event))))
	     (if (and last-date
		      (not (equal date last-date)))
		 (progn
		   (setcar (cdr log-data)
			   (cons (cons last-date day)
				 (cadr log-data)))
		   (setq day (list (and last-date-limited
					last-date-seconds))))
	       (unless day
		 (setq day (list (and last-date-limited
				      last-date-seconds)))))
	     (setq last-date date
		   last-date-limited nil)))
	  ((or "o" "O")
	   (if (not beg)
	       (error "Error in format of timelog file, line %d" line)
	     (setq beg nil))
	   (setcar (cdr entry) (cadr event))
	   (let ((desc (and (> (length (nth 2 event)) 0)
			    (nth 2 event))))
	     (if desc
		 (nconc entry (list (nth 2 event))))
	     (if (equal (car event) "O")
		 (nconc entry (if desc
				  (list t)
				(list nil t))))
	     (nconc day (list entry))
	     (setq desc (nth 2 entry))
	     (let ((proj (assoc desc (nth 2 log-data))))
	       (if (null proj)
		   (setcar (cddr log-data)
			   (cons (cons desc (list entry))
				 (nth 2 log-data)))
		 (nconc (cdr proj) (list entry)))))))
	(forward-line))
      (if day
	  (setcar (cdr log-data)
		  (cons (cons last-date day)
			(cadr log-data))))
      log-data)))