The Common Lisp epoch begins at 00:00 on January 1, 1900, GMT. get-universal-time returns a universal time, defined as the number of seconds elapsed since then.
The Unix epoch begins at 00:00 on January 1, 1970, GMT. time() returns the number of seconds elapsed since then.
It’s easy to get the difference between a Common Lisp universal time and a Unix epoch timestamp:
* (encode-universal-time 0 0 0 1 1 1970 0)
When working with Unix epoch timestamp data, it’s easy to write conversion functions:
(encode-universal-time 0 0 0 1 1 1970 0))
(defun universal-to-unix-time (universal-time)
(- universal-time *unix-epoch-difference*))
(defun unix-to-universal-time (unix-time)
(+ unix-time *unix-epoch-difference*))
(defun get-unix-time ()
Comparing CL output to the shell:
$ date +%s
(My CL implementation doesn’t constant-fold the call to encode-universal-time. Bummer.)
I sometimes see a question like this: “I have a list of things and I want to see if they’re all true, so how can I apply ‘and’ to it?” Since and is a macro, it can’t be applied, but there are standard functions that can answer the question instead.
(every #’identity list) will return nil as soon as it encounters any nil entries in list, and true if no items are nil. (notany #’null list) is equivalent.
Sometimes you know in advance how you want to change control flow in a loop. Other times you might want to defer that decision by offering a restart. For example, here’s a loop with a pair of with-simple-restarts:
(with-simple-restart (stop-processing "Stop processing users")
(dolist (user (pending-user-list))
(with-simple-restart (skip "Skip user ~A" user)
If there is a problem processing users, you might get something in the debugger that looks like this:
Could not find home directory for "nancy"
[Condition of type SIMPLE-ERROR]
0: [SKIP] Skip user nancy
1: [STOP-PROCESSING] Stop processing users
You can then interactively choose which action to take, depending on what’s most appropriate for the condition at hand.
(You can also choose restarts non-interactively. That’s a tip for another day.)
Producing “pretty” output can be time consuming. Some implementations do a lot of work to determine whether to e.g. break lines when printing with functions like print and format.
If printing is a bottleneck and aesthetic output isn’t required, binding or setting *print-pretty* to NIL can significantly improve output speed for some implementations.
To assign the multiple return values of a function to multiple variables, you could use this:
(multiple-value-setq (whole partial) (truncate x 1024))
(setf values) is more general, and works on places:
(setf (values whole partial) (truncate x 1024))
(setf (values (aref v 0) (aref v 1)) (truncate x 1024))
The “do” macros (do, do*, dolist, and dotimes) have bodies that act like tagbody. You can put go tags anywhere in the body and use go to jump to them from arbitrary places. This can be useful for skipping, retrying, or otherwise changing the flow of iteration.
(dolist (users (get-user-list))
The numeric comparison functions =, /=, <, <=, >, and >= can take more than two arguments. This is handy to e.g. check if several variables have monotonically increasing numeric value:
(< a b c d)
For numbers in a sufficiently short list, apply does the trick:
(apply #'< list)
Non-numeric comparison functions generally take exactly two objects to compare, so e.g. (string= x y z) is invalid, and for a list of three or more objects, you can’t just apply the function to the list.
However, you can work your way through the list and perform pairwise comparison with every. For example, to see if all the strings in a list are string=:
(every #'string= list (rest list))
Note that /= is special; the following calls are not equivalent:
* (apply #'/= list)
* (every #'/= list (rest list))
parse-integer takes :start and :end arguments, so you don’t have to extract integer subsequences from strings to pass them to parse-integer. For example, to parse date strings that look like “2011-10-01” into year, month, and date integers, you can do this:
(defun parse-date (string)
"Parse a date string in the form YYYY-MM-DD and return the
year, month, and day as multiple values."
(values (parse-integer string :start 0 :end 4)
(parse-integer string :start 5 :end 7)
(parse-integer string :start 8 :end 10)))
If you have the character #\7 and you want the integer 7, you might be tempted to use (parse-integer (string char)) or even this ASCII-oriented technique:
(- (char-int char) (char-int #\0))
While the former is specified to give the right answer, the latter will only work by coincidence. The spec does discuss character ordering, but it makes no guarantees about the values returned by char-int or char-code.
What to use, then? digit-char-p not only returns a true value if its first argument represents a digit, the true value it returns is the integer value of that digit:
* (digit-char-p #\7)
It also works with other radixes:
* (digit-char-p #\a 16)
If the character is not a digit, digit-char-p returns nil.
You can break up long format control strings with ~ at the end of a line. For example:
* (format t "It was the best of times, ~
it was the worst of times.")
It was the best of times, it was the worst of times.
The ~, newline, and all whitespace following the newline are removed from the output, so you can align the continued control string with the previous line.
The : and @ modifiers have additional meaning:
With a :, the newline is ignored, but any following whitespace is left in place. With an @, the newline is left in place, but any following whitespace is ignored.