In Coding Challenge: Increment a date/timestamp string, ncm challenges us to "consider the string as a pure 14-digit number, with digits that have very odd add-with-carry relationships." Then think of a fun-to-code way to write a function that could be "a lot faster than calling mktime etc."
Besides losing the libary-call overhead, there are other reasons such a function could be made very fast. Assuming a random distribution of tiemstamps,
Interestingly, nobody seems interested in writing the function this way. It seems much more fun for people to focus on conciseness rather than performance.
For what it's worth, I wrote a Scheme version that does not allocate new objects, is tail recursive, uses functions that are likely to be inlined, and does multiplication and modulo only with constant powers of two, allowing compiler optimization into bitwise operations.
It is longer than the other posted solutions, but all the way through it focuses on finding the most common case, doing it, and returning immediately.
(define (timestamp-increment! timestamp) (timestamp-position-increment! timestamp 13))(define (timestamp-position-increment! timestamp pos) (let ((current-char (string-ref timestamp pos))) (case pos ((13 11 3 2 1 0) ; last digits of second, minute, all year digits (timestamp-position-increment-simple! timestamp pos current-char #\0 #\9)) ((12 10) ; first digits of second, minute (timestamp-position-increment-simple! timestamp pos current-char #\0 #\5)) ((9) ; last digit of hour (timestamp-position-increment-depending! timestamp pos current-char #\0 #\0 #\9 #\3 #\2)) ((8) ; first digit of hour (timestamp-position-increment-simple! timestamp pos current-char #\0 #\2)) ((7) ; last digit of day (timestamp-position-increment-day! timestamp pos current-char)) ((6) ; first digit of day (timestamp-position-increment-simple! timestamp pos current-char #\0 (if (february? timestamp) #\2 #\3))) ((5) ; last digit of month (timestamp-position-increment-depending! timestamp pos current-char #\0 #\1 #\9 #\2 #\1)) ((4) ; first digit of month (timestamp-position-increment-simple! timestamp pos current-char #\0 #\1)))))
(define (timestamp-position-increment-simple! timestamp pos current-char ch0 ch9) (if (char=? current-char ch9) (begin (string-set! timestamp pos ch0) (timestamp-position-increment! timestamp (- pos 1))) (string-set! timestamp pos (next-digit current-char))))
(define (next-digit ch) (integer->char (+ 1 (char->integer ch))))
(define (timestamp-position-increment-depending! timestamp pos current-char ch0 ch0-special ch9 ch9-special chprev-special) (if (and (char=? current-char ch9-special) (char=? (string-ref timestamp (- pos 1)) chprev-special)) (begin (string-set! timestamp pos ch0-special) (timestamp-position-increment! timestamp (- pos 1))) (timestamp-position-increment-simple! timestamp pos current-char ch0 ch9)))
(define (timestamp-position-increment-day! timestamp pos current-char) (let ((first-day-pos (string-ref timestamp (- pos 1)))) (case first-day-pos ((#\0 #\1) (timestamp-position-increment-simple! timestamp pos current-char #\0 #\9)) ((#\2) (if (char<? current-char #\8) (string-set! timestamp pos (next-digit current-char)) (if (february? timestamp) (timestamp-position-increment-simple! timestamp pos current-char #\1 (ly-day-char timestamp)) (timestamp-position-increment-simple! timestamp pos current-char #\0 #\9)))) ((#\3) (timestamp-position-increment-simple! timestamp pos current-char #\1 (case (string-ref timestamp (- pos 2)) ((#\2 #\3 #\5 #\7 #\8 #\0) #\1) ; 31 in December, March, etc. ((#\1) (if (char=? #\0 (string-ref timestamp (- pos 3))) #\1 ; 31 days in January, 30 in November #\0)) (else #\0)))))))
(define (ly-day-char timestamp) (if (positive? (mod4 (string-ref timestamp 2) (string-ref timestamp 3))) #\8 ; year not a multiple of 4 (if (or (char<? #\0 (string-ref timestamp 2)) (char<? #\0 (string-ref timestamp 3))) #\9 ; multiple of 4 but not on a century (if (positive? (mod4 (string-ref timestamp 0) (string-ref timestamp 1))) #\8 ; multiple of 4 century #\9)))) ; regular century
(define (mod4 ch1 ch2) (modulo (+ (* 2 (modulo (char->integer ch1) 2)) (modulo (char->integer ch2) 4)) 4))
(define (february? timestamp) (and (char=? #\2 (string-ref timestamp 5)) (char=? #\0 (string-ref timestamp 4))))
I'm having fun with ncm's programming challenge. Here's a Scheme test harness for it, assuming you call the test function timestamp-increment!
(define test-values
'(("19991231235959" . "20000101000000")
("20000228235959" . "20000229000000")
("20000229235959" . "20000301000000")
("20040228235959" . "20040229000000")
("21000228235959" . "21000301000000")
("19000228235959" . "19000301000000")
("16000228235959" . "16000229000000")))
(define (test-answer q-a-pair)
(let ((a (string-copy (car q-a-pair))))
(timestamp-increment! a)
(if (string=? a (cdr q-a-pair))
'ok
(cons a q-a-pair))))
(define test-results
(map test-answer test-values))
My hosting provider is lame. JServ has not been running for some time. They never got back to me on any bug reports. I would finally phone them days later to get the latest promise. Now they say they're moving to JRun. We'll see. Meanwhile, the only place where I can demo BRL is BRL Cabaret. This is a free service shared by thousands of other apps, and the entire BRL environment gets unloaded after a short period of inactivity. This makes the first page load exceptionally slow. For now I'll wait and see how things go with my regular provider. If it doesn't improve I'll have to consider paying more than $17.95/month for servlet+db hosting.
12 Feb 2001 (updated 13 Feb 2001 at 14:46 UTC) »
#!/bin/sh # script to copy memo from Palm "advogato" category to diary # Memo must be filed under "advogato" and have 1st line "diary.txt" topdir=$HOME tmphtml=$topdir/diary$$.html memos -d $topdir cat > $tmphtml <<EOF <form method="POST" action="http://advogato.org/diary/post.html"> <textarea name="entry" EOF (echo ' cols=60 rows=16>' ; \ tail +2 $topdir/[Aa]dvogato/diary.txt \ | sed -e 's/&/\&/g' -e 's/</\</g' -e 's/>/\>/g') >> $tmphtml cat >> $tmphtml <<EOF </textarea> <p> <input type="submit" name=preview value="Preview"> <input type="hidden" name=key value="-1"> </form> EOF netscape -remote "OpenFile($tmphtml)"
FOAF updates: Trust rankings are now exported, making the data available to other users and websites. An external FOAF URI has been added, allowing users to link to an additional FOAF file.
Keep up with the latest Advogato features by reading the Advogato status blog.
If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!