dateexpr evaluates an expression, much like expr(1), except that the expression may also involve dates and times. As a simple introductory example, the invocation
dateexpr today - 1 dayprints yesterday's date. Since the date/time libraries used by dateexpr know about not only the basics of clocks and calendars (``Thirty days hath September...''), but also the more subtle details involving leap years and Daylight Saving Time (and even leap seconds!), it is straightforward to perform computations like the above accurately.
The supported operators are
* / + - < <= > >= = !=Parentheses may be used to override the default precedence, which otherwise follows the traditional levels (as reflected in the list above).
The terms in an expression may consist of:
Dates and times are relatively free-form, as suggested by the examples above. Notice that fractional seconds are supported. The notation ``nn:nn'' is interpreted as HH:MM; you can use either 0:nn:nn or nn:nn.0 to explicitly force minutes and seconds.
These special terms may also appear:
(Currently, the file name operands to the mtime(), atime(), and ctime() operators appear as ``bare words'', but this may change.)
Internally, dateexpr supports two kinds of date/timestamps: relative and absolute. Roughly speaking, date/timestamps that contain a calendar date are absolute, and all others are relative. Relative times can be added and subtracted freely, and added to and subtracted from absolute times. The difference between two absolute times is a relative time. The sum of two absolute times is meaningless and is disallowed.
Certain mixed-mode calculations are also permitted. Integers may be added to or subtracted from date/timestamps; the integer is interpreted as a number of seconds unless suffixed with a unit indicator. Relative timestamps (but not absolute) may be multiplied or divided by integers, yielding relative timestamps.
The relational operators (<, >=, =, etc.) may be applied to pairs of absolute times, to pairs of relative times, or to pairs of integers, but not to any other combinations.
dateexpr attempts to print its output in a format mimicking its input, and with an appropriate amount of precision. The heuristics are not always successful, but the -fmt option can be used to force an explicit output representation.
The exit status is zero if a nonzero time or integer is computed (including as the result of a successful comparison), 1 if a zero result is computed (including as the result of an unsuccessful comparison), and 2 on errors.
Compute the day before March 1, 2000, demonstrating that 2000 was a leap year:
dateexpr 2000-03-01 - 1 day
Compute the number of days between February 28 and March 1, 1900, demonstrating that 1900 was not a leap year:
dateexpr 3/1/1900 - 2/28/1900
Divide 1 hour by 3, yielding 20 minutes:
dateexpr 1:00:00 / 3
Compute the author's age:
dateexpr today - October 2, 1961
See if a file has been accessed since it's been modified:
dateexpr atime \( file \) \> mtime \( file \)(The backslashes \ quote the parentheses and greater-than symbol to protect them from interpretation by the shell.)
See how long a command took to execute:
start=`date` long_running_command end=`date` dateexpr $end - $start
See how long a command took to execute, another way:
start=`dateexpr now` long_running_command dateexpr now - $start
See how long a command took to execute, with subsecond resolution:
start=`dateexpr -fmt %H:%M:%.2S now` long_running_command dateexpr -fmt %H:%M:%.2S now - $start
Compare two times:
if dateexpr 0:91 '>' 1:30 > /dev/null; then echo yes; else echo no; fi
When adding integers to dates, you probably want the integers to be interpreted as days, not seconds.
Relative times are output in units of at most days, which is awkward if you're computing intervals which amount to years. (You can explicitly divide by 365 if you like, but the output will still be tagged with the word ``days''.)
It's unclear whether nn:nn should be interpreted as HH:MM or MM:SS. (On the other hand, in simple calculations like ``1:01 + 2:02'', it hardly matters.) The fact that nn:nn is interpreted as HH:MM, while nn:nn.nn is interpreted as MM:SS.ff, seems odd.
It is not fully possible to control the output format for relative date/timestamps. Negative relative times are probably not always printed correctly.
Division, especially by large numbers (e.g. greater than 1000) is buggy.
The syntax for the mtime, atime, and ctime operators is awkward and should probably be changed.
Time zones and Daylight Saving Time are not perfectly handled yet. (Nor are leap seconds, though the attempt is valiant.)
Calendars other than Gregorian are not handled yet.
Years 0 or B.C. are not properly handled yet.
When rounding times for printout, if 0.99999... seconds has to be rounded up to 1.000 second, it is not always possible to propagate the carry up through the %S, %M, %H, %d, %m, and %Y values.
This documentation corresponds to version 1.6 of the program.
See http://www.eskimo.com/~scs/src/#dateexpr for possible updates.
This program and its documentation may be freely redistributed and altered and used at will, as long as this notice remains attached and as long as any modifications are marked as such.
Steve Summit, firstname.lastname@example.org