Post #435

Redesign explained: time presentation

23rd July 2004, early evening | Comments (66)

Part one of the redesign explanations is going to look at time (specifically post and comment time), and how it gets presented on this site.

Presenting post times

The idea

Until recently I didn’t present post times (as different from post dates) on my blog, as I didn’t really see that they were relevant. However, the redesign got me looking at this area in a little more detail and I came to the conclusion that while an impersonal timestamp might not be very interesting, something with a more human touch might draw the eye in its place.

It’s a little long winded, but I wrote some code that helps present a more casual version of ‘post time’ to visitors. It also adds some emotion to the presentation, with phrases such as “Terribly early in the morning” or “Lunch time” conveying something more than “03:00” or “12:00”.

Here’s an example of it in action:

A screen shot showing a post title and its post times
A human-style timestamp: “late at night”

The code

Here’s the time_of_day() function:

  1. <?php
  2. // $hour must be 00-23 (in 24-hour clock)
  3. function time_of_day($hour)
  4. {
  5. switch($hour)
  6. {
  7. case 00:
  8. case 01:
  9. case 02:
  10. $tod = 'the wee hours';
  11. break;
  12. case 03:
  13. case 04:
  14. case 05:
  15. case 06:
  16. $tod = 'terribly early in the morning';
  17. break;
  18. case 07:
  19. case 08:
  20. case 09:
  21. $tod = 'early morning';
  22. break;
  23. case 10:
  24. $tod = 'mid-morning';
  25. break;
  26. case 11:
  27. $tod = 'late morning';
  28. break;
  29. case 12:
  30. case 13:
  31. $tod = 'lunch time';
  32. break;
  33. case 14:
  34. $tod = 'early afternoon';
  35. break;
  36. case 15:
  37. case 16:
  38. $tod = 'mid-afternoon';
  39. break;
  40. case 17:
  41. $tod = 'late afternoon';
  42. break;
  43. case 18:
  44. case 19:
  45. $tod = 'early evening';
  46. break;
  47. case 20:
  48. case 21:
  49. $tod = 'evening time';
  50. break;
  51. case 22:
  52. $tod = 'late evening';
  53. break;
  54. case 23:
  55. $tod = 'late at night';
  56. break;
  57. default:
  58. $tod = '';
  59. break;
  60. }
  61. return $tod;
  62. }
  63. ?>
  64. Download this code: 435a.txt

And here’s an example of how to call it:

  1. <?php
  2. // example usage of time_of_day()
  4. // I get $post_hour from the db using:
  5. // SELECT DATE_FORMAT(post_datetime, '%k') AS post_hour
  8. // Example 1
  9. // - - - - - - - - - - - - - - - - -
  10. // set post_hour
  11. $post_hour = 08;
  13. // set human-friendly post time
  14. $post_tod = time_of_day($post_hour);
  16. // debug
  17. print $post_tod;
  18. // > early morning
  21. // Example 2
  22. // - - - - - - - - - - - - - - - - -
  23. // set post_hour
  24. $post_hour = 21;
  26. // set human-friendly post time
  27. $post_tod = time_of_day($post_hour);
  29. // debug
  30. print $post_tod;
  31. // > evening time
  34. // Example 3
  35. // - - - - - - - - - - - - - - - - -
  36. // set post_hour
  37. $post_hour = 05;
  39. // set human-friendly post time
  40. $post_tod = time_of_day($post_hour);
  42. // debug
  43. print $post_tod;
  44. // > terribly early in the morning
  45. ?>
  46. Download this code: 435b.txt

Presenting comment times

The idea

Natalie Downe’s idea of showing post dates as time passed has become enormously popular on the web. It puts a twist on time-presentation which makes it a lot easier (for many people) to take in a glance, and I’m a big fan of anything that makes information more palatable. It occurred to me that a similar presentation method could be used to convey the age of a comment with respect to the post it related to; something I often want to know, but can’t be bothered to scroll up and down to compare dates.

To that end I added in a second (and optional) variable to time_since(), letting me specify a total of two dates. Now if I pass one variable to the function it calculates the time difference between that date and the current time, whereas if I pass two variables to the function it will calculate the difference between those two dates.

So, when presenting comment timestamps I pass time_since() two variables: the first represents the post’s UTC post time; and the second represents the comment’s UTC post time. The value that’s returned shows the time that passed between the post going live, and the comment being made.

And for those people who still want to know the exact moment the comment was made, the title text of this unusual timestamp contains all the information you could want.

Here’s an example of it in action:

A screen shot showing a comment’s post time as a timestamp
Comment post time can be seen in detail by hovering over the ‘time after the fact’ timestamp

The code

