10

I have been developing on php 5.3.

However our production server is 5.2.6.

I have been using

$schedule = '31/03/2011 01:22 pm'; // example input
if (empty($schedule))
    $schedule = date('Y-m-d H:i:s');
else {
    $schedule = dateTime::createFromFormat('d/m/Y h:i a', $schedule);
    $schedule = $schedule->format('Y-m-d H:i:s');
}
echo $schedule;

However that function is not available in 5.2

What is the easiest way to get around this (no chance of a php upgrade).

hakre
  • 193,403
  • 52
  • 435
  • 836
Hailwood
  • 89,623
  • 107
  • 270
  • 423

6 Answers6

19

just include the next code

function DEFINE_date_create_from_format()
  {

function date_create_from_format( $dformat, $dvalue )
  {

    $schedule = $dvalue;
    $schedule_format = str_replace(array('Y','m','d', 'H', 'i','a'),array('%Y','%m','%d', '%I', '%M', '%p' ) ,$dformat);
    // %Y, %m and %d correspond to date()'s Y m and d.
    // %I corresponds to H, %M to i and %p to a
    $ugly = strptime($schedule, $schedule_format);
    $ymd = sprintf(
        // This is a format string that takes six total decimal
        // arguments, then left-pads them with zeros to either
        // 4 or 2 characters, as needed
        '%04d-%02d-%02d %02d:%02d:%02d',
        $ugly['tm_year'] + 1900,  // This will be "111", so we need to add 1900.
        $ugly['tm_mon'] + 1,      // This will be the month minus one, so we add one.
        $ugly['tm_mday'], 
        $ugly['tm_hour'], 
        $ugly['tm_min'], 
        $ugly['tm_sec']
    );
    $new_schedule = new DateTime($ymd);

   return $new_schedule;
  }
}

if( !function_exists("date_create_from_format") )
 DEFINE_date_create_from_format();
ghindows
  • 234
  • 2
  • 2
  • This is a GREAT answer. Should really get more upvotes! Thanks – andreapier Mar 15 '13 at 20:45
  • Support for DateTime 'M': ```$schedule_format = str_replace(array('M', 'Y', 'm', 'd', 'H', 'i', 'a'),array('%b', '%Y', '%m', '%d', '%I', '%M', '%p'), $dformat);``` – kenorb Sep 09 '13 at 15:59
  • There is a small bug, as 'H' should be replaced to %H (24-hour format), not %I (12-hour format). So here is improved line: ```$schedule_format = str_replace(array('M', 'Y', 'm', 'd', 'H', 'i', 'a'), array('%b', '%Y', '%m', '%d', '%H', '%M', '%p'), $dformat);``` – kenorb Sep 19 '13 at 08:40
  • Doesn't work on Windows!, _strptime_ is not implemented – Marco Andreolli Feb 07 '19 at 10:41
10

Because strtotime does poorly when confronted with D/M/Y and date_create_from_format isn't available, strptime may be your only hope here. It does some pretty oldschool things, like deal with years as if they are the number of years since 1900 and deal with months as if January was month zero. Here's some horrible example code that uses sprintf to reassemble the date into something DateTime understands:

$schedule = '31/03/2011 01:22 pm';
// %Y, %m and %d correspond to date()'s Y m and d.
// %I corresponds to H, %M to i and %p to a
$ugly = strptime($schedule, '%d/%m/%Y %I:%M %p');
$ymd = sprintf(
    // This is a format string that takes six total decimal
    // arguments, then left-pads them with zeros to either
    // 4 or 2 characters, as needed
    '%04d-%02d-%02d %02d:%02d:%02d',
    $ugly['tm_year'] + 1900,  // This will be "111", so we need to add 1900.
    $ugly['tm_mon'] + 1,      // This will be the month minus one, so we add one.
    $ugly['tm_mday'], 
    $ugly['tm_hour'], 
    $ugly['tm_min'], 
    $ugly['tm_sec']
);
echo $ymd;
$new_schedule = new DateTime($ymd);
echo $new_schedule->format('Y-m-d H:i:s');

If it works, you should see the same, correct date and time printed twice.

