Displaying MODX Date Fields

As a person who used to write code that had to run in 64K of memory, the way MODX date strings are sometimes handled has always disturbed me. I’m calling them date strings, but they are more correctly called date/time strings. I’m too lazy to type that over and over, so I’ll just be using the word ‘date’ to describe them.

MODX Date Fields

MODX stores dates like the Resource createdon, publishedon, and editedon fields as Unix timestamps. That means they’re just a big integer that contains the number of seconds since January 1st, 1970. This is great for doing date comparisons, computing the time interval between two dates, or seeing how long it’s been between a date and right now, but it’s not so great when you want to show a date to a site visitor.

To solve that problem, MODX automatically converts the timestamps to a human-readable date when you put a tag like this on a page:

[[*createdon]]

This conversion is done at a very low level by xPDO. In fact, when you get the date in code with something like this:

$d = $resource->get('createdon');

What you get back looks something like this:

2013-01-10 21:18:57

Somewhere in MODX I think there’s a place to set the format of that string, but a) I can never remember where, and b) I want different formats on different pages.

Setting the Date Format with Output Modifiers

PHP has a number of date-handling functions, but most of the time, you need either strtotime() or strftime() (usually both).

These two functions are complimentary. The strtotime() function converts a date like the one shown above to a Unix timestamp. It has evolved over the years to the point where it can turn almost any conceivable human-readable date into the correct timestamp. It will handle strings as varied as the following:

  • Tuesday, June 24 2008
  • June 1st 2013:22:34
  • 2012-01-03 7pm
  • 01-03-13 6 a.m.

In fact, it’s difficult to come up with a date and time it can’t handle.

The strftime() function does the opposite. It converts a Unix timestamp to a human-readable date. Its first argument specifies the format you want and it’s flexible enough to put the date in any reasonable form (with one exception: it won’t do things like 1st, fourth, or 2nd). The strftime() function also respects the current locale setting, which can be set with the locale MODX System Setting, or by a Context Setting or User Setting with the same name. You can also set the locale in code with PHP’s setLocale() method. That means, for example, that the day and month names will be translated into the appropriate language.

It’s easy to remember which function is which because strtotime() does exactly what its name implies, it converts a string to a timestamp. You can remember that strftime() converts a timestamp to a human-readable string because it has an f in the middle of it, which tells us it formats a timestamp.

Back to Our Problem

To help us format the date string they way we want, MODX provides two output modifiers, named strtotime and date. The first one one simply calls the strtotime() PHP function and returns the output. The second one (date) calls PHP’s strftime() function. Because the tag is already converted to a human-readable string before the first output modifier gets it, we need to convert it back to a Unix timestamp with the strtotime modifier, then format that timestamp with the date modifier.

[[*createdon:strtotime:date=`%A %B %d, %Y`]]

That will display something like this:

Monday January 10, 2011

Notice that any spaces or punctuation in the format string (e.g., commas, colons, or dashes) will be taken literally and output at their locations in the displayed string

Explaining all the possible tokens in the format string used with the date modifier is beyond the scope of this article, but they are very well documented here.

Another option if you’re working in code is the PHP date() function, though I seldom use it because it won’t respect the locale setting. Note that if you switch back and forth between strftime() and date(), the format strings are not the same.

So What’s My Problem

I mentioned above that this process disturbs me. It’s because not just one, but two completely unnecessary conversions are being performed in this process. The date is already a timestamp in the MODX database. It’s being converted to a human-readable string by xPDO, then back into the exact timestamp it was originally by the strtotime output modifier. Since parsing a format string is involved in both conversions, they take time. It’s a trivial amount of time, but because both conversions are technically unnecessary and because site visitors are waiting for the page to load, the process offends my sensibilities.

Take the example of a blog where the age of each post in months, days, and years is displayed. The calculation can’t be cached, because it changes constantly. If a page displays 10 posts and the conversion is done with output modifiers, every page load will be delayed by 20 unnecessary conversions. Of course this can be mitigated by caching, but when the cache is cleared, it happens all over again.

A Solution

Because xPDO does the first conversion from timestamp to human-readable date on every date you get, this can’t really be solved with output modifiers. Even a custom modifier is going to get passed the human-readable date. It can be solved in code, though.

There may be a better way to get a raw date field in code (PDO would certainly do it), but this works and will cut the processing time considerably. The MODX Resource fields are currently contained in the _fields member variable of the Resource object. So the raw timestamp for the createdon field is available as $resource->_fields['createdon']. That means that we can get the timestamp for any MODX Resource date field with a fairly simple snippet:

[[!DateFormat? &field=`createdon` &formatString=`%A %B %d, %Y'`]]

 

<?php
/* DateFormat snippet */
$field = $scriptProperties['field'];
$format = $scriptProperties['formatString'];

$timestamp = $modx->resource->_fields[$field];
return strftime($format, $timestamp);

This only solves the problem for the date fields of the current Resource, but with a little modification, the method could be used any time you have a Resource object in code and want to display one of its date fields. If you want to display a date field from another resource, you could pass the Resource’s ID in a &docId property in the tag, get the Resource object with $modx->getObject('modResource', $scriptProperties['docId']), and get the timestamp from its _fields member. You could also pass the pagetitle or alias, but that would be a little slower.

A Word of Warning

The _fields member of the Resource object is meant to be used internally. It’s not part of the official MODX database interface. That means it could stop working in a future version of MODX. I don’t think that’s likely any time soon, but if it were to happen, your date displays might be incorrect or blank. They could also throw a PHP error. You’d have to rewrite the snippet to correct the problem.

 


For more information on how to use MODX to create a web site, see my web site Bob’s Guides, or better yet, buy my book: MODX: The Official Guide.

Looking for quality MODX Web Hosting? Look no further than Arvixe Web Hosting!

Tags: , , , , , | Posted under MODX, MODX | RSS 2.0

Author Spotlight

Bob Ray

Bob Ray

I am the author of MODX: The Official Guide and over 30 MODX add-on components. I host Bob's Guides, a source of valuable information for MODX users, and I've been very active in the MODX Forums with over 14,000 posts.

Leave a Reply

Your email address will not be published. Required fields are marked *


9 − = 5

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>