Forum OpenACS Q&A: datetime to "Nice Dates"

Posted by MaineBob OConnor on

Is there a procedure that will take the postgresql datetime that appears as "2000-07-18 15:04:56-04" and convert it to: (based on sysdate)

  • Today at 3:04PM
  • Yesterday at 8:00PM
  • Tuesday, July 4th
  • Saturday, Dec 25, 1999

(Display changes based on today. Back on July 4th we might not care what the time is....

Or is there something close that I can modify to accomplish this?
TIA - Bob OConnor

Posted by Don Baccus on
There's nothing in either the OpenACS or Postgres distributions that does exactly this, no.
Posted by Michael A. Cleverly on
Given the examples you gave, I wrote the following Tcl procedure that do what you want:

proc pretty_pg_date {pg_date} {
    set pgtime [clock scan $pg_date]
    set now    [ns_time]
    set diff   [expr $now - $pgtime]
    if {$diff < 0} {
        set diff [expr abs($diff)]
        set neighbor Tomorrow
        set neighbor_day -86400
    } else {
        set neighbor Yesterday
        set neighbor_day 86400
    # 31536000 seconds in a 365-day year
    if {$diff > 31536000} {
        return [ns_fmttime $pgtime "%A, %b %e, %Y"]
    set pg_day_of_year [ns_fmttime $pgtime %j]
    set now_day_of_year [ns_fmttime $now %j]
    if {[string compare $pg_day_of_year $now_day_of_year] == 0} {
        return "Today at [string trimleft [ns_fmttime $pgtime %I:%M%p] 0]"
    set neighbor_day_of_year [ns_fmttime [expr $pgtime + $neighbor_day] %j]
    if {[string compare $now_day_of_year $neighbor_day_of_year] == 0} {
        return "$neighbor at [string trimleft [ns_fmttime $pgtime %I:%M%p] 0]"
    switch -- [ns_fmttime $pgtime %d] {
        01  -
        21  -
        31  { set suffix st }
        02  -
        22  { set suffix nd }
        03  { set suffix rd }
        default { set suffix th }
    return [ns_fmttime $pgtime "%A, %b %e"]$suffix
This will only work on AOLserver 3.0 (since AOLserver 2.3 is Tcl 7.4-based, and the clock scan command wasn't added until Tcl 7.6). It also only works on dates between the start of the epoch, up through integer overflow (ie January 1, 1970 — sometime in August(?) of 2038).
Posted by MaineBob OConnor on

Thanks Michael,

My plan is to make this another choice in the Regular admin page:
Where it says:

    Subject Line Suffix:
    (legal values are blank, "name", "email", "date", separated by spaces)

I've added a new item "kooldate" in the /tcl/bboard-defs.tcl file in the procedure called: "bboard_one_line_suffix". Also I added the whole procedure that Michael wrote just above this. I also discovered that every time I make a change to this file, I need to restart AOLServer. I'd be open to other ideas about where to put enhancements such as this or do I just have to make my own change list when a new OpenACS version arrives?

So now the error that is generated:

...Error: nsd.tcl: unable to convert date-time string "posting_time"
unable to convert date-time string "posting_time"
    while executing
"clock scan $pg_date"
    (procedure "pretty_pg_date" line 2)

#From the error log:
#Notice: The value of posting time is 2000-07-19 14:17:08-04

So it seems that clock scan doesn't work. I believe I'm using AOLServer 3.0. (Sysadmin Bill is away). How do I check for versions. Further---} Is there a quick way to check all versions and "subversions"!!! ?:

  • AOLServer
  • PostGresql
  • OpenACS


Posted by Jonathan Ellis on
Did you make sure your AOLServer's tcl is directed to the version 8 binary?  Check your bin directory; by default it will look like this:

lrwxrwxrwx    1 nsadmin  nsadmin        7 Jul  5 16:36 nsd -> ./nsd76*

-rwxr-xr-x    1 nsadmin  nsadmin  1703824 Jul  5 16:30 nsd76*

-rwxr-xr-x    1 nsadmin  nsadmin  2649930 Jul  5 16:30 nsd8x*

You want nsd to be a link to nsd8x instead of nsd76; cd to the bin dir and run "ln -sf nsd8x nsd".

Posted by Michael A. Cleverly on
The pretty_pg_date procedure as it stands above works fine with the example postgres date (in the original message) if and only if you are running the Tcl 8.2+ version of AOLserver. (In other words, nsd is linked to nsd8x, or you run nsd8x directly.)

The clock command does in fact exist in Tcl 7.6 (where it made it's original debut) but the 7.6 version does not know how to interpret a postgres style date. (Guess I should have verified it on both versions of nsd before posting... :-)

To make the procedure work on either nsd76 or nsd8x, add the following snipet of code above the call to clock scan:

# Tcl 7.6 does not know how to deal with a "YYYY-MM-DD ..." type of date like 8.2 does
if {[string compare [info tclversion] 7.6] == 0} {
    regsub {^([12][0-9][0-9][0-9])-([01][0-9])-([0-3][0-9])} $pg_date {//} pg_date
Posted by Michael A. Cleverly on
Strange... though the email alert version of my posting has the proper regsub substitution, the bboard HTML version ends up just replacing the YYYY-MM-DD with " / / " instead of "MM/DD/YYYY". Let me repost the regsub in a plaintext and hope it works:

regsub {^([12][0-9][0-9][0-9])-([01][0-9])-([0-3][0-9])} $pg_date
{//} pg_date

Posted by Michael A. Cleverly on
Ok, apparently I need to escape my backslashes when posting them in either HTML or plain text mode? One last try... :-)

regsub {^([12][0-9][0-9][0-9])-([01][0-9])-([0-3][0-9])} $pg_date
{//} pg_date

Posted by MaineBob OConnor on

Well, FAR OUT! And thanks, It works and it's optional using the /bboard/admin-home.tcl page by specifying kooldate instead of date.

It turns out that I'm using nsd8x and didn't need the tcl7.6 fix but I discovered that I had forgot the $ in the proc

and the line:
set kooldate [pretty_pg_date $posting_time]


Posted by Don Baccus on
A word of warning about Tcl 8.3 - there are apparently memory leaks that will eventually eat your server when running OpenACS.  The AOLserver site switched back to Tcl 7.6 because of this.  They are/were running 8.3 behind Digital City, I think maybe whatever statement(s) trigger the memory leak by chance aren't used there.

But OpenACS (and presumably ACS Classic) both trigger these memory leaks.


Kriston's been trying 8.3.1 but as of a few days ago didn't know if th e memory leak problem(s) been fixed.