Charles
  • 50,943
  • 13
  • 104
  • 142
  • out of curiosity, whats the difference between your code and `else { $schedule = str_replace('/', '-', $schedule); $schedule = date('Y-m-d H:i:s', strtotime($schedule)); }` – Hailwood Mar 22 '11 at 23:50
  • This is probably the best solution unless you can have more control over the input and ensure you are using [Supported Date and Time Formats](http://www.php.net/manual/en/datetime.formats.php). – Jacob Mar 22 '11 at 23:54
  • `strtotime` does not understand D/M/Y. It only can handle Y/M/D and M/D/Y. If you try to pass a D/M/Y to it, it will fail. `strtotime('20/02/2003')` returns `false`. You'd have to pass `'20.03.2003'` (note the dots!) to get that format recognized, which isn't the date format you expect. – Charles Mar 22 '11 at 23:55
  • I understand that strtotime does not like `/` but if you convert `/` to `-` then it works perfectly. I am finding it hard to read your code above, mind commenting it a bit to explain what each function is doing? – Hailwood Mar 23 '11 at 00:02
  • It looks like D-M-Y is supported, but your example date includes only slashes. Further, while D-M-Y is supported, M-D-Y is not -- replacing slashes on a M/D/Y would result in an unparsable date. I'll edit my code with more comments in a moment. – Charles Mar 23 '11 at 00:10
  • also if ` deal with years as if they are the number of years since 1900` is true would you not want to subtract `1900` instead of adding `1900`? – Hailwood Mar 23 '11 at 00:11
  • I've edited my post with some inline comments, and a link to the `sprintf` documentation. `tm_year` ends up being 111 here, so we need to add 1900 to get back to 2011. Yes, it really works that way. Freaky, ain't it? Brings me back to my Perl days... – Charles Mar 23 '11 at 00:14
  • Wow, that year handling is messed up! Cheers! – Hailwood Mar 23 '11 at 00:22
  • @Hailwood @Charles see my answer http://stackoverflow.com/questions/5287224/strtotime-considered-harmful/5350457#5350457 about date formats. – Jacob Mar 23 '11 at 00:30
6

I think it is much cleaner to extend the DateTime class and implement createFromFormat() yourself like this:-

class MyDateTime extends DateTime
{
    public static function createFromFormat($format, $time, $timezone = null)
    {
        if(!$timezone) $timezone = new DateTimeZone(date_default_timezone_get());
        $version = explode('.', phpversion());
        if(((int)$version[0] >= 5 && (int)$version[1] >= 2 && (int)$version[2] > 17)){
            return parent::createFromFormat($format, $time, $timezone);
        }
        return new DateTime(date($format, strtotime($time)), $timezone);
    }
}

$dateTime = MyDateTime::createFromFormat('Y-m-d', '2013-6-13');
var_dump($dateTime);
var_dump($dateTime->format('Y-m-d'));

This will work in all versions of PHP >= 5.2.0.

See here for a demo http://3v4l.org/djucq

vascowhite
  • 18,120
  • 9
  • 61
  • 77
  • This doesn't work in 5.2.x with an usual non English format like 'd/m/Y', but it works if you replace '/' with '-'. – morgar Oct 14 '16 at 01:39
  • As 5.2.x reached [EOL](http://php.net/eol.php) nearly 6 years ago I'm not too concerned about it. Thanks for letting me know anyway. – vascowhite Oct 14 '16 at 06:08
0

Since this is not really showing how to convert YYYY:DDD:HH:MM:SS time to unix seconds using the "z" option you have to create you own functions to convert the DOY to month and day of month. This is what I did:

function _IsLeapYear ($Year)
{
    $LeapYear = 0;
    # Leap years are divisible by 4, but not by 100, unless by 400
    if ( ( $Year % 4 == 0 ) || ( $Year % 100 == 0 ) || ( $Year % 400 == 0 ) ) {
        $LeapYear = 1;
    }
    return $LeapYear;
}

function _DaysInMonth ($Year, $Month)
{

    $DaysInMonth = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

    return ((_IsLeapYear($Year) && $Month == 2) ? 29 : $DaysInMonth[$Month - 1]);
}

function yydddhhssmmToTime($Year, $DOY, $Hour, $Min, $Sec)
{
   $Day = $DOY;
   for ($Month = 1;  $Day > _DaysInMonth($Year, $Month);  $Month++) {
    $Day -= _DaysInMonth($Year, $Month);
   }

   $DayOfMonth = $Day;

   return mktime($Hour, $Min, $Sec, $Month, $DayOfMonth, $Year);
}

$timeSec = yydddhhssmmToTime(2016, 365, 23, 23, 23);
$str = date("m/d/Y H:i:s", $timeSec);
echo "unix seconds: " . $timeis . " " . $str ."<br>";

The output on the page shows its working since I can convert back the seconds back to the original input values. unix seconds: 1483140203 12/30/2016 23:23:23

user3416126
  • 148
  • 11
-1
$your_datetime_object=new DateTime($date);
$date_format_modified=date_format($your_datetime_object,'D M d Y');//Change the format of date time

I had the similar problem with the production server at 5.2, so I used the above datetime to create an object and then change the format to my liking as above.

yash
  • 183
  • 3
  • 12
-1

Date and Time only

$dateTime = DateTime::createFromFormat('Y-m-d\TH:i:s', '2015-04-20T18:56:42');

ISO8601 no colons

$dateTime = DateTime::createFromFormat('Y-m-d\TH:i:sO', '2015-04-20T18:56:42+0000');

ISO8601 with colons

$date = $dateTime->format('c');

Salesforce ISO8601 format

DateTime::createFromFormat('Y-m-d\TH:i:s.uO', '2015-04-20T18:56:42.000+0000');

Hope this saves someone time!

Kyll
  • 7,036
  • 7
  • 41
  • 64
  • Just read the question, please forgive me, meant to post on applicable question but was excited to have finally solved the issue and have no idea how to delete this, my bad. – Shelly Warren May 05 '15 at 19:01