Skip to content

Commit 7a39863

Browse files
committed
dates and time: show more of local-time
1 parent 44e35ae commit 7a39863

File tree

1 file changed

+199
-19
lines changed

1 file changed

+199
-19
lines changed

dates_and_times.md

Lines changed: 199 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -234,25 +234,53 @@ the somewhat limited functionalities as defined by the standard.
234234

235235
In particular, it can
236236

237-
- print timestamp in various standard or custom formats (e.g. RFC1123 or RFC3339)
237+
- print timestamps in various standard or custom formats (e.g. RFC1123 or RFC3339)
238238
- parse timestrings,
239239
- perform time arithmetic,
240-
- convert Unix times, timestamps, and universal times to and fro.
240+
- convert Unix times, timestamps, and universal times to and from.
241241

242-
For example, here is a function that returns Unix times as a human readable string:
242+
We present below what we find the most useful functions. See its [manual](https://common-lisp.net/project/local-time/manual.html) for the full details.
243+
244+
It is available in Quicklisp:
243245

244246
~~~lisp
245-
(defun unix-time-to-human-string (unix-time)
246-
(local-time:format-timestring
247-
nil
248-
(local-time:unix-to-timestamp unix-time)
249-
:format local-time:+asctime-format+))
247+
CL-USER> (ql:quickload "local-time")
248+
~~~
249+
250+
### Create timestamps (encode-timestamp, universal-to-timestamp)
251+
252+
Create a timestamp with `encode-timestamp`, giving it its number of nanoseconds, seconds, minutes, days, months and years:
253+
254+
~~~lisp
255+
(local-time:encode-timestamp 0 0 0 0 1 1 1984)
256+
@1984-01-01T00:00:00.000000+01:00
257+
~~~
258+
259+
The complete signature is:
260+
261+
**encode-timestamp** nsec sec minute hour day month year &key timezone offset into
262+
263+
The offset is the number of seconds offset from UTC of the locale. If offset is not specified, the offset will be guessed from the timezone. If a timestamp is passed as the into argument, its value will be set and that timestamp will be returned. Otherwise, a new timestamp is created.
264+
265+
Create a timestamp from a universal time with `universal-to-timestamp`:
266+
267+
~~~lisp
268+
(get-universal-time)
269+
3833588757
270+
(local-time:universal-to-timestamp (get-universal-time))
271+
@2021-06-25T07:45:59.000000+02:00
250272
~~~
251273

252-
See the [manual](https://common-lisp.net/project/local-time/manual.html) for
253-
the full details.
274+
You can also parse a human-readable time string:
254275

255-
### Get today's date
276+
~~~lisp
277+
(local-time:parse-timestring "1984-01-01")
278+
@1984-01-01T01:00:00.000000+01:00
279+
~~~
280+
281+
But see the section on parsing timestrings for more.
282+
283+
### Get today's date (now, today)
256284

257285
Use `now` or `today`:
258286

@@ -266,8 +294,141 @@ Use `now` or `today`:
266294

267295
"today" is the midnight of the current day in the UTC zone.
268296

297+
To compute "yesterday" and "tomorrow", see below.
298+
299+
### Add or substract times (timestamp+, timestamp-)
269300

270-
### Formatting time strings
301+
Use `timestamp+` and `timestamp-`. Each takes 3 arguments: a date, a number and a unit (and optionally a timezone and an offset):
302+
303+
~~~lisp
304+
(local-time:now)
305+
@2021-06-25T07:19:39.836973+02:00
306+
307+
(local-time:timestamp+ (local-time:now) 1 :day)
308+
@2021-06-26T07:16:58.086226+02:00
309+
310+
(local-time:timestamp- (local-time:now) 1 :day)
311+
@2021-06-24T07:17:02.861763+02:00
312+
~~~
313+
314+
The available units are `:sec :minute :hour :day :year`.
315+
316+
This operation is also possible with `adjust-timestamp`, which can do a bit more as we'll see right in the next section (it can do many operations at once).
317+
318+
~~~lisp
319+
(local-time:timestamp+ (today) 3 :day)
320+
@2021-06-28T02:00:00.000000+02:00
321+
322+
(local-time:adjust-timestamp (today) (offset :day 3))
323+
@2021-06-28T02:00:00.000000+02:00
324+
~~~
325+
326+
Here's `yesterday` and `tomorrow` defined from `today`:
327+
328+
~~~lisp
329+
(defun yesterday ()
330+
"Returns a timestamp representing the day before today."
331+
(timestamp- (today) 1 :day))
332+
333+
(defun tomorrow ()
334+
"Returns a timestamp representing the day after today."
335+
(timestamp+ (today) 1 :day))
336+
~~~
337+
338+
### Modify timestamps with any offset (adjust-timestamp)
339+
340+
`adjust-timestamp`'s first argument is the timestamp we operate on, and then it accepts a full `&body changes` where a "change" is in the form `(offset :part value)`:
341+
342+
Please point to the previous Monday:
343+
344+
~~~lisp
345+
(local-time:adjust-timestamp (today) (offset :day-of-week :monday))
346+
@2021-06-21T02:00:00.000000+02:00
347+
~~~
348+
349+
We can apply many changes at once. Travel in time:
350+
351+
~~~lisp
352+
(local-time:adjust-timestamp (today)
353+
(offset :day 3)
354+
(offset :year 110)
355+
(offset :month -1))
356+
@2131-05-28T02:00:00.000000+01:00
357+
~~~
358+
359+
There is a destructive version, `adjust-timestamp!`.
360+
361+
362+
### Compare timestamps (timestamp<, timestamp<, timestamp= …)
363+
364+
These should be self-explanatory.
365+
366+
~~~lisp
367+
timestamp< time-a time-b
368+
timestamp<= time-a time-b
369+
timestamp> time-a time-b
370+
timestamp>= time-a time-b
371+
timestamp= time-a time-b
372+
timestamp/= time-a time-b
373+
~~~
374+
375+
### Find the minimum or maximum timestamp
376+
377+
Use `timestamp-minimum` and `timestamp-maximum`. They accept any number of arguments.
378+
379+
~~~lisp
380+
(local-time:timestamp-minimum (local-time:today)
381+
(local-time:timestamp- (local-time:today) 100 :year))
382+
@1921-06-25T02:00:00.000000+01:00
383+
~~~
384+
385+
If you have a list of timestamps, use `(apply #'timestamp-minimum <your list of timestamps>)`.
386+
387+
### Maximize or minimize a timestamp according to a time unit (timestamp-maximize-part, timestamp-minimize-part)
388+
389+
We can answer quite a number of questions with this handy function.
390+
391+
Here's an example: please give me the last day of this month:
392+
393+
~~~lisp
394+
(let ((in-february (local-time:parse-timestring "1984-02-01")))
395+
(local-time:timestamp-maximize-part in-february :day))
396+
397+
@1984-02-29T23:59:59.999999+01:00
398+
~~~
399+
400+
401+
### Querying timestamp objects (get the day, the day of week, the days in month…)
402+
403+
Use:
404+
405+
~~~lisp
406+
timestamp-[year, month, day, hour, minute, second, millisecond, microsecond,
407+
day-of-week (starts at 0 for sunday),
408+
millenium, century, decade]
409+
~~~
410+
411+
Get all the values at once with `decode-timestamp`.
412+
413+
Bind a variable to a value of your choice with this convenient macro:
414+
415+
~~~lisp
416+
(local-time:with-decoded-timestamp (:hour h)
417+
(now)
418+
(print h))
419+
420+
8
421+
8
422+
~~~
423+
424+
You can of course bind each time unit (`:sec :minute :day`) to its variable, in any order.
425+
426+
See also `(days-in-month <month> <year>)`.
427+
428+
429+
### Formatting time strings (format, format-timestring, +iso-8601-format+)
430+
431+
local-time's date representation starts with `@`. We can `format` them as usual, with the aesthetic directive for instance, to get a usual date representation.
271432

272433
~~~lisp
273434
(local-time:now)
@@ -279,7 +440,7 @@ Use `now` or `today`:
279440
"2019-11-13T18:08:23.312664+01:00"
280441
~~~
281442

282-
`format-timestring` takes a stream argument like `format`:
443+
We can use `format-timestring`, which can be used like `format` (thus it takes a stream as first argument):
283444

284445
~~~lisp
285446
(local-time:format-timestring nil (local-time:now))
@@ -288,9 +449,10 @@ Use `now` or `today`:
288449

289450
Here `nil` returns a new string. `t` would print to `*standard-output*`.
290451

291-
It also accepts a `:format` argument. Its default value is
292-
`+iso-8601-format+`, with the output shown above. The
293-
`+rfc3339-format+` format defaults to it.
452+
But `format-timestring` also accepts a `:format` argument. We can use predefined date formats as well as give our own in s-expression friendly way (see next section).
453+
454+
Its default value is
455+
`+iso-8601-format+`, with the output shown above. The `+rfc3339-format+` format defaults to it.
294456

295457
With `+rfc-1123-format+`:
296458

@@ -314,7 +476,21 @@ With `+iso-week-date-format+`:
314476
~~~
315477

316478

317-
### Defining format strings
479+
Putting all this together, here is a function that returns Unix times as a human readable string:
480+
481+
~~~lisp
482+
(defun unix-time-to-human-string (unix-time)
483+
(local-time:format-timestring
484+
nil
485+
(local-time:unix-to-timestamp unix-time)
486+
:format local-time:+asctime-format+))
487+
488+
(unix-time-to-human-string (get-universal-time))
489+
"Mon Jun 25 06:46:49 2091"
490+
~~~
491+
492+
493+
### Defining format strings (format-timestring (:year "-" :month "-" :day))
318494

319495
We can pass a custom `:format` argument to `format-timestring`.
320496

@@ -326,7 +502,7 @@ The syntax consists of a list made of symbols with special meanings
326502
"2019-11-13"
327503
~~~
328504

329-
The list of symbols is available in the documentation: https://common-lisp.net/project/local-time/manual.html#Parsing-and-Formatting
505+
The list of symbols is available in the documentation: [https://common-lisp.net/project/local-time/manual.html#Parsing-and-Formatting](https://common-lisp.net/project/local-time/manual.html#Parsing-and-Formatting)
330506

331507
There are `:year :month :day :weekday :hour :min :sec :msec`, long and
332508
short notations ("Monday", "Mo."), gmt offset, timezone markers and
@@ -342,7 +518,7 @@ The `+rfc-1123-format+` itself is defined like this:
342518
"See the RFC 1123 for the details about the possible values of the timezone field.")
343519
~~~
344520

345-
We see the form `(:day 2)`: the 2 is for padding, to ensure that the
521+
We see the form `(:day 2)`: the 2 is for **padding**, to ensure that the
346522
day is printed with two digits (not only `1`, but `01`). There could be
347523
an optional third argument, the character with which to fill the
348524
padding (by default, `#\0`).
@@ -411,3 +587,7 @@ local-time library:
411587
(local-time:universal-to-timestamp *)
412588
;; @2019-11-13T19:13:15.000000+01:00
413589
~~~
590+
591+
### Misc
592+
593+
To find out if it's Alice anniversary, use `timestamp-whole-year-difference time-a time-b`.

0 commit comments

Comments
 (0)