• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

XF 2.0 Both Date and Time inputs?

DragonByte Tech

Well-known member
#1
I'm trying to create an input row with both a date picker and hour/minute inputs, I expected this to be an option for <xf:dateinputrow> but that does not appear to be the case.

Additionally, the datetime input filterer does not appear to support time input when it's not baked into the date format from the date picker, since the value gets passed directly to the DateTime class.

Am I missing something, or is this the first case of doing something in XF2 being more difficult than it should be?

EDIT: If I'm correct in that time inputs aren't baked in but hidden somewhere, a suggested patch would be to add this directly below the case 'datetime': statement:

PHP:
                if (is_array($value) && isset($value['date']))
                {
                    if (!isset($value['hours']))
                    {
                        $value['hours'] = !empty($options['end']) ? 23 : 0;
                    }

                    if (!isset($value['minutes']))
                    {
                        $value['minutes'] = !empty($options['end']) ? 59 : 0;
                    }

                    if (!isset($value['seconds']))
                    {
                        $value['seconds'] = !empty($options['end']) ? 59 : 0;
                    }

                    $value = "{$value['date']} {$value['hours']}:{$value['minutes']}:{$value['seconds']}";
                }
While untested, this should in theory allow for the input variable to be an array that allows for hours/minutes/seconds inputs as well. I really hope time input support is something that will be implemented before Gold, since it's very important in some cases.


Fillip
 
Last edited:

Snog

Well-known member
#2
I used a formrow for the same purpose.

One input for the date and one for the time (hours/minutes in 30 minute increments). Then melded the two inputs into one variable for the DateTime class.
 

DragonByte Tech

Well-known member
#3
I used a formrow for the same purpose.

One input for the date and one for the time (hours/minutes in 30 minute increments). Then melded the two inputs into one variable for the DateTime class.
I'm hoping we can get an approach that's cleaner (on our end), since if you're avoiding the datetime input cleaner you're forced to replicate a lot of code each time you need time inputs.


Fillip
 

Chris D

XenForo developer
Staff member
#4
It's not especially difficult. I'd recommend something like this for the template:
HTML:
<xf:formrow label="Date" rowtype="input">
    <div class="inputGroup">
        <xf:dateinput name="date" value="{{ date($xf.time, 'Y-m-d') }}"    />
        <span class="inputGroup-splitter"></span>
        <xf:textbox type="time" name="time" value="00:00" />
    </div>
</xf:formrow>
Then:
PHP:
$date = $this->filter('date', 'datetime');
$time = $this->filter('time', 'str');
list ($hour, $min) = explode(':', $time);

$dateTime = new \DateTime('@' . $date, \XF::language()->getTimeZone());
$dateTime->setTime($hour, $min);

$timestamp = $dateTime->getTimestamp();
 

Snog

Well-known member
#7
Nah, I take an extra step to meld the two inputs into a single variable that probably isn't needed. But it is very close.
 

DragonByte Tech

Well-known member
#8
It's not especially difficult.
Just feel like there could be a case for getting the explode / DateTime stuff abstracted away for us. There's obviously not a huge need for it internally in XF as the only place where time input was a thing that I could find was the Criteria function.

That being said, I was unaware of the type="time" which removes some of the validation concerns.

Then:
PHP:
$date = $this->filter('date', 'datetime');
$time = $this->filter('time', 'str');
list ($hour, $min) = explode(':', $time);

$dateTime = new \DateTime('@' . $date, \XF::language()->getTimeZone());
$dateTime->setTime($hour, $min);

$timestamp = $dateTime->getTimestamp();
This doesn't entirely work if users hit the Delete key on one or both of the components of the time row.

If you delete both values, the form is submitted without an error, but when you enter only Hours, or only Minutes, you receive the error.

I'll go report this bug now :)


Fillip
 

DragonByte Tech

Well-known member
#10
Not sure if joking...

The code written above is my own that I pretty much only just wrote roughly. But type="time" is a HTML 5 attribute. There may need to be further validation. It's not an XF thing.
I was not aware that was a HTML 5 attribute, remember I come from vBulletin where XHTML is still the new thing :p

I'm guessing what I just reported is a Chrome bug, then.


Fillip
 

Chris D

XenForo developer
Staff member
#13
I was not aware that was a HTML 5 attribute, remember I come from vBulletin where XHTML is still the new thing :p

I'm guessing what I just reported is a Chrome bug, then.


Fillip
Maybe but I'm not sure. It comes out at 0 if you enter nothing so I guess that's equivalent to 00:00.

The main error is in my rough code above.
 

DragonByte Tech

Well-known member
#14
Maybe but I'm not sure. It comes out at 0 if you enter nothing so I guess that's equivalent to 00:00.

The main error is in my rough code above.
Feel fairly stupid for not knowing that now, I usually double and triple check everything before I post a report but since I've never seen a time input before I assumed this was a custom extension to <xf:textbox> :(

I've read up on it now, and as far as browser support is concerned, if a browser doesn't support the time input type it behaves as text, so I'll just add extra validation to make sure the hours and minutes make sense.


Fillip
 

Snog

Well-known member
#15
Yeah, I would think you would have to validate that it contains something and return an error.

I can't test it right now, but I think it's returning NULL or false since 00:00 would mean midnight.
 

DragonByte Tech

Well-known member
#16
Final code:

PHP:
        $dateInput = $this->filter([
            'date' => 'datetime',
            'time' => 'str',
        ]);
        $form->setup(function() use ($dateInput, $download)
        {
            $language = \XF::language();

            $dateTime = new \DateTime('@' . $dateInput['date'], $language->getTimeZone());

            if (!$dateInput['time'] OR strpos($dateInput['time'], ':') === false)
            {
                // We didn't have a valid time string
                $hours = $language->date($download->release_date, 'H');
                $minutes = $language->date($download->release_date, 'i');
            }
            else
            {
                list($hours, $minutes) = explode(':', $dateInput['time']);

                // Sanitise hours and minutes to a maximum of 23:59
                $hours = min(intval($hours), 23);
                $minutes = min(intval($minutes), 59);
            }

            // Finally set it
            $dateTime->setTime($hours, $minutes);

            $download->release_date = $dateTime->getTimestamp();
        });
Either of you see any immediate issues with that? I changed the input type to a text so I could experiment some more. Tried with a : but missing hours and minutes, as well as leaving the : out, and it seems to work.


Fillip
 

Snog

Well-known member
#17
I don't see any problems. But I do something similar in a XFRM modification and I don't know exactly what you're doing. Why not just $download->release_date = time();?

I guess, there must be some reason for the time input.
 

DragonByte Tech

Well-known member
#18
I don't see any problems. But I do something similar in a XFRM modification and I don't know exactly what you're doing. Why not just $download->release_date = time();?

I guess, there must be some reason for the time input.
The goal with the release_date column is to be able to schedule download availability, so having a time input would mean a download could be scheduled at a specific time of day as well as just the day :)


Fillip