Zach’s ugly mug (his face)

Zach Leatherman

Yet Another Pretty Date JavaScript

23 Mar 2008 Zach Leatherman

I can’t let this Pretty Date thing go. I decided to use a modification of John Resig’s Pretty Date JavaScript implementation written by Dean Landolt and shared in the comments on John’s page. The script was an obvious choice for the next iteration of Alarmd, which is nearing completion as I type.

The more I used Dean Landolt’s script, the more problems I began to see with his implementation. It was a good start, but definitely had bugs. His assumptions translating from integer second differences to human readable labels stretched too far at times (there is an error in logic to say anything between 24 hours and 48 hours from now can be labeled “Tomorrow”), and he was a bit loose with his difference categories (assumed average month length was 28 days, and always used Math.floor instead of rounding — 47 hours from now would be labeled “1 Day”). It was great code otherwise, and I definitely liked the way he used the while loop to run through the comparisons.

So, I’ve cleaned up his great start, and am releasing it to the world in the spirit of cooperation and open sauce. You just read that typo out loud didn’t you?

Download: Yet Another Pretty Date Implementation (2 KB)

Update: Dates for this script must have a specific ISO8601 format: YYYY-MM-DDTHH:MM:SSZ (in UTC) where T and Z are literals.

Update: This script has been moved to Github.

25 Comments

➡ Load Disqus to Leave a Comment ⬅

Thanks for the fixes. I actually can't take credit for introducing those bugs (just completely missing them) -- I got that piece of code from a comment on Resig's original post which was actually the imputus for me to do the rewrite in the first place...

I like your code a lot better than mine -- cleaner and easier to understand.

Zach Leatherman

25 Mar 2008 at 09:17PM

Thanks Dean. I wouldn't have even noticed the problems had I not been trying to use the script for a project.

Open source moves solely due to impetus sometimes.

Cool. This came in useful. Thanks for hacking this out.

Zach Leatherman

28 Mar 2008 at 04:15AM

I appreciate the comment. I hope someone else gets some good use out of it.

Zach,

Very nice! This is exactly what I was looking for.
Thanks for sharing!

it is really nice script.

Very nice work.

But there's something I really don't get: if I'm using a future date (think about a dtstart / dtend duet, like hCalendar does), the script treats them as past events!

If current year is 2008 and I'm planning some event for year 2009, the script says "1 Year Ago"! This is undoubtedly wrong! And should be avoided, of course.

For me, the problem resides in the first if clause: seconds should not be modified; if seconds are less than zero, then the script should do nothing, returning null.

A null returning would be very comfortable, allowing control statements as John Resig did in his original scripts; in particular, would be comfortable because you would not soil the innerHTML.

Also, if you avoid the token, all the script will instantly get more suitable for l10n, making the code more clean and readable.

OK. Wait a sec. My previous comment clearly shows that I did not understand anything about your script. I apologize for that.

But...

I (think I) found a glitch -- from now on consider all the dates & everything treated as UTC: if you set a date to exactly now (where "now" is the instant where the page loads) the script returns a "2 Hours" -- I mean: future!

Is to be said that I live in a country where right now the time zone is CEST that is GMT plus two hours (see Wikipedia for more), but, as you can easily imagine, in other countries this could vary: zero, one or two, like me, or even more.

Now: all your script runs using UTC (which is good), but at line 34 you add the current local time zone offset, which is wrong in my opinion.

I think that this should be fixed, but I look forward to your opinion.

Anyway, I still think that you should never touch a future date, and I still think that by removing the token you'll get a more compact, readable and elegant code.

PS: just FYI, here's my test case: http://phpfi.com/327787

Leaving the script vanilla, I get the glitch; removing the time zone offset I get the correct behavior.

Also, you can test this by adding some minutes: just modify the 'difference' variable in the HTML document.

I hope the whole thing is clearer now.

Have a nice day.

Zach Leatherman

08 Jan 2009 at 12:57AM

@unwiredbrain I tried to check out your test script and it would seem that the link is down.

Can you repost somewhere else, or include the code?

I developed this for alarmd, so you can see it in action there. If you add an alarm, it will create a pretty date in the bottom right corner.

For instance, I just added an alarm for +1h, resulting in 2009-01-08T02:56:38Z. I'm in CST (-6), which is is right (it's now 7:56PM).

Thanks,
Zach

Zach,

