[local-time-devel] Proposed function: TIMESTAMP-ADD-DURATION

J.P. Larocque jpl at thoughtcrime.us
Tue May 4 22:15:20 UTC 2010


Hi,

I have a need to add a duration (as a number of seconds) to a
TIMESTAMP--a function that is complementary to TIMESTAMP-DIFFERENCE.
TIMESTAMP+ with a unit of :SEC doesn't work for me, because:

  1) I want the ability to pass a non-integer number of seconds, such
     as 3.25d0 or 1/4, and get a new timestamp with DAY, SEC, and NSEC
     updated accordingly.  Currently I'd have to call TIMESTAMP+ twice
     and do a lot of busywork that LOCAL-TIME should be able to do for
     me.  (Or call TIMESTAMP+ with an NSEC of (floor (* seconds (expt
     10 9))), but that's also quite ugly.)
  
  2) TIMESTAMP+ depends on %OFFSET-TIMESTAMP-PART, which has at least
     one DST bug.  When you give either function a unit of :DAY,
     :MONTH, :YEAR, etc., it will treat its given timestamp as a
     calendar date and time of day and perform the manipulation on the
     calendar date and time of day, converting the result back to an
     absolute time.  For example, adding 1 day to
     2010-03-13T10:00-08:00 in Pacific Standard Time results in
     2010-03-14T10:00-07:00 Pacific Daylight Time).  That's fine, as
     that seems to be intended.  However, nanoseconds spill over into
     seconds, and seconds spill over into days, so even if I want
     exactly 86400 seconds, TIMESTAMP+ treats my request as if I had
     asked for 1 calendar day:
     
       CL-USER> local-time:*default-timezone* ; = America/Los_Angeles
       #<LOCAL-TIME::TIMEZONE PDT PST PWT PPT>
       CL-USER> (let* ((ts1 (local-time:encode-timestamp
                             0 0 0 10 13 3 2010))
                       (ts2 (local-time:timestamp+ ts1 86400 :sec)))
                  (values ts1 ts2
                          (local-time:timestamp-difference ts2 ts1)))
       @2010-03-13T10:00:00.000000-08:00
       @2010-03-14T10:00:00.000000-07:00
       82800

Because of the inconvenience of #1, and the bug of #2 caused by
confusing calendar dates/times of day with abstract, absolute points
in time, I propose a new function, TIMESTAMP-ADD-DURATION.  It's as
simple as can be: add a number of seconds to a timestamp; no
consideration of time zones or DST is necessary at all.  I've attached
a patch that includes documentation.

Hope you find it useful,

-- 
J.P. Larocque <jpl at thoughtcrime.us>
-------------- next part --------------
Tue May  4 15:13:27 PDT 2010  J.P. Larocque <jpl at thoughtcrime.us>
  * Add function TIMESTAMP-ADD-DURATION.

New patches:

