xref: /netbsd-src/lib/libutil/parsedate.3 (revision 29027db22b969ef0aebc9a16d2329e1a0426ab75)
1.\"     $NetBSD: parsedate.3,v 1.27 2024/05/02 18:34:01 rillig Exp $
2.\"
3.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
4.\" All rights reserved.
5.\"
6.\" This code is derived from software contributed to The NetBSD Foundation
7.\" by Christos Zoulas.
8.\"
9.\" Redistribution and use in source and binary forms, with or without
10.\" modification, are permitted provided that the following conditions
11.\" are met:
12.\" 1. Redistributions of source code must retain the above copyright
13.\"    notice, this list of conditions and the following disclaimer.
14.\" 2. Redistributions in binary form must reproduce the above copyright
15.\"    notice, this list of conditions and the following disclaimer in the
16.\"    documentation and/or other materials provided with the distribution.
17.\"
18.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28.\" POSSIBILITY OF SUCH DAMAGE.
29.\"
30.Dd May 16, 2021
31.Dt PARSEDATE 3
32.Os
33.Sh NAME
34.Nm parsedate
35.Nd date parsing function
36.Sh LIBRARY
37.Lb libutil
38.Sh SYNOPSIS
39.In util.h
40.Ft time_t
41.Fn parsedate "const char *datestr" "const time_t *time" "const int *tzoff"
42.Sh DESCRIPTION
43The
44.Fn parsedate
45function parses a date and time from
46.Ar datestr
47described in English relative to an optional
48.Ar time
49point,
50and an optional timezone offset (in minutes behind/west of UTC)
51specified in
52.Ar tzoff .
53If
54.Ar time
55is
56.Dv NULL
57then the current time is used.
58If
59.Ar tzoff
60is
61.Dv NULL ,
62then the current time zone is used.
63.Pp
64The
65.Ar datestr
66is a sequence of white-space separated items.
67The white-space is optional if the concatenated items are not ambiguous.
68The string contains data which can specify a base time (used in
69conjunction with the
70.Ar time
71parameter, totally replacing that parameter's value if sufficient data
72appears in
73.Ar datestr
74to do so), and data specifying an offset from the base time.
75Both of those are optional.
76If no data specifies the base time, then
77.Nm
78simply uses the value given by
79.Ar \&*time
80.Pq "or now" .
81If there is no offset data then no offset is applied.
82An empty
83.Ar datestr ,
84or a
85.Ar datestr
86containing nothing but whitespace,
87is equivalent to midnight at the start of the day specified by
88.Ar \&*time
89.Pq "or today" .
90.Pp
91The following words have the indicated numeric meanings:
92.Dv last =
93\-1,
94.Dv this =
950,
96.Dv first , next ,
97or
98.Dv one =
991
100.Pq but see the BUGS section below ,
101.Dv second
102is unused so that it is not confused with
103.Dq seconds ,
104.Dv two =
1052,
106.Dv third
107or
108.Dv three =
1093,
110.Dv fourth
111or
112.Dv four =
1134,
114.Dv fifth
115or
116.Dv five  =
1175,
118.Dv sixth
119or
120.Dv six  =
1216,
122.Dv seventh
123or
124.Dv seven =
1257,
126.Dv eighth
127or
128.Dv eight =
1298,
130.Dv ninth
131or
132.Dv nine =
1339,
134.Dv tenth
135or
136.Dv ten =
13710,
138.Dv eleventh
139or
140.Dv eleven =
14111,
142.Dv twelfth
143or
144.Dv twelve =
14512.
146.Pp
147The following words are recognized in English only:
148.Dv AM ,
149.Dv PM ,
150.Dv a.m. ,
151.Dv p.m. ,
152.Dv midnight ,
153.Dv mn ,
154.Dv noon .
155.Pp
156The months:
157.Dv january ,
158.Dv february ,
159.Dv march ,
160.Dv april ,
161.Dv may ,
162.Dv june ,
163.Dv july ,
164.Dv august ,
165.Dv september ,
166.Dv october ,
167.Dv november ,
168.Dv december ,
169and common abbreviations for them.
170When a month name (or its ordinal number) is given,
171the number of some particular day of that month is required to accompany it.
172This is generally true of any data that specifies a period
173with a duration longer than a day, so simply specifying a year,
174or a month, is invalid, as also is specifying a year and a month.
175.Pp
176The days of the week:
177.Dv sunday ,
178.Dv monday ,
179.Dv tuesday ,
180.Dv wednesday ,
181.Dv thursday ,
182.Dv friday ,
183.Dv saturday ,
184and common abbreviations for them.
185Weekday names are typically ignored if any other data
186is given to specify the date, even if the name given
187is not the day on which the specified date occurred.
188.Pp
189Time units:
190.Dv year ,
191.Dv month ,
192.Dv fortnight ,
193.Dv week ,
194.Dv day ,
195.Dv hour ,
196.Dv minute ,
197.Dv min ,
198.Dv second ,
199.Dv sec ,
200.Dv tomorrow ,
201.Dv yesterday .
202.Pp
203Timezone names:
204.Dv gmt (+0000) ,
205.Dv ut (+0000) ,
206.Dv utc (+0000) ,
207.Dv wet (+0000) ,
208.Dv bst (+0100) ,
209.Dv wat (-0100) ,
210.Dv at (-0200) ,
211.Dv nft (-0330) ,
212.Dv nst (-0330) ,
213.Dv ndt (-0230) ,
214.Dv ast (-0400) ,
215.Dv adt (-0300) ,
216.Dv est (-0500) ,
217.Dv edt (-0400) ,
218.Dv cst (-0600) ,
219.Dv cdt (-0500) ,
220.Dv mst (-0700) ,
221.Dv mdt (-0600) ,
222.Dv pst (-0800) ,
223.Dv pdt (-0700) ,
224.Dv yst (-0900) ,
225.Dv ydt (-0800) ,
226.Dv hst (-1000) ,
227.Dv hdt (-0900) ,
228.Dv cat (-1000) ,
229.Dv ahst (-1000) ,
230.Dv nt (-1100) ,
231.Dv idlw (-1200) ,
232.Dv cet (+0100) ,
233.Dv met (+0100) ,
234.Dv mewt (+0100) ,
235.Dv mest (+0200) ,
236.Dv swt (+0100) ,
237.Dv sst (+0200) ,
238.Dv fwt (+0100) ,
239.Dv fst (+0200) ,
240.Dv eet (+0200) ,
241.Dv bt (+0300) ,
242.Dv it (+0330) ,
243.\".Dv zp4 (+0400) ,
244.\".Dv zp5 (+0500) ,
245.Dv ist (+0530) ,
246.\".Dv zp6 (+0600) ,
247.Dv ict (+0700) ,
248.Dv wast (+0800) ,
249.Dv wadt (+0900) ,
250.Dv awst (+0800) ,
251.Dv awdt (+0900) ,
252.Dv cct (+0800) ,
253.Dv sgt (+0800) ,
254.Dv hkt (+0800) ,
255.Dv jst (+0900) ,
256.Dv cast (+0930) ,
257.Dv cadt (+1030) ,
258.Dv acst (+0930) ,
259.Dv acdt (+1030) ,
260.Dv east (+1000) ,
261.Dv eadt (+1100) ,
262.Dv aest (+1000) ,
263.Dv aedt (+1100) ,
264.Dv gst (+1000) ,
265.Dv nzt (+1200) ,
266.Dv nzst (+1200) ,
267.Dv nzdt (+1300) ,
268.Dv idle (+1200) .
269.Pp
270The timezone names simply specify an offset from
271Coordinated Universal Time (UTC)
272and do not imply validating the time/date to be reasonable in any zone
273that happens to use the abbreviation specified.
274.Pp
275A variety of unambiguous dates are recognized:
276.Bl -tag -compact -width "20 Jun 1994"
277.It 9/10/69
278For years between 69-99 we assume 1900+ and for years between 0-68
279we assume 2000+.
280.It 2006-11-17
281An ISO-8601 date.
282Note that when using the ISO-8601 format date and time with the
283.Sq T
284designator to separate date and time-of-day,
285this must appear at the start of the input string,
286with no preceding whitespace.
287Other modifiers may optionally follow.
288.It 67-09-10
289The year in an ISO-8601 date is always taken literally,
290so this is the year 67, not 2067.
291.It 10/1/2000
292October 1, 2000; the common, but bizarre, US format.
293.It 20 Jun 1994
294.It 23jun2001
295.It 1-sep-06
296Other common abbreviations.
297.It 1/11
298The year can be omitted.
299A missing year is taken from the
300.Ar \&*time
301value, or
302.Dq now
303if
304.Ar time
305is NULL.
306Again, this is the US month/day format (the 11th of January).
307.El
308.Pp
309Standard e-mail (RFC822, RFC2822, etc)
310formats and the output from
311.Xr date 1 ,
312and
313.Xr asctime 3
314are all supported as input,
315as is cvs date format (where years < 100 are treated as
31620th century).
317.Pp
318Times can also be specified in common forms:
319.Bl -tag -compact -width 12:11:01.000012
320.It 10:01
321.It 10:12pm
322.It 12:11:01.000012
323.It 12:21-0500
324.El
325Fractions of seconds (after a decimal point, or comma) are parsed, but ignored.
326If no time is given, midnight on the specified date is assumed.
327If a time is given without a date, that time on the day
328specified by
329.Ar \&*time
330.Pq or now
331is used.
332Missing minutes, or seconds, are taken to be zero.
333.Pp
334A variety of forms for relative items to specify
335an offset from the base time are also supported:
336.Bl -tag -compact -width "this thursday"
337.It -1 month
338.It last friday
339.It one week ago
340.It this thursday
341.It next sunday
342.It +2 years
343.El
344.Pp
345Note that, as a special case for
346.Dv midnight
347with the name of a day only,
348.Dq "midnight tuesday"
349implies 00:00 at the beginning of Tuesday,
350.Pq "the midnight before Tuesday"
351whereas
352.Dq "Sat mn"
353implies 00:00 at the end of Saturday
354.Pq "midnight after Saturday"
355.Pq "i.e. early Sunday morning" .
356.Pp
357Seconds since epoch, UTC, (also known as UNIX time) are also supported
358to specify the base time:
359.Bl -tag -compact -width "E.g.:\ @735275209\ \ \ \ "
360.It "E.g.: @735275209"
361to specify: Tue Apr 20 03:06:49 UTC 1993
362.El
363provided that the value given is within the range
364that can be represented as a
365.Va "struct tm" .
366Negative values
367(times before the epoch)
368are permitted, but no other significant data as part of
369the base time \(en the value given specifies year, month,
370day, hour, minute, and second, there is no more.
371An offset from this base time may still be included.
372Thus
373.Dq "@735275209 +2 months 5 hours 15 minutes"
374produces a time_t which represents
375.Dq "Sun Jun 20 08:21:49 UTC 1993" .
376.Pp
377Text in
378.Ar datestr
379enclosed in parentheses
380.Ql \&(
381and
382.Ql \&)
383is treated as a comment, and ignored.
384Parentheses nest (the comment ends when there have
385been the same number of closing parentheses as there
386were opening parentheses.)
387There is no escape character in comments,
388.Ql \&)
389always ends
390(or decreases the nesting level of)
391the comment.
392.Sh RETURN VALUES
393.Fn parsedate
394returns the number of seconds passed since,
395or before (if negative,)
396the Epoch, or
397.Dv \-1
398if the date could not be parsed properly.
399A non-error result of
400.Dv \-1
401can be distinguished from an error by setting
402.Va errno
403to
404.Dv 0
405before calling
406.Fn parsedate ,
407and checking the value of
408.Va errno
409afterwards.
410.Sh ENVIRONMENT
411If the
412.Ar tzoff
413parameter is given as
414.Dv NULL ,
415then:
416.Bl -tag -width iTZ
417.It Ev TZ
418The timezone to which the input is relative,
419when no zone information is otherwise specified in the
420.Ar datestr
421input.
422.El
423.Sh SEE ALSO
424.Xr date 1 ,
425.Xr touch 1 ,
426.Xr errno 2 ,
427.Xr ctime 3 ,
428.\" WTF ????  eeprom(8)!!  Why?  Just because it calls this function?  Weird!
429.Xr eeprom 8
430.Sh HISTORY
431The parser used in
432.Fn parsedate
433was originally written by Steven M. Bellovin while at the University
434of North Carolina at Chapel Hill.
435It was later tweaked by a couple of people on Usenet.
436Completely overhauled by Rich $alz and Jim Berets in August, 1990.
437Further mangled during its residence with
438.Nx .
439.Pp
440The
441.Fn parsedate
442function first appeared in
443.Nx 4.0 .
444.Sh BUGS
445.Bl -tag -compact -width 1
446.It 1
447The
448.Fn parsedate
449function is not re-entrant or thread-safe.
450.It 2
451The
452.Fn parsedate
453function assumes years less than 0 mean \(mi
454.Fa year ,
455and in non ISO formats,
456that years less than 69 mean 2000 +
457.Fa year ,
458otherwise
459years less than 100 mean 1900 +
460.Fa year .
461That is except in the CVS format, where years less than 100
462mean 1900 +
463.Fa year .
464.It 3
465The
466.Fn parsedate
467function accepts
468.Dq "12 am"
469where
470.Dq "12 midnight"
471is correct, and similarly
472.Dq "12 pm"
473for
474.Dq "12 noon" .
475The correct forms are also accepted.
476.It 4
477There are various weird cases that are hard to explain,
478but are nevertheless considered correct.
479.It 5
480It is very hard to specify years BC,
481and in any case,
482conversions of times before the
483commencement of the modern Gregorian calendar
484(when that occurred depends upon location,
485but late 16th century is a rough guide)
486are suspicious at best,
487and depending upon context,
488often just plain wrong.
489.It 6
490Despite what is stated above,
491.Dq next
492is actually 2.
493The input
494.Dq "next January" ,
495instead of producing a timestamp for January of the
496following year, produces one for January 2nd, of the
497current year.
498Use caution with
499.Dq next
500it rarely does what humans expect.
501For example, on a Sunday
502.Dq "next sunday"
503means the following Sunday (7 days hence)
504whereas
505.Dq "next monday"
506means the monday that follows that (8 days hence)
507rather than
508.Dq tomorrow
509or just
510.Dq Mon
511.Pq without the Dq next
512which is the nearest subsequent Monday.
513.El
514