not receiving a reply for months I deleted all the relative documents; my documents deleted, phpfi.com down... Guess what? I had to recreate the glitch from scratch.

Let's assume my current system date is 2008-01-08;
Let's assume my current system time is 08:45:00;
Let's assume my current time zone offset is +0100;
Let's assume my current span looks like this:
<span class="dtstart" title="2009-01-08T08:45:00Z+0100">Some event that just happened</span>

On my test page, launching $(".dtstart").humane_dates() I will see "60 Minutes". Which is future.
That's exactly my current local time added with my current local time zone offset.

Apart from the glitch; being a future event, isn't it supposed to be left as it was -- i.e. not humanized at all?

I confirm what unwiredbrain says. The script adds the timezoneoffset to the current local time returning a humanized date that is in the future..

eg. '11 hours' no ago..

replacing line 34 with this fixes it for me:


seconds = ((dt - new Date(time)) / 1000),

Zach Leatherman

21 Jan 2009 at 04:34AM

I believe the script should work as intended (as is).

It should be noted that including a timezone offset into your markup date is not a supported use case for this script. Outputting UTC time only (no hardcoded offsets in the dates) allows for the JavaScript code to interpret the date to the offset of the client.

I believe that adding support for hardcoded timezone offsets would add unnecessary complexity to the code. Output Z +/- 0 and it will work fine.

That being said, if you disagree, feel free to modify the script and re-release it! It's all open source.

Whats are you trying to do with the .replace(/[TZ]/g, " ") call?

It ends up removing all the letter Ts. so some dates fail.

e.g. "Thu Feb 5 08:02:38 PST 2009" is parsed as
"hu Feb 5 08:02:38 PST 2009" and subsequently fails.

Zach Leatherman

17 Mar 2009 at 12:10AM

Hey Frank,
Take a look at the Original Script, it's intended to take ISO8601 dates, such as "2008-01-28T20:24:17Z"

The T and Z removal make more sense in that context.

Hi, I just find out this post from john post about pretty date.

@unwiredbrain
You must change the date to shown in title attribute into GMT. So it must written as:
Some event that just happened

See that it is 7:45 in GMT, because your timezone is +01:00.

The javascript will use the browser timezone setting, so the result will be correct.

If you are using PHP in the server-side, this is the code to change timestamp into GMT (using server's timezone setting), then format it to become ISO.

http://pastie.org/450720

@webmack

The line 34 is to overcome the timezone setting in user's browser. Since the calculation is done in each user browser, the js script must know how much the time different is.

If you remove the (dt.getTimezoneOffset() * 60000) addition, all user browser is assumed at GMT.

The addition is proposed by Dean in the comment at john blog. So the date that must changed is the one in the html. It must in GMT.

Check my previous comment to find the way to convert local server date into GMT, then show it as ISO format using PHP.

Has anyone else noticed that this script, when implemented with JQuery, will not work on firefox 3? I'm trying to find a solution, but currently it just outputs the original date string, and does not format it...

Zach Leatherman

12 Jun 2009 at 01:03AM

I use the script in ALARMd, so I know that it works in Firefox 3. What date are you trying to transform that doesn't work?

Hi there, If you can help you will end hours of head scratching. The dates i'm working with look like: 2009-06-03 20:06:44+0000
Firefox finds this as an invalid date.

Zach Leatherman

13 Jun 2009 at 01:38PM

Hey Tristan, as mentioned in some of the previous comments, your dates should be ISO8601 using GMT:
2009-06-03T20:06:44Z

Thanks!

Small tweak, it wasn't accounting for GMT time, thus, it parsed 10:00 am CST, which is 15:00 GMT time, and told me "5 hours ago" when viewing it at 10:05 am. So I made the following change at line 34, but don't know how this will affect all cases:

seconds = ((dt - new Date(time) + ((-dt.getTimezoneOffset()/60) * 60000)) / 1000),

Zach Leatherman

05 Aug 2011 at 05:35PM

Hey Sherman,
You can make your modification to the GitHub repo and run the unit tests:
https://github.com/zachleat...

Feel free to put in a Pull Request and I'll merge it in.
Zach

Hey guys, I am pretty new to JS, but i am curious, if i wanted a date older than 4 weeks to say the actual date, how hard is that?

Example: instead of saying 1 month ago, how about just September 18 @ 10:06PM.

any feedback is appreciated. thanks.

You saved the day man !!! Thanks a lot