Here’s the time_since() function:

  1. <?php
  2. // adapted from original code by Natalie Downe
  3. //
  5. // inputs must be unix timestamp (seconds)
  6. // $newer_date variable is optional
  7. function time_since($older_date, $newer_date = false)
  8. {
  9. // array of time period chunks
  10. $chunks = array(
  11. array(60 * 60 * 24 * 365 , 'year'),
  12. array(60 * 60 * 24 * 30 , 'month'),
  13. array(60 * 60 * 24 * 7, 'week'),
  14. array(60 * 60 * 24 , 'day'),
  15. array(60 * 60 , 'hour'),
  16. array(60 , 'minute'),
  17. );
  19. // $newer_date will equal false if we want to know the time elapsed between a date and the current time
  20. // $newer_date will have a value if we want to work out time elapsed between two known dates
  21. $newer_date = ($newer_date == false) ? time() : $newer_date;
  23. // difference in seconds
  24. $since = $newer_date - $older_date;
  26. // we only want to output two chunks of time here, eg:
  27. // x years, xx months
  28. // x days, xx hours
  29. // so there's only two bits of calculation below:
  31. // step one: the first chunk
  32. for ($i = 0, $j = count($chunks); $i < $j; $i++)
  33. {
  34. $seconds = $chunks[$i][0];
  35. $name = $chunks[$i][1];
  37. // finding the biggest chunk (if the chunk fits, break)
  38. if (($count = floor($since / $seconds)) != 0)
  39. {
  40. break;
  41. }
  42. }
  44. // set output var
  45. $output = ($count == 1) ? '1 '.$name : "$count {$name}s";
  47. // step two: the second chunk
  48. if ($i + 1 < $j)
  49. {
  50. $seconds2 = $chunks[$i + 1][0];
  51. $name2 = $chunks[$i + 1][1];
  53. if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0)
  54. {
  55. // add to output var
  56. $output .= ($count2 == 1) ? ', 1 '.$name2 : ", $count2 {$name2}s";
  57. }
  58. }
  60. return $output;
  61. }
  62. ?>
  63. Download this code: 435c.txt

And here’s an example of how to call it:

  1. <?php
  2. // example usage of time_since()
  4. // I get $post_timestamp_utc from the db using:
  5. // SELECT UNIX_TIMESTAMP(post_datetime_utc) as post_timestamp_utc
  7. // I get $cmnt_timestamp_utc from the db using:
  8. // SELECT UNIX_TIMESTAMP(cmnt_date) as cmnt_timestamp_utc
  11. // Example 1 - using one variable
  12. // - - - - - - - - - - - - - - - - -
  13. // set post_timestamp_utc
  14. // 10:25:15 22/07/2004
  15. $post_timestamp_utc = 1090491915;
  17. // get the age of the post
  18. $post_age = time_since($post_timestamp_utc);
  20. // debug
  21. print $post_age;
  22. // > 13 hours, 51 minutes
  25. // Example 2 - using two variables
  26. // - - - - - - - - - - - - - - - - -
  27. // set post_timestamp_utc
  28. // 10:25:15 22/07/2004
  29. $post_timestamp_utc = 1088677515;
  31. // set cmnt_timestamp_utc
  32. // 22:08:09 24/07/2004
  33. $cmnt_timestamp_utc = 1090706889;
  35. // get time between post going live and comment being made
  36. $after_fact = time_since($post_timestamp_utc, $cmnt_timestamp_utc);
  38. // debug
  39. print $after_fact;
  40. // > 2 days, 11 hours
  41. ?>
  42. Download this code: 435d.txt

And that’s it, folks.

Jump up to the start of the post

Comments (66)

