time to read counter

posted in code with 0 comments

Like it or not as you will, but Medium has come to prominence lately as a place for thoughtful curated articles. Among other features that have caught my eye is the time to read counter, as shown in the topright corner of this screenshot: article screenshot

Depending on your desired level of accuracy in the counter (you can give an estimate almost down to the second), it can be easy or hard to do:

  1. Get word count of article.
  2. Get the average per-minute word count for an adult, and divide the article into this.
  3. Round either up or down to reach the nearest minute.
  4. (Optionally!) Turn this number into words.

To go beyond the basic solution: you could dive into per-word complexity and comprehension in a manner similar to Hemingway. Time average comprehension and reading time on a per-word basis, or track reading time for a sample set of articles by a random set of mixed lay and adept readers.

Words per minute
Reading speed doesn’t equal comprehension speed. Most people can read and recite quickly, but comprehension and retention will come more slowly. I’m above average-I clock in the ~513 WPM reading range, as averaged from three runs on the Staples speed-reading test. I am an avid and regular reader with a broad vocabulary, so don’t consider this empirical. A Forbes article gives a range of reading speeds, with an adult average of 300 words per minute. I think Medium will use a higher WPM number than this, because:

  1. A shorter given read time is more likely to lead to engagement. Time is precious after all.
  2. A higher assumed reading time will flatter in these circumstances. If you’re flattered, then you feel good.
  3. I have a suspicion that many readers on Medium are possibly already above average readers given their demographic (technically educated?).

But the most empirical WPM count I have remains 300, or 5 words per second.

Post WPM count
Word count in an article can vary by dependent on how you parse present markdown. Take the post “PSR J1719-1438 b’s surface gravity” and its mix of words and arithmetic:

  • The WordPress editor reports 165 words.
  • wc -w in the Bash shell reports 197 words.
  • str_word_count() without strip_tags() reports 270 words.
  • str_word_count() with strip_tags() reports 124 words.

I will use str_word_count(strip_tags($article) for this.
Words per second = words per minute, rounded.
Reading time = word count / words per second:

function rmwb_reading_seconds($post) {
    $average_wpm = 300;
    $average_wps = round($average_wpm / 60);
    $time = str_word_count(strip_tags($post));
    return round($time / $average_wps);

Medium rounds this time to the nearest minute. So will I:

function rmwb_reading_minutes($seconds) {
    if ($seconds % 60 <= 30) {
        $minutes = floor($seconds / 60);
    } else {
        $minutes = ceil($seconds / 60);

    return $minutes;

Call it all with:

function rmwb_reading_time($post) {
    $time = rmwb_reading_seconds($post);
    $time = rmwb_reading_minutes($time);
    $time_word = rmwb_minutes_to_words($time);
    $min_word = ($time <= 1) ? ' minute.' : ' minutes.';
    return ucfirst($time_word) . $min_word;

That’s it-you now have a time counter for your website.

Time to words
If you want to go be fancy and convert the minutes to words, then add this function too. The method I use for this is fairly close to my solution for Problem 17 of Project Euler.

function rmwb_minutes_to_words($minutes) {
    $time_word = '';

    $singles = array(

    $teens = array(
        'eleven', 'twelve','thirteen','fourteen','fifteen',

    $tens = array(

    if ($minutes <= 0) {
        // < 0 - 0
        $time_word = $singles[0];
    } elseif ($minutes < 10) {
        // 1 - 9
        $time_word = $singles[$minutes - 1];
    } elseif ($minutes > 10 && $minutes < 20) {
        // 11 - 19
        $time_word = $teens[$minutes - 11];
    } elseif ($minutes % 10 == 0) {
        // 10, 20, etc.
        $time_word = $tens[($minutes / 10) - 1];
    } elseif ($minutes > 99) {
        // > 99
        $a = $tens[8];   
        $b = $singles[8];
        $time_word = 'greater than' . $a . '-' . $b;
    } else {
        // 31, 56, 77, etc.
        $a = $tens[($minutes % 100) / 10 - 1];   
        $b = $singles[($minutes % 10) - 1];
        $time_word = $a . '-' . $b;

    return $time_word;

by Mark -

Debug a PHP script in JavaScript console

posted in code with 0 comments

Useful little tidbit if you don’t have access to the machine on which the script is run, but don’t want to spit PHP debug code all over the page:

<?php echo "<script>console.log('" . $message . "');</script>"; ?>
function browser_console_log($message) {
    echo "<script>console.log('" . $message . "');</script>";

by Mark -

PSR J1719-1438 b’s surface gravity

posted in astronomy with 0 comments

Comparison of Earth, PSR J1719-1438 b, and Jupiter

Diamond planets-specifically PSR J1719-1438 b-have my eye today. I tried to describe this chthonian planet to Eadaoin earlier, but I fell short because I couldn’t visualize some elements myself.

The formula for surface gravity of a planet is:

gplanet = G * M / r2

PSR J1719-1438 b has (both estimated) a mass of ~1.02 Mj and an equatorial radius of 0.4 Rj. So

Mplanet = (1.89813 * 1027) * 1.02 = 1.936572 * 1027
Rplanet = 69911 * 0.4 = 27964.4 = 2.27964 * 107
= (6.67 * 10-11) * (1.936572 * 1027) / (2.27964 * 107)2
= 248.55754152183457648718
= 248.55754152183457648718 / 9.81
= 25.3371601959 g

PSR J1719-1438 b’s surface gravity is ~25.3 times that of Earth. That isn’t too far off the Sun’s surface gravity of 27.94 g. You would die horribly, in agonizing pain, in several different simultaneous ways over the course of the following hour, while blind, if you ever set foot on PSR J1719-1438 b.

You would not, thankfully, die instantly! :)

by Mark -

Stick the footer to bottom of your document

posted in code with 0 comments

Fuck fucking CSS. I wasted two hours wanking with combinations of CSS and JavaScript with the goal of pinning the footer to the bottom of the page. The one that worked was convoluted, requiring two divs and an arcane spread of rules. The jQuery code below works better, and it doesn’t require phantom divs.

$(function() {
    // Sticky footer to bottom of page.
    var windowHeight = $(window).height();
    var footerHeight = $('footer').height();
    var footerTopPos = $('footer').position().top + footerHeight;

    if (footerTopPos < windowHeight)
        $('footer').css('margin-top', (windowHeight - footerTopPos) + 'px');

If the footer’s position from the top is less than the height of the window, add margin of the distance minus the footer’s height to the top of the footer.

by Mark -

The Corrib was drained this weekend

posted in ireland with 0 comments

For about twenty four hours, between Saturday night and earlier this evening, all of the gates at the fisheries weir were shut and thus the river was drained. Over a quarter of a century in Galway, on and off, and I’ve never chanced to see this. It was extraordinary to see the river almost completely drained, and if I had been brave there were spots where I could’ve crossed sides without getting a foot wet.

Drained River Corrib
Drained River Corrib
Drained River Corrib

by Mark -