[Add function TIMESTAMP-ADD-DURATION.
J.P. Larocque <jpl at thoughtcrime.us>**20100504221327] {
hunk ./doc/local-time.texinfo 448
+
+ at itindex timestamp-add-duration
+ at defun timestamp-add-duration time duration
+
+Adds @var{duration} to @var{time}, returning a new @code{timestamp}
+with the resulting time.  @var{duration} is a @code{real} number of
+seconds occurring after @var{time}.
+
+ at var{duration} may be positive or negative, indicating a time later
+than or prior to @var{time}.  @var{duration} may be an integer, in
+which case the returned @code{timestamp} will have the same
+ at code{nsec} value as @var{time}, or it may have a subsecond fractional
+part, in which case @code{nsec} is updated as expected.
+ at end defun
+
+
hunk ./src/local-time.lisp 58
+	   #:timestamp-add-duration
hunk ./src/local-time.lisp 954
+(defun timestamp-add-duration (time duration)
+  "Adds DURATION to TIME, returning a new TIMESTAMP with the resulting time.  DURATION is a REAL number of seconds occurring after TIME."
+  (declare (type timestamp time)
+	   (type real duration))
+  (let ((sec (+ (* (day-of time) +seconds-per-day+)
+		(sec-of time)
+		(/ (nsec-of time) #.(expt 10 9))
+		(rational duration))))
+      (multiple-value-bind (sec subsec) (floor sec)
+	(multiple-value-bind (day sec) (floor sec +seconds-per-day+)
+	  (make-timestamp :day day :sec sec
+			  :nsec (floor subsec #.(expt 10 -9)))))))
+
}

Context:

[TODO file
attila.lendvai at gmail.com**20100420063102
 Ignore-this: c6136055d112035c5df541adde00d862
] 
[no need to :shadow #:time anymore because it's called time-of-day now
attila.lendvai at gmail.com**20100419193011
 Ignore-this: b7dbc95244891992951f58265ab368aa
] 
[Updated copyright year for probably no reason
Daniel Lowe <dlowe at bitmuse.com>**20100324195045
 Ignore-this: 76fb8af82a60d2f4c0e952febde10363
] 
[Many default offset inconsistencies resolved, more tests pass
Daniel Lowe <dlowe at bitmuse.com>**20100324194517
 Ignore-this: b414446d02273d5e75b9a93bed5ca6fa
] 
[Fixed offset bug in minimize and maximize part functions
Daniel Lowe <dlowe at bitmuse.com>**20100324152342
 Ignore-this: b58b5e69598805c9b30a6b600560ade
] 
[fix parentheses from last patch
jaap at streamtech.nl**20100209114731
 Ignore-this: a70910106b446020eed799cebab65b6c
] 
[roll back my change where adjust-timestamp defaulted to UTC (both are broken, but this way it's at least backwards compatible)
attila.lendvai at gmail.com**20100209102239
 Ignore-this: 63f876b8f1bf5483e874b3dbc0d4e177
] 
[use hu.dwim.stefil for unit testing.
attila.lendvai at gmail.com**20100127081740
 Ignore-this: e5ddf9db232c9723b233e19ba1c9948c
 
 useful things for copy/pasting:
 darcs get http://common-lisp.net/project/alexandria/darcs/alexandria/
 darcs get http://dwim.hu/darcs/hu.dwim.stefil
 (asdf:test-system :local-time)
] 
[follow documentation/ -> doc/ rename in .boring
attila.lendvai at gmail.com**20100127081710
 Ignore-this: 2ea403b64f5ada4b2e9dbb4b013b99b9
] 
[added a (check-type result time-of-day) in cl-postgres integration
attila.lendvai at gmail.com**20100126123531
 Ignore-this: 4750c6ffaa3e8ed41d10fe2fb9d5b229
] 
[renamed 'time to 'time-of-day for less conflict headaches
attila.lendvai at gmail.com**20100126123505
 Ignore-this: 50b518114f386d042701ad92260e4794
] 
[fix valid-date-p
attila.lendvai at gmail.com**20091206211948
 Ignore-this: 207df3b76010adf3a2e749fe9d60db57
] 
[Added date and time types.
levente.meszaros at gmail.com**20091201201849
 Ignore-this: b858bbe9a6b10f4ed106fba83d69e406
] 
[Split local-time.asd and introduce cl-postgres+local-time.asd.
levente.meszaros at gmail.com**20091009161856
 Ignore-this: 3e4521adc1a0afa273c63d304cd6e9c8
] 
[TAG before controversial changes
Daniel Lowe <dlowe at bitmuse.com>**20100126123450
 Ignore-this: 7f2ec6e3a5baa0691637367f1b22aed
] 
[fix test adjust-timestamp/bug3 (PLEASE AUDIT!)
attila.lendvai at gmail.com**20100125122540
 Ignore-this: 6b449034e6c96f245709a808c5e14593
] 
[fix test adjust-timestamp/bug2 (PLEASE AUDIT!)
attila.lendvai at gmail.com**20100125122530
 Ignore-this: 212178187413618cb83e4e7d0bd8658e
] 
[adjust-timestamp defaults to :utc-offset 0 unless timezone is specified. fixes surprises shown by test adjust-timestamp/bug2 (PLEASE AUDIT!)
attila.lendvai at gmail.com**20100125122507
 Ignore-this: 1eff627c0e5d072b89d7119c4426f229
] 
[added adjust-timestamp/bug3
attila.lendvai at gmail.com**20100125121843
 Ignore-this: 2c3cd77b1f107152dd36633734ae4ae
] 
[whitespace
attila.lendvai at gmail.com**20100125120759
 Ignore-this: 341ea584efa430672b4a7fae8368184a
] 
[added test adjust-timestamp/bug2
attila.lendvai at gmail.com**20100124185450
 Ignore-this: 996991645615afe1a9a6be8cef3c7a4f
] 
[Fix SBCL conditional compilation
Jonathan Lee <jonathlee at gmail.com>**20100102181805
 Ignore-this: e084a602df8e1931fff11d4d9f6ba814
] 
[Updated asdf version number to 1.0.1
dlowe at bitmuse.com**20100111031331
 Ignore-this: 17e00a012590c5116fbdeb86566b1786
] 
[added +months-per-year+
attila.lendvai at gmail.com**20091202102038
 Ignore-this: 5c1c99bee45537409939c4da0ada1075
] 
[another take on reread-timezone-repository & co.
attila.lendvai at gmail.com**20091030235517
 Ignore-this: ad00124eea993a623c42e0cd9b6ad81c
] 
[try to make the initialization of *project-home-directory* a bit less fragile when not loading through ASDF
attila.lendvai at gmail.com**20091030093403
 Ignore-this: 5a848c282db52a5edb38df6fdf9c186e
 
 although i personally am much more interested in making local-time load with xcvb, than keeping it in one
 file that can be CL:LOAD'ed...
] 
[make it loadable with (load "local-time.lisp")
attila.lendvai at gmail.com**20091030092409
 Ignore-this: b3aae958e1003af861646fda0f036c9d
] 
[fix #+#. voodoo, one less compilation warning
attila.lendvai at gmail.com**20091030091812
 Ignore-this: b80cc242457896e43c168c9fdc1aadf3
] 
[formatting, semantically NOP
attila.lendvai at gmail.com**20091030091743
 Ignore-this: 6edfb0b406108f1b3cd296a245dac55f
] 
[whitespace changes, one less warning
attila.lendvai at gmail.com**20091029122310
 Ignore-this: 6a319ea0491a85a8bd270a2468c7b47a
] 
[added a deftype for timezone-offset, fix bug reported by Abhishek Reddy and Huw Giddens
attila.lendvai at gmail.com**20091029122004
 Ignore-this: a3e828c02dcdf1d195311cfe5305ec6f
 
 http://common-lisp.net/pipermail/local-time-devel/2009-October/000173.html
] 
[some tests
attila.lendvai at gmail.com**20091029121803
 Ignore-this: 9c510d5a16519beeeed2738d290742a1
] 
[Don't discard value of sb-ext:get-time-of-day
Daniel Lowe <dlowe at bitmuse.com>**20091022155025
 Ignore-this: 565ad4c1ee49c11d900c3e1781e9f6e0
] 
[Provide support for formatting the day as an ordinal (e.g. 1st, 22nd)
Daniel White <daniel at whitehouse.id.au>**20091022132601
 Ignore-this: c166703967661a3d7e32a4489184fdd4
] 
[fix test: reread-timezone-repository is not public in local-time package (anymore?)
attila.lendvai at gmail.com**20091005090107
 Ignore-this: 8e3f2381c3c11afdd5123055e332f904
] 
[comments
attila.lendvai at gmail.com**20091002083019
 Ignore-this: 855a9b7004e33350c0a0394e242f459d
] 
[ccl-windows-without-gettimeofday
essdir at web.de**20090901164212
 Ignore-this: b6df4f6bd69eff0d6fd18dc1a90097e7
] 
[Minor bugfix: :utc-offset instead of :offset
Maciej Katafiasz <mathrick at gmail.com>**20090808135148
 Ignore-this: e20b7cff5ec220a83bd112265b06f99f
] 
[follow the format-rfcnumber-timestring nameing convention, rename format-http-timestring
attila.lendvai at gmail.com**20090928091959
 Ignore-this: a35c5d543cabb520ff676c9a490f1cb2
] 
[Make timestamp manipulation functions take and respect timezone arguments.
Maciej Katafiasz <mathrick at gmail.com>**20090727180103
 Ignore-this: 79214728e4966f44d8d4587bd850c53b
] 
[Make WITH-DECODED-TIMESTAMP and related take timezone/offset arguments.
Maciej Katafiasz <mathrick at gmail.com>**20090727175400
 Ignore-this: 296084f8d9179fe257c69118b7123309
] 
[Make ENCODE-TIMESTAMP accept timezones instead of fixed offsets.
Maciej Katafiasz <mathrick at gmail.com>**20090727174013
 Ignore-this: f6420e93d194396afb221821e1312652
] 
[update TODO, add link to chronicity
attila.lendvai at gmail.com**20090729181326
 Ignore-this: aa290ebfb4f6001600cf33a228a99a41
] 
[Use symbols instead of strings where possible.
Maciej Katafiasz <mathrick at gmail.com>**20090724164920] 
[added a once failing test
attila.lendvai at gmail.com**20090616143818
 Ignore-this: 741ad01d47b47e15cb4877567d3ba9d9
] 
[add a more useful error when find-timezone-by-location-name is used without reading in the timezone files
attila.lendvai at gmail.com**20090616143733
 Ignore-this: c982ca27ef16e7f865afece963b6c9be
] 
[fix (print (now)) when *timezone* is (find-timezone-by-location-name "UTC")
attila.lendvai at gmail.com**20090616141707
 Ignore-this: ac694826aa5e9719d41c51503e0a8785
] 
[clean up gettimeofday stuff, follow sbcl's changes (but remain backward compatible)
attila.lendvai at gmail.com**20090521170712
 Ignore-this: 70b2754c0a254abb060dce0f15bb266
] 
[remove superfluous eval-when around reread-timezone-repository
attila.lendvai at gmail.com**20090513213236
 Ignore-this: 337cf4b3d50d0714f2c4a4a3d84e356f
] 
[Local-time now passes all tests in CCL
Daniel Lowe <dlowe at bitmuse.com>**20090417142203] 
[Changed lispworks/ccl kluge to another, better kluge
Daniel Lowe <dlowe at bitmuse.com>**20090417142156] 
[In WITH-DECODED-TIMESTAMP, declare nsec type as ranged integer instead of FIXNUM
Daniel Lowe <dlowe at bitmuse.com>**20090416204555] 
[clarification comment for the lispworks #_ situation
attila.lendvai at gmail.com**20090324135651
 Ignore-this: 1f97d85c23ecffd5806f7a3c137f8491
] 
[Less intrusive version of the Lispworks patch for #_.
Larry Clapp <larry at theclapp.org>**20090324132813
 
 Use an around method in ASDF's compile-op to set the readtable to ignore #_.
 This achieves the same end, but more elegantly, and doesn't pollute the
 regular readtable.
] 
[be more conservative when installing global reader macros as a lispwork workaround
attila.lendvai at gmail.com**20090323142133
 Ignore-this: dca64a6f7daa4d478beba41d1c102a16
] 
[Work with Lispworks
Larry Clapp <larry at theclapp.org>**20090323132602
 
 - Added a dummy reader macro for #_ so the
 
     #+ccl
     (... #_gettimeofday ... )
     
   doesn't break the compile
 - Fix %unix-gettimeofday for Lisps other than CMU, SBCL, and CCL.
] 
[TAG local-time-1.0.1
Daniel Lowe <dlowe at bitmuse.com>**20090312154109] 
Patch bundle hash:
f755fcabbb233c18fe2987311facd95aec666ae6


More information about the local-time-devel mailing list