Calculating a duration given a start and end time

Last modified: December 6, 2009 - 10:23

This example uses KarenS' date module to create two date fields field_start_time and field_end_time which record hours and minutes. We then create a new computed field to work out the duration as a decimal number of hours (so 1.5 is 1hour, 30minutes).

Computed field settings:

  • Computed Code:
    <?php
    $start_date
    = date_make_date($node->field_start_time[0]['value']);
    $start = $start_date->db->parts;
    $end_date = date_make_date($node->field_end_time[0]['value']);
    $end = $end_date->db->parts;
    $start_decimal = $start['hours'] + ($start['minutes'] / 60);
    $end_decimal = $end['hours'] + ($end['minutes'] / 60);
    $node_field[0]['value'] = $end_decimal - $start_decimal;
    ?>
  • Check 'Display this field'
  • Display Format:
    <?php
    $display
    = $node_field_item['value'] . " hours";
    ?>
  • Check 'Store using the database settings below
  • Data Type: float
  • Data Length: 3,2
  • Check 'Sortable'

Now if you set the start time field to 9am and the end time to 11:30am, your computed field will store the value '2.5' and display '2.5 hours'.

Interest rate?

Rosamunda - April 27, 2008 - 21:11

Could this (something similar) be applied to money to pay calculating the total debt with a certain interest rate?
It could be between dates calculated in months...

Anyone know how to make this

StuartDH - December 18, 2008 - 01:05

Anyone know how to make this work in D6?

Drupal 6 code.

cannod - June 11, 2009 - 12:41

Yes I spent a couple of hours getting it working with D6.
I changed the code a bit to make it more flexible.

Here is the computed code.
NOTE: change "$node->field_datefield" to the field name of your date field.

# Get the values from $node
$start_value = $node->field_datefield[0]['value'];
$end_value = $node->field_datefield[0]['value2'];
$timezone =  $node->field_datefield[0]['timezone'];
$type = $node->field_datefield[0]['date_type'];

# Get a date object from the values
$start_date = date_make_date($start_value, $timezone, $type);
$end_date = date_make_date($end_value, $timezone, $type);

# Call the date_difference function to get the difference between the two dates. Note you can specify the duration measure, either years, months, weeks, days, hours, minutes or seconds. I am using hours. The following line is taken from the date_difference function.
# date_difference($date1_in, $date2_in, $measure = 'seconds', $type = DATE_OBJECT)

$duration = date_difference($start_date, $end_date, 'hours');
$node_field[0]['value'] = "$duration";

And the display code.

$display = $node_field_item['value'];

Store in database.
Data type: float
data Length: 5,2
Sortable = checked.

Mix of Datetime and Date

sphopkins - August 21, 2009 - 16:09

Is it possible for this code to work on two fields where one is a datetime field and one is a date field?

"Only" alter one date

Ralf Saalmueller - December 14, 2009 - 17:07

Hello cannod,

hope you can help. I used your code and it is working. Great.

But I'm in need to alter one of the datefield values and lack the basic coder know how. How to I store a date? Even this simple, untouched copy doesn't work:
: $start_value = $node->field_datefield[0]['value'];
: $node_field[0]['value'] = $start_value;

Is it possible to handle datefields? How do handle multiple values. What is the display code for multiple data?

Background: My users found a way to misuse the setup as they cheat by enter a start value in the past just to get on top of the list. I like to correct that by compute the max($start_value, today), so all nodes have the same start date when the event already started.

All in all:
: Read two values from a multiple value datefield in start_date and end_date;
: if (end_date > today)
: : if (start_date < today) start_date = today endif
: endif
: Return a result with two values: start_date & end_date

I'm a little bit ashamed that I can't write the php code for that. Sorry, I'm at the very beginning.

ThanX, Ralf

 
 

Drupal is a registered trademark of Dries Buytaert.