582 lines
24 KiB
HTML
582 lines
24 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta name="generator" content=
|
||
"HTML Tidy for HTML5 for Linux version 5.2.0">
|
||
<title>Dates and Times</title>
|
||
<meta charset="utf-8">
|
||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||
<meta name="viewport" content=
|
||
"width=device-width, initial-scale=1">
|
||
<link rel="stylesheet" href=
|
||
"assets/style.css">
|
||
<script type="text/javascript" src=
|
||
"assets/highlight-lisp.js">
|
||
</script>
|
||
<script type="text/javascript" src=
|
||
"assets/jquery-3.2.1.min.js">
|
||
</script>
|
||
<script type="text/javascript" src=
|
||
"assets/jquery.toc/jquery.toc.min.js">
|
||
</script>
|
||
<script type="text/javascript" src=
|
||
"assets/toggle-toc.js">
|
||
</script>
|
||
|
||
<link rel="stylesheet" href=
|
||
"assets/github.css">
|
||
|
||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||
</head>
|
||
<body>
|
||
<h1 id="title-xs"><a href="index.html">The Common Lisp Cookbook</a> – Dates and Times</h1>
|
||
<div id="logo-container">
|
||
<a href="index.html">
|
||
<img id="logo" src="assets/cl-logo-blue.png"/>
|
||
</a>
|
||
|
||
<div id="searchform-container">
|
||
<form onsubmit="duckSearch()" action="javascript:void(0)">
|
||
<input id="searchField" type="text" value="" placeholder="Search...">
|
||
</form>
|
||
</div>
|
||
|
||
<div id="toc-container" class="toc-close">
|
||
<div id="toc-title">Table of Contents</div>
|
||
<ul id="toc" class="list-unstyled"></ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="content-container">
|
||
<h1 id="title-non-xs"><a href="index.html">The Common Lisp Cookbook</a> – Dates and Times</h1>
|
||
|
||
<!-- Announcement we can keep for 1 month or more. I remove it and re-add it from time to time. -->
|
||
<p class="announce">
|
||
📹 <a href="https://www.udemy.com/course/common-lisp-programming/?couponCode=6926D599AA-LISP4ALL">NEW! Learn Lisp in videos and support our contributors with this 40% discount.</a>
|
||
</p>
|
||
<p class="announce-neutral">
|
||
📕 <a href="index.html#download-in-epub">Get the EPUB and PDF</a>
|
||
</p>
|
||
|
||
|
||
<div id="content"
|
||
<p>Common Lisp provides two different ways of looking at time: universal time,
|
||
meaning time in the “real world”, and run time, meaning time as seen by your
|
||
computer’s CPU. We will deal with both of them separately.</p>
|
||
|
||
<p><a name="univ"></a></p>
|
||
|
||
<h2 id="built-in-time-functions">Built-in time functions</h2>
|
||
|
||
<h3 id="universal-time">Universal Time</h3>
|
||
|
||
<p>Universal time is represented as the number of seconds that have elapsed since
|
||
00:00 of January 1, 1900 in the GMT time zone. The function
|
||
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_get_un.htm"><code>get-universal-time</code></a>
|
||
returns the current universal time:</p>
|
||
|
||
<pre><code class="language-lisp">CL-USER> (get-universal-time)
|
||
3220993326
|
||
</code></pre>
|
||
|
||
<p>Of course this value is not very readable, so you can use the function
|
||
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_dec_un.htm"><code>decode-universal-time</code></a>
|
||
to turn it into a “calendar time” representation:</p>
|
||
|
||
<pre><code class="language-lisp">CL-USER> (decode-universal-time 3220993326)
|
||
6
|
||
22
|
||
19
|
||
25
|
||
1
|
||
2002
|
||
4
|
||
NIL
|
||
5
|
||
</code></pre>
|
||
|
||
<p><strong>NB</strong>: in the next section we’ll use the <code>local-time</code> library to get more user-friendy functions, such as <code>(local-time:universal-to-timestamp (get-universal-time))</code> which returns <code>@2021-06-25T09:16:29.000000+02:00</code>.</p>
|
||
|
||
<p>This call to <code>decode-universal-time</code> returns nine values: <code>seconds, minutes, hours, day, month, year, day of
|
||
the week, daylight savings time flag and time zone</code>. Note that the day of the
|
||
week is represented as an integer in the range 0..6 with 0 being Monday and 6
|
||
being Sunday. Also, the <strong>time zone</strong> is represented as the number of hours you need
|
||
to add to the current time in order to get GMT time.</p>
|
||
|
||
<p>So in this example the
|
||
decoded time would be <code>19:22:06 of Friday, January 25, 2002</code>, in the EST time
|
||
zone, with no daylight savings in effect. This, of course, relies on the
|
||
computer’s own clock, so make sure that it is set correctly (including the time
|
||
zone you are in and the DST flag). As a shortcut, you can use
|
||
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_get_un.htm"><code>get-decoded-time</code></a>
|
||
to get the calendar time representation of the current time directly:</p>
|
||
|
||
<pre><code class="language-lisp">CL-USER> (get-decoded-time)
|
||
</code></pre>
|
||
|
||
<p>is equivalent to</p>
|
||
|
||
<pre><code class="language-lisp">CL-USER> (decode-universal-time (get-universal-time))
|
||
</code></pre>
|
||
|
||
<p>Here is an example of how to use these functions in a program (but frankly, use the <code>local-time</code> library instead):</p>
|
||
|
||
<pre><code class="language-lisp">CL-USER> (defconstant *day-names*
|
||
'("Monday" "Tuesday" "Wednesday"
|
||
"Thursday" "Friday" "Saturday"
|
||
"Sunday"))
|
||
*DAY-NAMES*
|
||
|
||
CL-USER> (multiple-value-bind
|
||
(second minute hour day month year day-of-week dst-p tz)
|
||
(get-decoded-time)
|
||
(format t "It is now ~2,'0d:~2,'0d:~2,'0d of ~a, ~d/~2,'0d/~d (GMT~@d)"
|
||
hour
|
||
minute
|
||
second
|
||
(nth day-of-week *day-names*)
|
||
month
|
||
day
|
||
year
|
||
(- tz)))
|
||
It is now 17:07:17 of Saturday, 1/26/2002 (GMT-5)
|
||
</code></pre>
|
||
|
||
<p>Of course the call to <code>get-decoded-time</code> above could be replaced by
|
||
<code>(decode-universal-time n)</code>, where n is any integer number, to print an
|
||
arbitrary date. You can also go the other way around: the function
|
||
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_encode.htm"><code>encode-universal-time</code></a>
|
||
lets you encode a calendar time into the corresponding universal time. This
|
||
function takes six mandatory arguments (seconds, minutes, hours, day, month and
|
||
year) and one optional argument (the time zone) and it returns a universal time:</p>
|
||
|
||
<pre><code class="language-lisp">CL-USER> (encode-universal-time 6 22 19 25 1 2002)
|
||
3220993326
|
||
</code></pre>
|
||
|
||
<p>Note that the result is automatically adjusted for daylight savings time if the time zone is not supplied. If it is supplied, than Lisp assumes that the specified time zone already accounts for daylight savings time, and no adjustment is performed.</p>
|
||
|
||
<p>Since universal times are simply numbers, they are easier and safer to manipulate than calendar times. Dates and times should always be stored as universal times if possible, and only converted to string representations for output purposes. For example, it is straightforward to know which of two dates came before the other, by simply comparing the two corresponding universal times with <code><</code>.</p>
|
||
|
||
<h3 id="internal-time">Internal Time</h3>
|
||
|
||
<p>Internal time is the time as measured by your Lisp environment, using your computer’s clock. It differs from universal time in three important respects. First, internal time is not measured starting from a specified point in time: it could be measured from the instant you started your Lisp, from the instant you booted your machine, or from any other arbitrary time point in the past. As we will see shortly, the absolute value of an internal time is almost always meaningless; only differences between internal times are useful. The second difference is that internal time is not measured in seconds, but in a (usually smaller) unit whose value can be deduced from <a href="http://www.lispworks.com/documentation/HyperSpec/Body/v_intern.htm"><code>internal-time-units-per-second</code></a>:</p>
|
||
|
||
<pre><code class="language-lisp">CL-USER> internal-time-units-per-second
|
||
1000
|
||
</code></pre>
|
||
|
||
<p>This means that in the Lisp environment used in this example, internal time is measured in milliseconds.</p>
|
||
|
||
<p>Finally, what is being measured by the “internal time” clock? There are actually two different internal time clocks in your Lisp:</p>
|
||
|
||
<ul>
|
||
<li>one of them measures the passage of “real” time (the same time that universal time measures, but in different units), and</li>
|
||
<li>the other one measures the passage of CPU time, that is, the time your CPU spends doing actual computation for the current Lisp process.</li>
|
||
</ul>
|
||
|
||
<p>On most modern computers these two times will be different, since your CPU will never be entirely dedicated to your program (even on single-user machines, the CPU has to devote part of its time to processing interrupts, performing I/O, etc). The two functions used to retrieve internal times are called <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_get_in.htm"><code>get-internal-real-time</code></a> and <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_get__1.htm"><code>get-internal-run-time</code></a> respectively. Using them, we can solve the above problem about measuring a function’s run time, which is what the <code>time</code> built-in macro does.</p>
|
||
|
||
<pre><code class="language-lisp">CL-USER> (time (sleep 1))
|
||
Evaluation took:
|
||
1.000 seconds of real time
|
||
0.000049 seconds of total run time (0.000044 user, 0.000005 system)
|
||
0.00% CPU
|
||
2,594,553,447 processor cycles
|
||
0 bytes consed
|
||
</code></pre>
|
||
|
||
<h2 id="the-local-time-library">The <code>local-time</code> library</h2>
|
||
|
||
<p>The <a href="https://common-lisp.net/project/local-time/">local-time</a> library (<a href="https://github.com/dlowe-net/local-time/">GitHub</a>) is a very handy extension to
|
||
the somewhat limited functionalities as defined by the standard.</p>
|
||
|
||
<p>In particular, it can</p>
|
||
|
||
<ul>
|
||
<li>print timestamps in various standard or custom formats (e.g. RFC1123 or RFC3339)</li>
|
||
<li>parse timestrings,</li>
|
||
<li>perform time arithmetic,</li>
|
||
<li>convert Unix times, timestamps, and universal times to and from.</li>
|
||
</ul>
|
||
|
||
<p>We present below what we find the most useful functions. See its <a href="https://common-lisp.net/project/local-time/manual.html">manual</a> for the full details.</p>
|
||
|
||
<p>It is available in Quicklisp:</p>
|
||
|
||
<pre><code class="language-lisp">CL-USER> (ql:quickload "local-time")
|
||
</code></pre>
|
||
|
||
<h3 id="create-timestamps-encode-timestamp-universal-to-timestamp">Create timestamps (encode-timestamp, universal-to-timestamp)</h3>
|
||
|
||
<p>Create a timestamp with <code>encode-timestamp</code>, giving it its number of nanoseconds, seconds, minutes, days, months and years:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:encode-timestamp 0 0 0 0 1 1 1984)
|
||
@1984-01-01T00:00:00.000000+01:00
|
||
</code></pre>
|
||
|
||
<p>The complete signature is:</p>
|
||
|
||
<pre><code>**encode-timestamp** nsec sec minute hour day month year &key timezone offset into
|
||
|
||
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.
|
||
</code></pre>
|
||
|
||
<p>Create a timestamp from a universal time with <code>universal-to-timestamp</code>:</p>
|
||
|
||
<pre><code class="language-lisp">(get-universal-time)
|
||
3833588757
|
||
(local-time:universal-to-timestamp (get-universal-time))
|
||
@2021-06-25T07:45:59.000000+02:00
|
||
</code></pre>
|
||
|
||
<p>You can also parse a human-readable time string:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:parse-timestring "1984-01-01")
|
||
@1984-01-01T01:00:00.000000+01:00
|
||
</code></pre>
|
||
|
||
<p>But see the section on parsing timestrings for more.</p>
|
||
|
||
<h3 id="get-todays-date-now-today">Get today’s date (now, today)</h3>
|
||
|
||
<p>Use <code>now</code> or <code>today</code>:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:now)
|
||
@2019-11-13T20:02:13.529541+01:00
|
||
|
||
(local-time:today)
|
||
@2019-11-13T01:00:00.000000+01:00
|
||
</code></pre>
|
||
|
||
<p>“today” is the midnight of the current day in the UTC zone.</p>
|
||
|
||
<p>To compute “yesterday” and “tomorrow”, see below.</p>
|
||
|
||
<h3 id="add-or-substract-times-timestamp-timestamp-">Add or substract times (timestamp+, timestamp-)</h3>
|
||
|
||
<p>Use <code>timestamp+</code> and <code>timestamp-</code>. Each takes 3 arguments: a date, a number and a unit (and optionally a timezone and an offset):</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:now)
|
||
@2021-06-25T07:19:39.836973+02:00
|
||
|
||
(local-time:timestamp+ (local-time:now) 1 :day)
|
||
@2021-06-26T07:16:58.086226+02:00
|
||
|
||
(local-time:timestamp- (local-time:now) 1 :day)
|
||
@2021-06-24T07:17:02.861763+02:00
|
||
</code></pre>
|
||
|
||
<p>The available units are <code>:sec :minute :hour :day :year</code>.</p>
|
||
|
||
<p>This operation is also possible with <code>adjust-timestamp</code>, which can do a bit more as we’ll see right in the next section (it can do many operations at once).</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:timestamp+ (today) 3 :day)
|
||
@2021-06-28T02:00:00.000000+02:00
|
||
|
||
(local-time:adjust-timestamp (today) (offset :day 3))
|
||
@2021-06-28T02:00:00.000000+02:00
|
||
</code></pre>
|
||
|
||
<p>Here’s <code>yesterday</code> and <code>tomorrow</code> defined from <code>today</code>:</p>
|
||
|
||
<pre><code class="language-lisp">(defun yesterday ()
|
||
"Returns a timestamp representing the day before today."
|
||
(timestamp- (today) 1 :day))
|
||
|
||
(defun tomorrow ()
|
||
"Returns a timestamp representing the day after today."
|
||
(timestamp+ (today) 1 :day))
|
||
</code></pre>
|
||
|
||
<h3 id="modify-timestamps-with-any-offset-adjust-timestamp">Modify timestamps with any offset (adjust-timestamp)</h3>
|
||
|
||
<p><code>adjust-timestamp</code>’s first argument is the timestamp we operate on, and then it accepts a full <code>&body changes</code> where a “change” is in the form <code>(offset :part value)</code>:</p>
|
||
|
||
<p>Please point to the previous Monday:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:adjust-timestamp (today) (offset :day-of-week :monday))
|
||
@2021-06-21T02:00:00.000000+02:00
|
||
</code></pre>
|
||
|
||
<p>We can apply many changes at once. Travel in time:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:adjust-timestamp (today)
|
||
(offset :day 3)
|
||
(offset :year 110)
|
||
(offset :month -1))
|
||
@2131-05-28T02:00:00.000000+01:00
|
||
</code></pre>
|
||
|
||
<p>There is a destructive version, <code>adjust-timestamp!</code>.</p>
|
||
|
||
<h3 id="compare-timestamps-timestamp-timestamp-timestamp-">Compare timestamps (timestamp<, timestamp<, timestamp= …)</h3>
|
||
|
||
<p>These should be self-explanatory.</p>
|
||
|
||
<pre><code class="language-lisp">timestamp< time-a time-b
|
||
timestamp<= time-a time-b
|
||
timestamp> time-a time-b
|
||
timestamp>= time-a time-b
|
||
timestamp= time-a time-b
|
||
timestamp/= time-a time-b
|
||
</code></pre>
|
||
|
||
<h3 id="find-the-minimum-or-maximum-timestamp">Find the minimum or maximum timestamp</h3>
|
||
|
||
<p>Use <code>timestamp-minimum</code> and <code>timestamp-maximum</code>. They accept any number of arguments.</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:timestamp-minimum (local-time:today)
|
||
(local-time:timestamp- (local-time:today) 100 :year))
|
||
@1921-06-25T02:00:00.000000+01:00
|
||
</code></pre>
|
||
|
||
<p>If you have a list of timestamps, use <code>(apply #'timestamp-minimum <your list of timestamps>)</code>.</p>
|
||
|
||
<h3 id="maximize-or-minimize-a-timestamp-according-to-a-time-unit-timestamp-maximize-part-timestamp-minimize-part">Maximize or minimize a timestamp according to a time unit (timestamp-maximize-part, timestamp-minimize-part)</h3>
|
||
|
||
<p>We can answer quite a number of questions with this handy function.</p>
|
||
|
||
<p>Here’s an example: please give me the last day of this month:</p>
|
||
|
||
<pre><code class="language-lisp">(let ((in-february (local-time:parse-timestring "1984-02-01")))
|
||
(local-time:timestamp-maximize-part in-february :day))
|
||
|
||
@1984-02-29T23:59:59.999999+01:00
|
||
</code></pre>
|
||
|
||
<h3 id="querying-timestamp-objects-get-the-day-the-day-of-week-the-days-in-month">Querying timestamp objects (get the day, the day of week, the days in month…)</h3>
|
||
|
||
<p>Use:</p>
|
||
|
||
<pre><code class="language-lisp">timestamp-[year, month, day, hour, minute, second, millisecond, microsecond,
|
||
day-of-week (starts at 0 for sunday),
|
||
millenium, century, decade]
|
||
</code></pre>
|
||
|
||
<p>Get all the values at once with <code>decode-timestamp</code>.</p>
|
||
|
||
<p>Bind a variable to a value of your choice with this convenient macro:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:with-decoded-timestamp (:hour h)
|
||
(now)
|
||
(print h))
|
||
|
||
8
|
||
8
|
||
</code></pre>
|
||
|
||
<p>You can of course bind each time unit (<code>:sec :minute :day</code>) to its variable, in any order.</p>
|
||
|
||
<p>See also <code>(days-in-month <month> <year>)</code>.</p>
|
||
|
||
<h3 id="formatting-time-strings-format-format-timestring-iso-8601-format">Formatting time strings (format, format-timestring, +iso-8601-format+)</h3>
|
||
|
||
<p>local-time’s date representation starts with <code>@</code>. We can <code>format</code> them as usual, with the aesthetic directive for instance, to get a usual date representation.</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:now)
|
||
@2019-11-13T18:07:57.425654+01:00
|
||
</code></pre>
|
||
|
||
<pre><code class="language-lisp">(format nil "~a" (local-time:now))
|
||
"2019-11-13T18:08:23.312664+01:00"
|
||
</code></pre>
|
||
|
||
<p>We can use <code>format-timestring</code>, which can be used like <code>format</code> (thus it takes a stream as first argument):</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:format-timestring nil (local-time:now))
|
||
"2019-11-13T18:09:06.313650+01:00"
|
||
</code></pre>
|
||
|
||
<p>Here <code>nil</code> returns a new string. <code>t</code> would print to <code>*standard-output*</code>.</p>
|
||
|
||
<p>But <code>format-timestring</code> also accepts a <code>:format</code> argument. We can use predefined date formats as well as give our own in s-expression friendly way (see next section).</p>
|
||
|
||
<p>Its default value is
|
||
<code>+iso-8601-format+</code>, with the output shown above. The <code>+rfc3339-format+</code> format defaults to it.</p>
|
||
|
||
<p>With <code>+rfc-1123-format+</code>:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:format-timestring nil (local-time:now) :format local-time:+rfc-1123-format+)
|
||
"Wed, 13 Nov 2019 18:11:38 +0100"
|
||
</code></pre>
|
||
|
||
<p>With <code>+asctime-format+</code>:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:format-timestring nil (local-time:now) :format local-time:+asctime-format+)
|
||
"Wed Nov 13 18:13:15 2019"
|
||
</code></pre>
|
||
|
||
<p>With <code>+iso-week-date-format+</code>:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:format-timestring nil (local-time:now) :format local-time:+iso-week-date-format+)
|
||
"2019-W46-3"
|
||
</code></pre>
|
||
|
||
<p>Putting all this together, here is a function that returns Unix times as a human readable string:</p>
|
||
|
||
<pre><code class="language-lisp">(defun unix-time-to-human-string (unix-time)
|
||
(local-time:format-timestring
|
||
nil
|
||
(local-time:unix-to-timestamp unix-time)
|
||
:format local-time:+asctime-format+))
|
||
|
||
(unix-time-to-human-string (get-universal-time))
|
||
"Mon Jun 25 06:46:49 2091"
|
||
</code></pre>
|
||
|
||
<h3 id="defining-format-strings-format-timestring-year---month---day">Defining format strings (format-timestring (:year “-“ :month “-“ :day))</h3>
|
||
|
||
<p>We can pass a custom <code>:format</code> argument to <code>format-timestring</code>.</p>
|
||
|
||
<p>The syntax consists of a list made of symbols with special meanings
|
||
(<code>:year</code>, <code>:day</code>…), strings and characters:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:format-timestring nil (local-time:now) :format '(:year "-" :month "-" :day))
|
||
"2019-11-13"
|
||
</code></pre>
|
||
|
||
<p>The list of symbols is available in the documentation: <a href="https://common-lisp.net/project/local-time/manual.html#Parsing-and-Formatting">https://common-lisp.net/project/local-time/manual.html#Parsing-and-Formatting</a></p>
|
||
|
||
<p>There are <code>:year :month :day :weekday :hour :min :sec :msec</code>, long and
|
||
short notations (“Monday”, “Mo.”), gmt offset, timezone markers and
|
||
more.</p>
|
||
|
||
<p>The <code>+rfc-1123-format+</code> itself is defined like this:</p>
|
||
|
||
<pre><code class="language-lisp">(defparameter +rfc-1123-format+
|
||
;; Sun, 06 Nov 1994 08:49:37 GMT
|
||
'(:short-weekday ", " (:day 2) #\space :short-month #\space (:year 4) #\space
|
||
(:hour 2) #\: (:min 2) #\: (:sec 2) #\space :gmt-offset-hhmm)
|
||
"See the RFC 1123 for the details about the possible values of the timezone field.")
|
||
</code></pre>
|
||
|
||
<p>We see the form <code>(:day 2)</code>: the 2 is for <strong>padding</strong>, to ensure that the
|
||
day is printed with two digits (not only <code>1</code>, but <code>01</code>). There could be
|
||
an optional third argument, the character with which to fill the
|
||
padding (by default, <code>#\0</code>).</p>
|
||
|
||
<h3 id="parsing-time-strings">Parsing time strings</h3>
|
||
|
||
<p>Use <code>parse-timestring</code> to parse timestrings, in the form
|
||
<code>2019-11-13T18:09:06.313650+01:00</code>. It works in a variety of formats
|
||
by default, and we can change parameters to adapt it to our needs.</p>
|
||
|
||
<p>To parse more formats such as “Thu Jul 23 19:42:23 2013” (asctime),
|
||
we’ll use the <a href="https://github.com/tkych/cl-date-time-parser">cl-date-time-parser</a> library.</p>
|
||
|
||
<p>The <code>parse-timestring</code> docstring is:</p>
|
||
|
||
<blockquote>
|
||
<p>Parses a timestring and returns the corresponding timestamp. Parsing begins at start and stops at the end position. If there are invalid characters within timestring and fail-on-error is T, then an invalid-timestring error is signaled, otherwise NIL is returned.</p>
|
||
|
||
<p>If there is no timezone specified in timestring then offset is used as the default timezone offset (in seconds).</p>
|
||
</blockquote>
|
||
|
||
<p>Examples:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:parse-timestring "2019-11-13T18:09:06.313650+01:00")
|
||
;; @2019-11-13T18:09:06.313650+01:00
|
||
</code></pre>
|
||
|
||
<pre><code class="language-lisp">(local-time:parse-timestring "2019-11-13")
|
||
;; @2019-11-13T01:00:00.000000+01:00
|
||
</code></pre>
|
||
|
||
<p>This custom format fails by default: “2019/11/13”, but we can set the
|
||
<code>:date-separator</code> to “/”:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:parse-timestring "2019/11/13" :date-separator #\/)
|
||
;; @2019-11-13T19:42:32.394092+01:00
|
||
</code></pre>
|
||
|
||
<p>There is also a <code>:time-separator</code> (defaulting to <code>#\:</code>) and
|
||
<code>:date-time-separator</code> (<code>#\T</code>).</p>
|
||
|
||
<p>Other options include:</p>
|
||
|
||
<ul>
|
||
<li>the start and end positions</li>
|
||
<li><code>fail-on-error</code> (defaults to <code>t</code>)</li>
|
||
<li><code>(allow-missing-elements t)</code></li>
|
||
<li><code>(allow-missing-date-part allow-missing-elements)</code></li>
|
||
<li><code>(allow-missing-time-part allow-missing-elements)</code></li>
|
||
<li><code>(allow-missing-timezone-part allow-missing-elements)</code></li>
|
||
<li><code>(offset 0)</code></li>
|
||
</ul>
|
||
|
||
<p>Now a format like ““Wed Nov 13 18:13:15 2019” will fail. We’ll use the
|
||
<code>cl-date-time-parser</code> library:</p>
|
||
|
||
<pre><code class="language-lisp">(cl-date-time-parser:parse-date-time "Wed Nov 13 18:13:15 2019")
|
||
;; 3782657595
|
||
;; 0
|
||
</code></pre>
|
||
|
||
<p>It returns the universal time which, in turn, we can ingest with the
|
||
local-time library:</p>
|
||
|
||
<pre><code class="language-lisp">(local-time:universal-to-timestamp *)
|
||
;; @2019-11-13T19:13:15.000000+01:00
|
||
</code></pre>
|
||
|
||
<h3 id="misc">Misc</h3>
|
||
|
||
<p>To find out if it’s Alice anniversary, use <code>timestamp-whole-year-difference time-a time-b</code>.</p>
|
||
|
||
|
||
<p class="page-source">
|
||
Page source: <a href="https://github.com/LispCookbook/cl-cookbook/blob/master/dates_and_times.md">dates_and_times.md</a>
|
||
</p>
|
||
</div>
|
||
|
||
<script type="text/javascript">
|
||
|
||
// Don't write the TOC on the index.
|
||
if (window.location.pathname != "/cl-cookbook/") {
|
||
$("#toc").toc({
|
||
content: "#content", // will ignore the first h1 with the site+page title.
|
||
headings: "h1,h2,h3,h4"});
|
||
}
|
||
|
||
$("#two-cols + ul").css({
|
||
"column-count": "2",
|
||
});
|
||
$("#contributors + ul").css({
|
||
"column-count": "4",
|
||
});
|
||
</script>
|
||
|
||
|
||
|
||
<div>
|
||
<footer class="footer">
|
||
<hr/>
|
||
© 2002–2021 the Common Lisp Cookbook Project
|
||
</footer>
|
||
|
||
</div>
|
||
<div id="toc-btn">T<br>O<br>C</div>
|
||
</div>
|
||
|
||
<script text="javascript">
|
||
HighlightLisp.highlight_auto({className: null});
|
||
</script>
|
||
|
||
<script type="text/javascript">
|
||
function duckSearch() {
|
||
var searchField = document.getElementById("searchField");
|
||
if (searchField && searchField.value) {
|
||
var query = escape("site:lispcookbook.github.io/cl-cookbook/ " + searchField.value);
|
||
window.location.href = "https://duckduckgo.com/?kj=b2&kf=-1&ko=1&q=" + query;
|
||
// https://duckduckgo.com/params
|
||
// kj=b2: blue header in results page
|
||
// kf=-1: no favicons
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<script async defer data-domain="lispcookbook.github.io/cl-cookbook" src="https://plausible.io/js/plausible.js"></script>
|
||
|
||
</body>
|
||
</html>
|