Jump down to the comment form ↓

  1. Rob Mientjes:

    I think I'm going to use some of your code on my newly coming blog (yes, I'm starting a second one, even more nonsense), because it can be quite handy. You always know how to implement those smart features in a fun way.

    By the way, did you get my mail about the strange time-afters? 'Posted -11 hours, 23 minutes after the fact' seems a bit of an absurd fast response.

    Posted 22 minutes after the fact
  2. Tony:

    Brilliant. Just brilliant. And you're sharing, which just makes it doublely brilliant.

    Thanks Dunstan.

    Posted 24 minutes after the fact
    Inspired: ↓ Jesse Perry
  3. Jesse Perry:

    id say more of a triple brilliancy. the dropdown info about the panorama is 100% awesome.

    good freakin job.

    Posted 29 minutes after the fact
    Inspired by: ↑ Tony
  4. Paul Griffin:

    Ever the altruist, eh Dunstan?

    Nice writeup. I hadn't even noticed the human-friendly post times yet, but that's a great idea.

    I'm going to stop reading your blog one of these days, because it really just serves as a constant reminder of how much I need to get cranking on revamping my site.

    Posted 44 minutes after the fact
  5. Rimantas:

    And then I thought - what if you combine this time with weather info... "one early rainy morning", "late windy evening". That sound like overkill, sure, but on the other hand... if do that only for non trivial weather? ;)

    Posted 52 minutes after the fact
    Inspired: ↓ Paul Griffin, ↓ Tom, ↓ Dunstan
  6. Paul Griffin:

    ...But then you'd be way too tempted to post something on a rainy night just because the time would say "a dark and stormy night" :P

    Posted 1 hour, 6 minutes after the fact
    Inspired by: ↑ Rimantas
    Inspired: ↓ Tom
  7. Ian McFarlan:

    Great job, Dustan. Really adds a personal, human touch instead of having an almost mechanical feel.

    Posted 1 hour, 9 minutes after the fact
  8. Ken Walker:

    Dunstan--lovely code highlighting, by the way. When do we get to read the write-up on how you did that? ;-)

    Posted 2 hours, 28 minutes after the fact
    Inspired: ↓ Dunstan
  9. Dunstan:

    Thanks Ken, it looks a bit funny in FF because the font is too big, but in Safari it's just right. I think I might write that up next, along with the image insertion script.

    Posted 2 hours, 38 minutes after the fact
    Inspired by: ↑ Ken Walker
    Inspired: ↓ Ken Walker
  10. Ssp:

    ... and I thought 4a.m. was 'rather late at night'.

    Another neat feature would be listing Sunday 2a.m. as Saturday night and so on. I always dislike when I post past midnight and the software displays a weekday that feels wrong.

    Posted 2 hours, 43 minutes after the fact
  11. Ken Walker:

    Actually, I think it's pretty good. So many browsers interpret [code] tags at, like, 8pt font or lower *cough*IE*cough*. It's refreshing to actually be able to read the code for a change.

    One thing I had thought about the other day was the idea of highlighting boilerplate code differently from the rest. Sometimes, when you're in a hurry to implement some scripting, it's overwhelming to see 46 lines of code and not know which parts of it you actually have to think about.

    Anyway, looking forward to more Super Dunstan Technologies (c)!

    Posted 2 hours, 54 minutes after the fact
    Inspired by: ↑ Dunstan
  12. Jeremy Flint:

    When I first started my site, and before installing WordPress, I marked the time of my posts in offhand ways like that as well:

    "just after lunch, in the vicinity of lunch, early afternoon, high noon, really late"

    Seemed to add a bit of personality to the site, as it does here. I had thought of maybe looking at modifying WP to do something similar, but never had the time.

    Good job, Dunstan.

    Posted 3 hours, 26 minutes after the fact
  13. Matthom:

    Love it. Thanks. Do I need "express written consent" to use these functions on my own site? I have just made the change, and implemented the function... I like it already.

    Posted 3 hours, 52 minutes after the fact
    Inspired: ↓ Dunstan
  14. Dunstan:

    Matthom, glad you like it, and yes, feel free to use the code :o)

    Posted 3 hours, 57 minutes after the fact
    Inspired by: ↑ Matthom
  15. Scott:

    Hey Dunstan! I just wanted to know how long you have been working with PHP. I have only just got the grasp on how to start a basic blog and I have been working with it for about 5 months. I was wondering how fast you got the grasp of PHP.

    Posted 6 hours, 49 minutes after the fact
  16. Tom:

    I'm already rapidly in the process of figuring out how to get this to work for me, but the weather tie in would be incredible. And yes, I'd be more likely to post on dark and stormy nights, but anything that encourages me to post can't be too bad, right? :)

    Great work Dunstan -- I love visiting your site.

    Posted 7 hours, 51 minutes after the fact
    Inspired by: ↑ Rimantas, ↑ Paul Griffin
  17. Comshares:

    Well, i think its, better if we use array to make greetings, based on time, coz the code will be less.

    Posted 8 hours, 43 minutes after the fact
  18. Colin D. Devroe:

    A little OT, but I miss the ability to click on a comment and see which comment it was a reply to.....however I am now using safari and perhaps this feature doesn't work in it.

    Posted 8 hours, 54 minutes after the fact
    Inspired: ↓ Dunstan
  19. Shawn Rice:

    I'm getting a very peculiar error when viewing the comments. The background image for Dunstan's posts is showing up along with the mouse over image. (a screencapture will explain this better than I can)

    It's only happening with that particular comment and only in Safari (on OS X Panther). I reloaded the browser a few times and it was still there. Anyone else experienceing this?

    Posted 11 hours, 32 minutes after the fact
    Inspired: ↓ Dunstan
  20. Dunstan:

    Shawn, I get that same error on certian posts, and that includes the one you highlight. I have no idea why it happens, but I'm going to be revisiting all the comment highlighting code soon so maybe I'll figure it out then. Very odd...

    Posted 14 hours, 44 minutes after the fact
    Inspired by: ↑ Shawn Rice
  21. Dunstan:

    Colin, I'm afraid it doesn't work on Safari (which is a bugger, as that's what I use as well). Mark Wubben says it's due to Safari's event handling, and I think he's right, as I've run into quite a few problems with triggering events in that browser. I don't think it's too reliable for this kind of thing.

    Posted 14 hours, 46 minutes after the fact
    Inspired by: ↑ Colin D. Devroe
    Inspired: ↓ Colin D. Devroe
  22. Dunstan:

    Rimantas, what a great idea! It might be overkill, but it's a cool concept, and one I'll bear in mind :o)

    Posted 14 hours, 48 minutes after the fact
    Inspired by: ↑ Rimantas
    Inspired: ↓ Mark Tranchant
  23. David House:

    Shouldn't the words 'the fact' in the permalink be linked to the top of the entry? Makes more sense that way.

    Oh, and the comment numbers bug [1] still is present. Just thought I should highlight this, it's quite annoying.


    Posted 15 hours, 8 minutes after the fact
  24. David House:

    Oh, and there is a shorter (albeit less intuitive) way of calculating the human-friendly timestamp:

    function time_of_date($hr) {
    $hr = (int)$hr;
    if (3 - $hr) { return 'the wee hours'; }
    if (7 - $hr) { return 'stupidly early'; }
    if (10 - $hr) { return 'early morning'; }
    //and so on

    Note that the first value in brackets, 3, 7, or 10 in my example above, is always one more than the largest hour value in that particular group - imagine what would happen if the hour was '02'. It should fall into 'the wee hours', but if we used '2 - $hr' that would return 0 and the if condition would fail. Hence we add one to the largest hour value in this group and use that instead.

    Posted 15 hours, 18 minutes after the fact
    Inspired: ↓ Steven Marshall, ↓ Dunstan
  25. Andrew:

    function time_of_day($hour)
    if ($hour > 24 || $hour < 0) return;
    if ($hour <= 3) $tod = 'the wee hours';
    if ($hour >= 3) $tod = 'terribly early in the morning';
    if ($hour >= 7) $tod = 'early morning';
    if ($hour == 10) $tod = 'mid-morning';
    if ($hour == 11) $tod = 'late morning';
    if ($hour >= 12) $tod = 'lunch time';
    if ($hour == 14) $tod = 'early afternoon';
    if ($hour >= 15) $tod = 'mid-afternoon';
    if ($hour == 17) $tod = 'late-afternoon';
    if ($hour >= 18) $tod = 'early evening';
    if ($hour >= 20) $tod = 'evening time';
    if ($hour == 22) $tod = 'late evening';
    if ($hour >= 23) $tod = 'late at night';
    return $tod;

    Is much shorter, i ran this code compared to your code, in a for loop from 0 to 24:

    0 = the wee hours - the wee hours
    1 = the wee hours - the wee hours
    2 = the wee hours - the wee hours
    3 = terribly early in the morning - terribly early in the morning
    4 = terribly early in the morning - terribly early in the morning
    5 = terribly early in the morning - terribly early in the morning
    6 = terribly early in the morning - terribly early in the morning
    7 = early morning - early morning
    8 = early morning -
    9 = early morning -
    10 = mid-morning - mid-morning
    11 = late morning - late morning
    12 = lunch time - lunch time
    13 = lunch time - lunch time
    14 = early afternoon - early afternoon
    15 = mid-afternoon - mid-afternoon
    16 = mid-afternoon - mid-afternoon
    17 = late-afternoon - late afternoon
    18 = early evening - early evening
    19 = early evening - early evening
    20 = evening time - evening time
    21 = evening time - evening time
    22 = late evening - late evening
    23 = late at night - late at night
    24 = late at night -

    Mines on the left, yours is on the right

    hth =)

    Posted 15 hours, 24 minutes after the fact
    Inspired: ↓ Steven Marshall, ↓ Dunstan
  26. Steven Marshall:

    David, Andrew: Dunstan's current code is actually far more CPU/memory efficient than either of your implementations. Perhaps it is a little less visually compact, but both your implementations use repeated ifs (as opposed to a switch or an if-else-if-else). This means that, when executing the code, the system will have to do numerous (expensive) comparisons and register loads, whereas Dunstan's code does considerably fewer - the system will treat the switch block as one logical operation block so, no matter where the case is in the block, you will get roughly equal performance* (assuming equivalent operations in each case statement). In both your code blocks, the last condition in the code block will take considerably longer than the first or second (and so forth) because each if block is counted as a seperate operation (meaning more loads from memory, and so forth). Not only that, but Dunstan's switch block requires far less branch prediction and pipeline clearing than your solutions. In general, for simple "value selection" operations such as this, use of a switch block will be far more resource-efficient than if blocks, because that's what switch is designed for.

    *The operations will be something like this, as far as the system is concerned:
    Dunstan's code:
    Ok, here's the time of day, which of the following values is it: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, or something else? Oh, it's 7, let's store "early in the morning".
    Send our stored value back.

    David's code:
    Ok here's the time of day, if we subtract it from 3, do we get an integer equivalent to true? No.
    Ok here's the time of day, if we subtract it from 7, do we get an integer equivalent to true? No.
    Ok here's the time of day, if we subtract it from 10, do we get an integer equivalent to true? Yes, let's send 'early morning' back.

    Andrew's code:
    Ok here's the time of day, is it greater than 24 or less than 0? No.
    Ok here's the time of day, is it less than or equal to 3? No.
    Ok here's the time of day, is it greater than or equal to 3? Yes, let's store "terribly early in the morning".
    Ok here's the time of day, is it greater than or equal to 7? Yes, let's store "early in the morning".
    Ok here's the time of day, is it equal to 10? No.
    Ok here's the time of day, is it equal to 11? No.
    Ok here's the time of day, is it greater than or equal to 12? No.
    Ok here's the time of day, is it equal to 14? No.
    Ok here's the time of day, is it greater than or equal to 15? No.
    Ok here's the time of day, is it equal to 17? No.
    Ok here's the time of day, is it greater than or equal to 18? No.
    Ok here's the time of day, is it greater than or equal to 20? No.
    Ok here's the time of day, is it equal to 22? No.
    Ok here's the time of day, is it greater than or eqaul to 23? No.
    Send our stored value back.

    As can be seen by this example (which is basically how the code will execute, give or take a few runtime optimisations, and ignoring branch prediction, et al.), Dunstan's switch is the most efficient. Both David's and Andrew's are very resource intensive for the 'late at night' values, Andrew's especially so - it would have to make at least six writes to the return value, and would have to read it's input $hour 15 times (not taking into account any caching), compared to 12 $hr reads (I think) for David's code and one memory write, and one $hour read for Dunstan's, and one memory write.

    Again, I'm not taking into account the relative costs of subtractions and comparisons and so forth, but even with those considered, Dunstan's switch is still far more efficient than either alterative.

    Dunstan: Good work with the redesign so far, I'm liking it more and more as I use it, and I may just have to crib some of your time presentation ideas ;)

    Posted 16 hours, 32 minutes after the fact
    Inspired by: ↑ David House, ↑ Andrew
    Inspired: ↓ Rob Mientjes, ↓ David House, ↓ Dunstan
  27. Rob Mientjes:

    You're right. The kilobytes aren't more important than the serverload. A SWITCH is always handy, and I couldn't live without them, but this ingenious use of a SWITCH is just magnificent. And about the time presentation, check out the post explaining the comment highlighting system [1] and the following comments. Posted about like one year before the fact. Odd, to say the least.


    Posted 16 hours, 45 minutes after the fact
    Inspired by: ↑ Steven Marshall
    Inspired: ↓ David House
  28. Phu:

    With Dunstan's permission, I've knocked up a Wordpress Plugin that provides an implementation of the Time of Day function:

    Usage instructions can be found at:

    Posted 16 hours, 53 minutes after the fact
    Inspired: ↓ Kitta
  29. David House:

    Yes, good point: thanks for pointing that out. In fact, after a bit of testing, my function tended to run at about 0.000001 seconds faster than Andrew's, but Dunstan's blew us both away running at roughly 0.000005 faster than either of our algorithms.

    Notes on testing: I used two calls to microtime() to time the tests, one before calling each algorithm and one after (and then obviously subtracting the second from the first). I set up a for loop to run 10 times, adding at each loop the time taken for each algorithm a variable (either $david_avg, $andrew_avg or $dunstan_avg), then divided each of these numbers by 10, rounded them to 7 decimal places using number_format, then echoed them. The literal number 23 was passed to each algorithim, this should be the number that takes the longest. The source code is available (and is probably clearer than my explanation) at

    Posted 18 hours, 48 minutes after the fact
    Inspired by: ↑ Steven Marshall, ↑ Rob Mientjes
    Inspired: ↓ Steven Marshall
  30. Andrew:

    I agree with most of your comments, but i think 0.000005 seconds isnt going to make that much of a difference, its not like its being called 10,000 or 100,000 times a second. ^_^

    Posted 19 hours, 17 minutes after the fact
    Inspired: ↓ Steven Marshall
  31. Andrew:

    Note that wasnt saying mine is better, i agree using switch would be, but im just saying its not something worth making a big deal over.

    Posted 19 hours, 19 minutes after the fact
    Inspired: ↓ Steven Marshall
  32. Steven Marshall:

    Admittedly not, Andrew, but it's the little things like these that can make all the difference, say, when one is slashdotted.

    The only reason I care about that sorta thing is because a) I'm anal and b) I do this sort of thing for my living on a million-plus-hits-per-day corporate website (not an "I'm better than you", because I'm most likely not, just a qualifier for why in the nine hells I'd worry about 0.000005 of a second; for what it's worth, it's et al.*).

    Whilst 0.000005 seconds won't make much of a difference in general, it's more a matter of best practices than anything - when the edge case does come into being, wouldn't you rather be prepared than have to pick your steaming pile of server up after it's been melted by too much traffic? ;)
    Not only that, but a switch is ever so slightly easier to read and maintain, usually.

    *N.B. I cannot be held responsible for the positively atrocious design and HTML/CSS on that site... Well, not yet, anyway. Blame our online marketing team. I'm currently making a business case for why, in our next incarnation of our CMS, we should be outputting completely valid XHTML 1.1 and CSS2, with a minimum of JavaScript.

    Posted 21 hours, 45 minutes after the fact
    Inspired by: ↑ David House, ↑ Andrew, ↑ Andrew
    Inspired: ↓ Rob Mientjes
  33. Colin D. Devroe:

    Dunstan, perhaps as Safari gets better, this functionality will become valid and work one day. Either way, the site works nicely in Safari.

    Posted 21 hours, 46 minutes after the fact
    Inspired by: ↑ Dunstan
  34. Rob Mientjes:

    That is a good case. It can't be noted too many times that CSS and XHTML are good partners when it comes to bandwidth, serverload and of course easy editability. IMO, all big companies should do this, and save money overall. Of course, the back-end is important too. Ask a friend of mine: he's pretty happy with me asking him to deliver XHTML compliant outputs on CMSes for our to-be company. He knows it's easy for us and for the clients, and well, PHP => XHTML + CSS = superb. Thanks again, Dunstan, for enlightening us with your outrageously handy code.

    Posted 21 hours, 57 minutes after the fact
    Inspired by: ↑ Steven Marshall
  35. Kitta:

    Thanks Phu (and of course Dunstan). :o)

    Posted 22 hours, 10 minutes after the fact
    Inspired by: ↑ Phu
  36. Dunstan:

    Thanks for that post Steve, it's nice to see some figures.

    I coded as I did because, as you say, a) it's nice and simple to understand, and so easier to maintain, and b) because of the efficiency of the switch. (I'm a big fan of switches.)

    p.s. That siemens site must be a nightmare IA-wise, I seem to recall it's huge!

    Posted 1 day, 5 hours after the fact
    Inspired by: ↑ Steven Marshall
    Inspired: ↓ Steven Marshall
  37. Dunstan:

    Andrew, thanks for your alternative code, but remember that the 24hr clock never actually reaches 24:00! It's 23:59, and then 00:00 :o)

    But always nice to see a different appraoch, so thanks for the comment.

    Posted 1 day, 5 hours after the fact
    Inspired by: ↑ Andrew
  38. Dunstan:

    Thanks for that David, as I said to Andrew, it's always nice to see an alternative approach.

    Posted 1 day, 5 hours after the fact
    Inspired by: ↑ David House
  39. Pintu:

    Nice Idea, More Human TOuch to Blogs make them more reader friendly.

    Posted 1 day, 14 hours after the fact
  40. Steven Marshall:

    You mean we're supposed to do IA on websites?!? :P

    Unfortunately, I don't get to have any involvement in the design process or the IA processes of our websites (I assume they do exist, although it's likely at a very basic level or possibly not at all!)

    If I had, things might be very different...
    As it stands, the main decision makers in the design and IA process were an external company and our CEO.

    That said, I'm doing my damndest to correct all the issues that're in our current site as we speak, but unfortunately our version 2 (XHTML/CSS2 compliant) CMS won't roll out for a good few months yet. Still, I think we'll be the first major computer hardware supplier worldwide to output valid XHTML and CSS2 (IBM, Dell, Microsoft, and many others don't...).

    Posted 1 day, 15 hours after the fact
    Inspired by: ↑ Dunstan
  41. Simon Willison:

    Dunstan: any idea why your comments above are displayed with incorrect list numbers next to them? Is that deliberate?

    Posted 2 days, 4 hours after the fact
    Inspired: ↓ Dunstan
  42. Dunstan:

    Simon, it's not deliberate, it's a bug in the browsers. They (sometimes) reset the ordered-list numbering when they get to one of my (class="dunstan") comments. I have no idea why, but I'm going to investigate when I get some spare time.

    Odd, eh?

    Posted 2 days, 4 hours after the fact
    Inspired by: ↑ Simon Willison
  43. Rob:

    I have been a big fan of this, and on my site I have a greeting which changes with the time of day.
    (Mostly inspired by answering the phones on my placement job :'( )

    However the biggest problem I found was that using php it was only possible to get the server time, which is great if all your visitors are from the same country, well not even that if you are from the States where you have 8/7 central etc :p [/English ignorance]

    Originally I used flash to do this which provided a client side alternative, but whilst trying to get a valid layout and lower my use of flash I switched to PHP, which is great but not if you are from America and can’t understand why my site is saying Good Afternoon when you have just got into work (and no I’m sure you boss won’t take it as a valid excuse to go home).

    I’m therefore looking into a method to do the process in Java Script with a back up of PHP for those who aren’t using it.

    Wouldn’t it be nice if we all surfed with internet passports which said what time zone, currency, and language we uses… shame Microsoft came up with the idea an not some one capable of implementing it :p

    Posted 2 days, 15 hours after the fact
  44. Danithew:

    I see that this code is now a plugin available at the Wordpress Wiki. Thanks for sharing!

    Posted 2 days, 18 hours after the fact
  45. Mark Tranchant:

    "It might be overkill, but it's a cool concept"

    Since when has overkill ever been a restriction on your blog?

    Posted 2 days, 20 hours after the fact
    Inspired by: ↑ Dunstan
  46. Aryan:

    Hey dunstan,
    I really like the new design, it has an "apple-like" (the panaroma window in particular) feel to it. Perhapes you should apply for a job at apple in their UI department (or whatever they call it), I'm sure they'll be happy to have you. :p
    Maybe you should also give the user the ability to deselect a selected comment by clicking on it again. ;)

    Posted 3 days after the fact
    Inspired: ↓ Dunstan
  47. Dunstan:

    Aryan, that would then cause a problem if you decided you wanted to click on the checkbox, or click-drag select some text. The comment would be unselected.

    The CSS and Javascript for the comments needs an overhaul at some point, I'm not very pleased with the way it's working right now.

    Thanks for the suggestion though.

    Posted 3 days, 1 hour after the fact
    Inspired by: ↑ Aryan
  48. George:

    I think you should take those sheep inside in the rain and snow. They get cold and wet.

    Posted 4 days, 12 hours after the fact
  49. Chris Hester:

    I'd have used an array to store the time phrases and just referenced that. Something like this (untested):

    First, define each phrase:

    $ph1 = "the wee hours";
    $ph2 = "terribly early in the morning";
    $ph3 = "early morning";
    $ph4 = "mid-morning";
    $ph5 = "late morning";
    $ph6 = "lunch time";
    $ph7 = "early afternoon";
    $ph8 = "mid-afternoon";
    $ph9 = "late afternoon";
    $ph10 = "early evening";
    $ph11 = "evening time";
    $ph12 = "late evening";
    $ph13 = "late at night";

    Now store them in an array (line-breaks for clarity here):

    $phrase = array(

    Now, assuming the hour to be a round number from 0 to 23, just use the hour to reference the array like this:

    echo $phrase[$hour];

    So if $hour is "12", the array gives you $ph5 which is "late morning". (Remember arrays start at 0 not 1.)

    Would that be easier?

    Posted 5 days, 2 hours after the fact
    Inspired: ↓ Nick Brogna, ↓ Nick Brogna
  50. CLINT:


    very impressive, and I applaud the human element within the coding, its a theme I see you execute well within the scope of the entire site.

    Posted 5 days, 21 hours after the fact
  51. Nick Brogna:

    Chris, the problem with your array solution, as it was presented, is that when using 24h time the hour parameter that gets passed to time_of_day() uses two digits (i.e. 08 for 8:00 AM) yet the corresponding indexes in the $phrase use only a single digit. I believe that to use that solution, you would need to strip that leading "0" off all times from midnight to nine AM which would be more work than merely using a switch structure, IMHO. :)

    Posted 2 weeks, 5 days after the fact
    Inspired by: ↑ Chris Hester
    Inspired: ↓ Chris Hester
  52. Nick Brogna:

    Actually, after hitting "submit" I realized that you could use that solution as it stands, however you would need to use an associative array like:

    $phrase = array(
    [00] => $ph13,
    [01] => $ph13,
    [02] => $ph1,

    ...and so on. At least it'd be simpler than stripping the leading "0"...

    Posted 2 weeks, 5 days after the fact
    Inspired by: ↑ Chris Hester
    Inspired: ↓ Chris Hester
  53. Chris Hester:

    The array should work fine as PHP is able to handle 24-hour dates that do not use two-digits for numbers less than 10. Checking the page below, you can easily convert the unix timestamp (server's date) into a format that goes from 0 (not "00") to 23 for hours. It's the "G" date setting:

    Of course I don't know how Dunstan is processing his dates and times with PHP.

    Posted 3 weeks after the fact
    Inspired by: ↑ Nick Brogna
  54. Chris Hester:

    Ah wait, I see Dunstan is pulling the date from his database, giving an example with a zero fronting it, eg: "08" for the hour. Well no problem there either. All you have to do is strip the zero first before calling the array.

    There are at least two ways I can think of to do this. One is using this function:

    Make it check only the first character. If it's a zero, replace it with nothing (eg: ""). Only one line of extra code needed!

    Or you could do a regex.

    Anyway, who knows, my array might work as is. Perhaps PHP can recognize that "03" means "3" and return the same result. I admit I haven't tested my code!

    Posted 3 weeks after the fact
    Inspired by: ↑ Nick Brogna
  55. Chris Hester:

    Finally tested my code. It works!

    Add this to the bottom of my code above to test it:

    $hour = 0;

    while ($hour < 24) {
    echo "When hour = $hour, phrase = ".$phrase[$hour]."<br />";

    Posted 3 weeks, 1 day after the fact
  56. Chris Hester:

    D'oh! My test code was using dates without leading zeros. Here's a better piece of code. If the date is less than 10, I've made it chop off the first character (which will be a zero).

    Adjust the value of $hour to anything from "00" to "09" and it should work.

    $hour = "00";

    while ($hour < 24) {
    echo "When hour = $hour, phrase = ";
    if ($hour < 10) {$hour = substr($hour,-1);}
    echo $phrase[$hour]."<br />";

    Posted 3 weeks, 1 day after the fact
  57. Jay Smith:

    The human-friendly time component has now been implemented as a plugin for textpattern:

    Posted 3 weeks, 2 days after the fact
  58. Ramanan:

    Oh, I forgot to post that here. I wrote the Textpattern plugin that generates your friendly times. I hope you don't mind. It was requested on the textpattern forum.

    Posted 3 weeks, 4 days after the fact
  59. Chris:

    I feel a bit sheepish asking this question, but here goes:

    This is a nifty piece of work here, and everything I've read has been entirely positive. But being a rather novice with wordpress, how does one implement it? Do we download it, rename it to .php and put it in plug-ins? Do we simply inject it into the wordpress index and call it from there?

    Sorry if this is irritating, I've been quite eager to use this but have been frustrated with my lack of prowess!

    Posted 3 weeks, 4 days after the fact
    Inspired: ↓ Dunstan
  60. Dunstan:

    Chris, you can't directly use my code for WordPress, you'll have to go find one of the many WP plugins that people have written since I posted this entry and implement that.

    For example, here's Michael's version:

    Posted 4 weeks after the fact
    Inspired by: ↑ Chris
  61. Rick Yribe:

    Dunstan, I love you. I was struggling to get a Word Press version of your code implemented on the redesign of my site that I'm working on right now. I almost gave up, but came here, copied your code, changed a few things, and BAM, everything worked perfectly.

    I appreciate your generosity in handing this code out. :)

    Posted 1 month, 3 weeks after the fact
  62. Olivier:

    You should put the hour values in quotes (case '02':) or remove the leading zeroes (case 2:) in your time_of_day() function. It seems to work as it is but there's a catch.

    In PHP, writing 02 without quotes means the octal value 2 (I was reminded of it just yesterday when I read about the chmod function in the PHP documentation. It expects an octal value like 0755, which is very different from 755 as its decimal value is 493). Therefore, 2, 02, '2', '02', "2" and "02" are all equal, at least when tested using the == operator or in a case structure.

    However, 08 and 09 make no sense to PHP, because 8 and 9 are not octal digits. Therefore it treats them as zero. So when you pass "08" or "09" to time_of_day(), there is no case that matches the value and it returns the empty string. This happens only with 8 and 9, which is apparently not a very widespread time for weblog posting since no one noticed it before :-)

    Posted 9 months after the fact
  63. Craig C:

    I know Dunstan has closed shop on this blog, so this isn't so much a feature request/suggestion as a comment to the people who still find and read the blog when thinking about great design.

    I love the human readable time of day business! It was surprising when it was not linkable though.

    I think it would be interesting to get a list of all the "early morning" posts or what not. Particularly for people who stumble across a blog after it's been up for a few years and they're reading through the archive.

    Posted 1 year, 2 months after the fact
  64. Matt Schinckel:

    I've written a Smarty Tags version of this plugin for WordPress Multi-User (Blogsome).

    It uses exactly the logic from Dunstan's version (partly because if/elseif/else is the only logic seemingly available to Smarty).


    Posted 1 year, 2 months after the fact
  65. Christopher:

    Has anybody seen a plugin that does the after the fact, (difference in time) between a post and the comments? I've either over looking the obvious... or this is something that hasn't been written yet.


    Posted 1 year, 5 months after the fact
  66. Mario:


    i want only to see how many days to this upcoming event. what i have to change in the php code? thanks. mario from east of germany ;O)!

    please send me an e-mail.

    Posted 1 year, 6 months after the fact

Jump up to the start of the post

Add your comment

I'm sorry, but comments can no longer be posted to this blog.