How to format the date in Drupal

Monday, December 11 2006

Updated, some error corrected and tested working on Drupal 5.

Possibly one of the most baroque settings to customize in Drupal is the date format; the Drupal user interface is not always so friendly with administrators looking to change default settings. Find here a complete how to for date formatting.

My own small contribution to the Drupal community, I hope the first one of a series, it's about the custom formatting of posts date. I struggled a lot with this and finally found the solution collecting infos here and there as it's quite common with Drupal since its user-submitted support is sometimes quite messy to deal with.

Credit goes to the following two posts where the original solution was taken from: How I can change format of type flexinode field datetime to DAY/MONTH/YEAR? and Formatting the way the date/time is displayed.

Please consider using the following tip at your own risk, as always the case for this kind of advices no warranty is given. Remember to backup all the files you are about to modify, before modifying them that is. This hack is based on Drupal 4.7.4, it should work also in 4.6 and in any 4.7.x. Consider I'm absolutely no PHP savvy, so forgive my mispelling of PHP conventions or some naiveté, this is a help tip for non programmers as I am. Also, I will be quite pedantic, in the hope this will help to understand every single step of the process.

Forget the date setting configuration menu you find in your Drupal user interface (you find that in administer > settings) this is of no use in this case while it's essentially helpful just for the time zone setting. (img. 1)

(img. 1) date settings in administer > settings

The files you have to modify are two: the system.module (you find it in the module folder) and common.inc (you find it in the includes folder). Open the two files with your text editor of choice and save a backup copy of the two (naming them BACKUPcommon.inc and BACKUPsystem.module is what I do). Now open again the two original files you will modify: common.inc and system.module.

Creating a new date format

Better to create a new custom date format, leaving the original offered ones as they are. To do this you have to declare your new format, that is create a new variable with your name of choice (PHP naming rules applies, so stick to a simple/non restricted name; i.e. mydate, myblogdate, jackdate, etc; datecustom is alreay there, so you cannot use it, unless you modify it instead of making one from scratch.)

In your system.module file use the find command of your text editor and look for Date settings: possible date formats, this should be at line 772, but line numbering may change depending on your Drupal version and/or configuration. You should have something like the following:

// Date settings: possible date formats
$dateshort = array('Y-m-d H:i','m/d/Y - H:i', 'd/m/Y - H:i', 'Y/m/d - H:i', 'd.m.Y - H:i', 'm/d/Y - g:ia', 'd/m/Y - g:ia', 'Y/m/d - g:ia', 'M j Y - H:i', 'j M Y - H:i', 'Y M j - H:i', 'M j Y - g:ia', 'j M Y - g:ia', 'Y M j - g:ia');
$datemedium = array('D, Y-m-d H:i', 'D, m/d/Y - H:i', 'D, d/m/Y - H:i', 'D, Y/m/d - H:i', 'F j, Y - H:i', 'j F, Y - H:i', 'Y, F j - H:i', 'D, m/d/Y - g:ia', 'D, d/m/Y - g:ia', 'D, Y/m/d - g:ia', 'F j, Y - g:ia', 'j F Y - g:ia', 'Y, F j - g:ia', 'j. F Y - G:i');
$datelong = array('l, F j, Y - H:i', 'l, j F, Y - H:i', 'l, Y, F j - H:i', 'l, F j, Y - g:ia', 'l, j F Y - g:ia', 'l, Y, F j - g:ia', 'l, j. F Y - G:i');

I won't go deep with the above (mainly because I'm not able to ;) ), what we have to know is that there you find the default given formats by Drupal: dateshort, datemedium, datelong, datecustom, all of them are preceded by the $ which is the PHP convention to define variables. To each of those variable is assigned a series of values they accept, that is the kind of date formatting they are allowed to support. We will see them in detail in a while. Now its your turn to create your own date format, this means we declare a new variable and assign to it the values we want the date to display.

Let's call our format myblogdate and assign to it the same values we find in the datecustom format, since for the time being we don't know how to render our intended format. The following is the resulting code after we added our own date format (remember to add the $ symbol before our myblogdate name); what I did was to copy the whole $datecustom = array('l, F j Y'); line and rename the variable name from datecustom to myblogdate:

