Introduction to newLISP/Working with dates and times

Working with dates and times

edit

Date and time functions

edit

To work with dates and times, use the following functions:

  • date convert a seconds count to a date/time, or return date/time for now
  • date-value return the time in seconds since 1970-1-1 for a date and time, or for now
  • now return the current date/time information in a list
  • time-of-day return milliseconds since the start of today till now

date-value and now work in UT, not your local time. date can take account of the time difference between your local time and UT.

The current time and date

edit

All four functions can be used to return information about the current time. date-value returns the number of seconds between 1970 and the current time (in UT):

1142798985

and now returns a list of integers containing information about the current date and time (in UT):

(now)
;-> (2006 3 19 20 5 2 125475 78 1 0 0)

This provides the following information:

  • year, month, day (2006, 3, 19)
  • hour, minute, second, microsecond (20, 5, 2, 125475)
  • day of current year (78)
  • day of current week (1)
  • local time zone offset (in minutes west of GMT) (0)
  • daylight savings time flag (0)

To extract the information you want, use a slice or pick out the elements:

(slice (now) 0 3)             ; year month day using explicit slice
(0 3 (now))                   ; year month day using implicit slice
(select (now) '(0 1 2))        ; year month day using selection
(3 3 (now))                   ; hour minute second
(nth 8 (now))                 ; day of the week, starting from Sunday

date used on its own will give you the current date and time for the local time zone (now and date-value return values in UCT/UTC, not relative to your local time zone):

(date)
;-> "Mon Mar 19 20:05:02 2006"

It can also tell you the date of an integer number of seconds since 1970 (the start of the Unix epoch), adjusted for your local time zone:

(date 0)                                ; a US newLISP user sees this
;-> "Wed Dec 31 16:00:00 1969"
(date 0)                                ; a European newLISP user sees this
;-> "Thu Jan 1 01:00:00 1970"

date-value can calculate the number of seconds for a specific date or date/time (in UT):

(date-value 2006 5 11)                  ; just the date
;-> 1147305600

(date-value 2006 5 11 23 59 59)         ; date and time (in UT)
;-> 1147391999

Because date-value can accept the year, month, day, hours, minutes, and seconds as input, it can be applied to the output of now:

(apply date-value (now))         
;-> 1164723787

By converting different times to these date values, you can do calculations. For example, to subtract November 13 2003 from January 3 2005:

(- (date-value 2005 1 3) (date-value 2003 11 13))
;-> 36028800 
; seconds, which is

(/ 36028800 (* 24 60 60))
;-> 417 
; this is a duration in days - don't convert this to a date!

You can find out the date that is 12 days after Christmas Day 2005 by adding 12 days-worth of seconds to the date:

(+ (date-value 2005 12 25) (* 12 24 60 60)) 
; seconds in 12 days 
;-> 1136505600 
; this is an instant in time, so it can be converted!

This seconds value can be converted to a human-friendly date by date in its longer form, when it takes a seconds-since-1970 value and converts it to a local time zone representation of this UT-based value:

(date 1136505600)           
;-> "Fri Jan 6 00:00:00 2006"           ; for this European user...

Of course (date (date-value)) is the same as (date), but you'll have to use the longer form if you want to change the date format. date accepts an additional formatting string (preceded by a time-zone offset in minutes). If you're familiar with C-style strftime formatting, you'll know what to do:

(date (date-value) 0 "%Y-%m-%d %H:%M:%S")     ; ISO 8601
;-> 2006-06-08 11:55:08

(date 1136505600 0 "%Y-%m-%d %H:%M:%S")
;-> "2006-01-06 00:00:00"

(date (date-value) 0 "%Y%m%d-%H%M%S")         ; in London
;-> "20061207-144445"

(date (date-value) (* -8 60) "%Y%m%d-%H%M%S") ; in Los Angeles
;-> "20061207-064445"                         ; 8 hours offset

Reading dates and times: parse-date

edit

The parse-date function (which is, unfortunately, not available on Windows) can convert date and time strings to seconds-since-1970 values. You supply a date-time format string after the string:

(parse-date "2006-12-13" "%Y-%m-%d")
;-> 1165968000

(date (parse-date "2007-02-08 20:12" "%Y-%m-%d %H:%M"))
;-> "Thu Feb  8 20:12:00 2007"

Timing and timers

edit

For timing purposes, you can use these functions:

  • time return the time taken to evaluate an expression, in milliseconds
  • timer set a timer to wait for a certain number of seconds and then evaluate expression
  • sleep stop working for a certain number of milliseconds

time is useful for finding out how much time expressions take to evaluate:

(time (read-file "/Users/me/Music/iTunes/iTunes Music Library.xml"))
;-> 27                                  ; milliseconds

You can supply a repetition count as well, which probably gives a more accurate picture:

(time (for (x 1 1000) (factor x)) 100)  ; 100 repetitions
;-> 426

If you can't or don't want to enclose expressions, more simple timing can be done using time-of-day:

(set 'start-time (time-of-day))
(for (i 1 1000000)
  (set 'temp (sqrt i)))

(string {that took } (div (- (time-of-day) start-time) 1000) { seconds})
;-> "that took 0.238 seconds"

timer is basically an alarm clock. Set it and then forget about it until the time comes. You supply a symbol specifying the alarm action, followed by the number of seconds to wait:

(define (teas-brewed) 
 (println (date) " Your tea has brewed, sir!"))

(timer teas-brewed (* 3 60))

and three minutes later you'll see this:

Sun Mar 19 23:36:33 2006 Your tea has brewed, sir!

Without any arguments, this function returns the name of the current symbol that's been assigned as the alarm action:

(timer)
;-> teas-brewed

If you're waiting for the alarm to go off, and you're impatient to see how much time has elapsed so far, use the function with the name of the assigned symbol but without a seconds value:

(timer teas-brewed)
;-> 89.135747
; waited only a minute and a bit so far

For another example of the use of these functions, see Simple countdown timer.