// Date settings: possible date formats
$dateshort = array('Y-m-d H:i','m/d/Y - H:i', 'd/m/Y - H:i', 'Y/m/d - H:i', 'd.m.Y - H:i', 'm/d/Y - g:ia', 'd/m/Y - g:ia', 'Y/m/d - g:ia', 'M j Y - H:i', 'j M Y - H:i', 'Y M j - H:i', 'M j Y - g:ia', 'j M Y - g:ia', 'Y M j - g:ia');
$datemedium = array('D, Y-m-d H:i', 'D, m/d/Y - H:i', 'D, d/m/Y - H:i', 'D, Y/m/d - H:i', 'F j, Y - H:i', 'j F, Y - H:i', 'Y, F j - H:i', 'D, m/d/Y - g:ia', 'D, d/m/Y - g:ia', 'D, Y/m/d - g:ia', 'F j, Y - g:ia', 'j F Y - g:ia', 'Y, F j - g:ia', 'j. F Y - G:i');
$datelong = array('l, F j, Y - H:i', 'l, j F, Y - H:i', 'l, Y, F j - H:i', 'l, F j, Y - g:ia', 'l, j F Y - g:ia', 'l, Y, F j - g:ia', 'l, j. F Y - G:i');
$myblogdate = array('l, F j Y');

In this same file, look for the string Date settings: construct choices for user, it should be on line 790, but again this may change depending on your system configuration. What you'll have is something like:

// Date settings: construct choices for user foreach ($dateshort as $f) { $dateshortchoices[$f] = format_date(time(), 'custom', $f); }
foreach ($datemedium as $f) { $datemediumchoices[$f] = format_date(time(), 'custom', $f); }
foreach ($datelong as $f) { $datelongchoices[$f] = format_date(time(), 'custom', $f); }

Just add your new date format at the end of the above code:

// Date settings: construct choices for user foreach ($dateshort as $f) { $dateshortchoices[$f] = format_date(time(), 'custom', $f); }
foreach ($datemedium as $f) { $datemediumchoices[$f] = format_date(time(), 'custom', $f); }
foreach ($datelong as $f) { $datelongchoices[$f] = format_date(time(), 'custom', $f); }
foreach ($datemyblogdate as $f) { $datemyblogdatechoices[$f] = format_date(time(), 'custom', $f); }

Ok, this is done. Save your modified system.module and have a small break, relax, have a cup of coffee (all serious programmers drink coffee, y'know)... sorry, this was my yellow-dummy-book moment, forget it.

Make your myblogdate the default one

Now we have our own date format variable done, what we need is to tell Drupal to use it. To do this we have to go to the other file, the common.inc one. Again, open the common.inc file with your text editor, this time you have to look for the following text: switch ($type), what you will find is the following:

switch ($type) {
case 'small':
$format = variable_get('date_format_short', 'm/d/Y - H:i'); break;
case 'large':
$format = variable_get('date_format_long', 'l, F j, Y - H:i');
break;
case 'custom':
$format = variable_get('date_format_custom', 'l, F j Y');
break;
case 'medium':
default:
$format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
}

As before I won't go deep, the thing we see here is that we find all the date formats we had in the system.module file (here they are expressed after the case term and in parenthesis as: date_format_short, date_format_long, date_format_medium, date_format_custom) the only missing one is our own $myblogdate. It's up to us to put it in there. Please, note also the default thing (I put it in red to highlight it), this tells Drupal which one among the formats is the one that will be used; in my case this is set to medium but you may have a different setting. Also, pay attention to the break term, this is used to separate one format to the other.

What we do now is copy the lines starting from the last break term until the end of the above code:

break;
case 'medium':
default:
$format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
}

(If you have the default term assigned to another format (the short one, the long one or the custom one, copy the lines starting with the break just above the case 'XXX': part and ending with $format = variable_get('date_format_XXX', 'D, m/d/Y - H:i'); where XXX is the format name.)

And paste it at the and of that very same part of code, we will have something like this:

switch ($type) {
case 'small':
$format = variable_get('date_format_short', 'm/d/Y - H:i'); break;
case 'large':
$format = variable_get('date_format_long', 'l, F j, Y - H:i');
break;
case 'custom':
$format = variable_get('date_format_custom', 'l, F j Y');
break;
case 'medium':
default:
$format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
break;
case 'medium':
default:
$format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
}

We can see we have two times the same format, in this case the medium one. What we have to do is change the name of every occurence of medium in our pasted part with myblogdate, resulting in:

switch ($type) {
case 'small':
$format = variable_get('date_format_short', 'm/d/Y - H:i'); break;
case 'large':
$format = variable_get('date_format_long', 'l, F j, Y - H:i');
break;
case 'custom':
$format = variable_get('date_format_custom', 'l, F j Y');
break;
case 'medium':
default:
$format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
break;
case 'myblogdate':
default:
$format = variable_get('date_format_myblogdate', 'D, m/d/Y - H:i');
}

Two more things to do are to get rid of one default, leaving only the one assigned to myblogdate, and assign to myblogdate the same values we previously assigned in the system.module, that is: l, F j Y. The result will be:

switch ($type) {
case 'small':
$format = variable_get('date_format_short', 'm/d/Y - H:i'); break;
case 'large':
$format = variable_get('date_format_long', 'l, F j, Y - H:i');
break;
case 'custom':
$format = variable_get('date_format_custom', 'l, F j Y');
break;
case 'medium':
$format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
break;
case 'myblogdate':
default:
$format = variable_get('date_format_myblogdate', 'l, F j Y');
}

Ok, step two has been done, save the file. You deserve another small break.

To have a look at your new format date, upload the two files (system.module and common.inc) in their relevant folder on your blog server. And have a look at the result, yeah, I know... no more silly hours:minutes ;)

Some explanation on the format options

If you used my proposed l, F j Y format, your result will be like: Monday, 11 December 2006. Maybe this is not your preferred format, so find here the detailed meaning of each of those one letter abbreviations to deploy your format of choice (remember also you can separate each parte of the date with any of the following: (:), (.), (,), (/) )

  • a - am or pm
  • A - AM or PM
  • d - day of the month, 2 digits with leading zeros; i.e. 01 to 31
  • D - day of the week, textual, 3 letters; i.e. Fri
  • F - month, textual, long; i.e. January
  • h - hour, 12-hour format; i.e. 01 to 12
  • H - hour, 24-hour format; i.e. 00 to 23
  • g - hour, 12-hour format without leading zeros; i.e. 1 to 12
  • G - hour, 24-hour format without leading zeros; i.e. 0 to 23
  • i - minutes; i.e. 00 to 59
  • j - day of the month without leading zeros; i.e. 1 to 31
  • l (lowercase 'L') - day of the week, textual, long; i.e. Friday
  • L - boolean for whether it is a leap year; i.e. 0 or 1
  • m - month; i.e. 01 to 12
  • n - month without leading zeros; i.e. 1 to 12
  • M - month, textual, 3 letters; i.e. Jan
  • s - seconds; i.e. 00 to 59
  • S - English ordinal suffix, textual, 2 characters; i.e. th, nd
  • t - number of days in the given month; i.e. 28 to 31
  • U - seconds since the epoch
  • w - day of the week, numeric, i.e. 0 (Sunday) to 6 (Saturday)
  • Y - year, 4 digits; i.e. 1999
  • y - year, 2 digits; i.e. 99
  • z - day of the year; i.e. 0 to 365
  • Z - timezone offset in seconds (i.e. -43200 to 43200)

That's it, I hope everything is clear enough to help you sort out the whole date thing in Drupal. Good night, and good luck.

The editing bug

And you thought everything went smooth and neat, don't you? Well, not really. It looks like there's a small, annoying bug: if you have two post in the same day and you edit the last one you posted, that one will appear as earlier in respect to the other one, as it was posted before the one that's actually older. At the moment I did not find any solution, or clue; this is happening if you do not have the hours:minutes displayed (those Drupal guys should have something really personal with that h:m ;) ).

Post new comment

The content of this field is kept private and will not be shown publicly.

Get in Touch

Tags for this post

Subscribe to the feed!

What is this RSS thing? For help on subscribing and more options, or to subscribe to a particular category, please have a look at: RSS feed how to.

My del.icio.us tags

Journal of Contemporary Street Art

The Journal of Contemporary Street Art is printed on demand with lulu (lulu.com) and it mix street art photography with toponomy research.

Buy the Journal of Contemporary Street Art - JoCSA00

Support independent publishing: buy this book on Lulu - Buy the Journal of Contemporary Street Art (JoCSA00)

Aggregate Me!

My Google shared stuff

browse my shared stuff on Google

My friendfeed page

me on friendfeed.

Support Civil Liberties and Human Rights

Support EFF and Amnesty International, visit their web sites and find out how you can help.

Beijing 2008