Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Smoke1987's avatar

Safari date time bug fix

In eloquent when storing any dates in the database as timestamt, in the database these fields have the form such as '2018-08-22 11:18:44'. When retrieve those dates and convert it to the JSON, those form not changed. Safari browser have a bug (e.g. Angular app) - the date pipe is crash app if date form differs from '2018-08-22T11:18:44' (need delimiter 'T' between date and time). In Eloquent i can define such property as $dateFormat, but any attempts to add delimiter 'T' is not success :(

Are there any suggestions to add a mutator of all dates for the model so that they do not go through them and replace them with regular expressions?

0 likes
30 replies
Smoke1987's avatar

By default

protected $dateFormat = 'Y-m-d H:i:s';
Snapey's avatar

never heard of such a bug. It seems very unlikely.

The date format you are talking about is ISO8601

You can cast dates to any format in the model, and carbon can produce this format directly

Smoke1987's avatar

https://github.com/angular/angular/issues/12334

discuss about bug...

I`m still cannot convert date to needed format.

protected $dateFormat = 'YYYY-MM-DDThh:mm:ss';

Dos not work - error in Carbon.php

Unexpected data found.
Unexpected data found.
Unexpected data found.
The timezone could not be found in the database
Data missing
Smoke1987's avatar

Escaping symbol "T" dos not help protected $dateFormat = 'YYYY-MM-DD\Thh:mm:ss';

Unexpected data found.
Unexpected data found.
Unexpected data found.
Hour can not be higher than 12
Hour can not be higher than 12
Data missing
Smoke1987's avatar

I found solution, but now error in another place

"file": "/Users/.../Sites/.../app/Http/Controllers/OrderController.php",
"line": 384,
"function": "toArray",
"class": "Illuminate\Support\Collection",
"type": "->"

Order model is override HasAttribute trait's field $dateFromat

protected $dateFormat = 'Y-m-d\TH:i:s';
Smoke1987's avatar

When call the function toArray() on collection of models... any ideas?

Smoke1987's avatar

Moved transform collection of models to array. Now error in serialize response to JSON....

Smoke1987's avatar

I get something information...

Order model

protected $dateFormat = 'Y-m-d\TH:i:s';

Carbon.php (add some code)

/**
     * Create a Carbon instance from a specific format.
     *
     * @param string                    $format
     * @param string                    $time
     * @param \DateTimeZone|string|null $tz
     *
     * @throws \InvalidArgumentException
     *
     * @return static
     */
    public static function createFromFormat($format, $time, $tz = null)
    {
        if ($tz !== null) {
            $dt = parent::createFromFormat($format, $time, static::safeCreateDateTimeZone($tz));
        } else {
            $dt = parent::createFromFormat($format, $time);
        }

        static::setLastErrors($lastErrors = parent::getLastErrors());

        if ($dt instanceof DateTime) {
            return static::instance($dt);
        }

        
        //throw new InvalidArgumentException(implode(PHP_EOL, $lastErrors['errors'])); <<<--this line throw
        
        // modify to get info
        throw new InvalidArgumentException(implode(PHP_EOL, ['$format' => $format, '$time' => $time, '$tz'=> $tz]));
    }
Smoke1987's avatar

And response

"message": "Y-m-d\TH:i:s\n2018-08-23 10:33:17\n",
    "exception": "InvalidArgumentException",
    "file": "/Users/.../Sites/.../vendor/nesbot/carbon/src/Carbon/Carbon.php",
    "line": 583,
... stacktrace...

Timezone is null... it can be null.... What goes wrong?

Smoke1987's avatar

The problem is that the PDO driver when selecting from a DB values of the type of a timestamp returns a string representation and not a timestamp:

DateTime::createFromFormat(DateTime::ISO8601, $time)

expects the second argument of a timestamp, but gets a string. When we do not override the protected field of the model $dateFormat, the Carbon class does not call the function createFromFormat($format, $time, $tz = null).

Question: is this the expected behavior of the PHP-PDO-MySQL bundle?

Smoke1987's avatar

I mean that the redefinition of the date format is given in the documentation for the Laravel framework. However, using this method of converting the date format leads to errors / bugs?

Smoke1987's avatar

Amendment:

DateTime :: createFromFormat ('Y-m-d H:i:s', '2018-08-22 11:18:44');

this function will never create a date object from the specified date-time string if the date format differs from the specified date. That is: when storing a date in a database in the form of a timestamp when using a Laravel, it is impossible to get the date in a different format than the default format?

Smoke1987's avatar

Finally i have modified function in Carbon.php

/**
     * Create a Carbon instance from a specific format.
     *
     * @param string $format
     * @param string $time
     * @param \DateTimeZone|string|null $tz
     *
     * @throws \InvalidArgumentException
     *
     * @return static
     */
    public static function createFromFormat ( $format, $time, $tz = null )
    {
        if ( $tz !== null ) {
            $dt = parent::createFromFormat ( $format, $time, static::safeCreateDateTimeZone ( $tz ) );
        } else {
            $dt = parent::createFromFormat ( $format, $time );
        }

        static::setLastErrors ( $lastErrors = parent::getLastErrors () );

        // when we redefine format of date in Eloquent (e.g. protected $dateFormat = 'Y-m-d\TH:i:s')
        if ( !$dt ) {
            // create instanceof DateTime from default format
            // at this format we retrieve "TIMESTAMP" from SQL (PHP->PDO->MySQL)
            $dateFromString = DateTime::createFromFormat ( 'Y-m-d H:i:s', $time );
            // now we convert DateTime to format we needed
            $dt = $dateFromString->format ( $format ); // note, that this return `string`
            // now we create instanceof DateTime from format we needed
            $dt = DateTime::createFromFormat ( $format, $dt );
        }

        if ( $dt instanceof DateTime ) {
            return static::instance ( $dt );
        }

        throw new InvalidArgumentException( implode ( PHP_EOL, $lastErrors[ 'errors' ] ) );
    }

this function will help to override any of the valid date formats to the model and to avoid bugs when retrieving the date from the MySQL database which will be stored in the timestamp column

Looks like its a bug in framework.... ???

Snapey's avatar

Looks like you are off your head if you modify anything in the vendor folder.

Smoke1987's avatar

I do not see anything illegal here. Simply if you have a cleaner solution to the problem - share ...

Cronix's avatar

Now go run composer update... you better lock that current version of Carbon down so it never gets upgraded, which will overwrite your changes and break your app leaving you scratching your head wondering why it's not working anymore.

Smoke1987's avatar

All the edits that I made in the vendor folder (including I changed the "username" field from the e-mail to the phone number from the Laravel-Passport package due to requirements), I record. I do not think that having such a powerful tool as a Laravel for all the variety of customers' needs, you can not edit stock projects for your own needs

Cronix's avatar

All of that stuff can be done/changed/extended/overridden without even touching /vendor. You just apparently don't know how.

But, it's your project, that you have to maintain...not us. You're just making it a lot more complex and have more work for yourself and "core changes that you have to track" than needed. I guess you just don't know how?

Smoke1987's avatar

I have problems when I try to solve this requirement by the example given in the documentation for the Laravel framework

Smoke1987's avatar
  1. By default model store in DB (e.g. MySQL) date fields created_at and updated_at at type of column TIMESTAMP. When PHP receives data - PDO driver represent this columns in default format Y-m-d H:i:s. This format does not suit me. I tried to change this format to custom valid date-time format (e.g. Y-m-d\TH:i:s). The trouble is that the function of the createFromFormat ( $format, $time, $tz = null ) in Carbon.php dos not convert date-time 'from<->to format' which differs from the format of the provided 'time' (in string) in the parameter (I apologize for my broken English).
jlrdw's avatar

@Smoke1987 do as you wish, but myself, @Snapey and @Cronix has been at this for a while. You need to

  • Slow down
  • Take a while a learn laravel correctly
  • Watch some videos
  • Check stackoverflow also

The vendor is not supposed to be modified.

No reply necessary, just take the time to learn.

If you were a beginner electrician, day 2 you would not be ready to repair a high power line by yourself yet.

Those electricians go through a 4 year apprenticeship program.

You do the same

Take a couple of months to learn laravel better, not a one day thing.

Smoke1987's avatar
  1. all attempts are similarly to convert dates by oververting the field protected $dateFormat = 'DateTime :: ISO8601' also results in an error inside the carbon package.
jlrdw's avatar

Did you even read my above reply.

Smoke1987's avatar

OK! I understood the direction of your policy. I did not think that attempts to get advice will lead to the same as usual - read, learn.

jlrdw's avatar

Well @Smoke1987 I used to do java development, those days there was no forum with quick answers, I spent years learning.

Just my 2 cents.

Doctors, mechanics, carpenters, electricians, programmers, cooks, do I need to mention more, all have to

Learn

their trade, it's not a one day or one week thing. It takes quality time.

If you need instant results look at phprunner

https://xlinesoft.com/phprunner

But even there you need to customize code.

Or look at

https://www.hkvstore.com/phpmaker/

One of these may suit you better.

Snapey's avatar
Snapey
Best Answer
Level 122

Dates are handled well in Laravel.

Add your field to the $dates array in the model.

Your field will then be converted to an instance of Carbon whenever the model is loaded.

Once it is a Carbon object it can be output in any format you like. There is really no complication to it.

If you need the date cast to a different format for a json response then see

https://laravel.com/docs/5.6/eloquent-mutators#date-casting

A carbon object may be converted to ISO format;

Tinker output;

Psy Shell v0.9.7 (PHP 7.2.9 — cli) by Justin Hileman
>>> $u=User::find(1)

=> App\User {#2954
     id: 1,
     name: "***************",
     email: "***********@*******",
     password: "y$qs1krUehz6QgWpAYCv2K8ecrXjp0jrLiA9h.UsC6JC/b4AVwAfblK",
     remember_token: "8Iz7Xynwro4UNB4W1bX2RX9WRA5rNdUDX3N9lBpyHwErHuuWzA0BUqKg7rmF",
     created_at: "2018-08-25 15:22:35",
     updated_at: "2018-08-25 15:22:35",
   }

//here you can see created_at is a carbon object
>>> $u->created_at
=> Illuminate\Support\Carbon @1535206955 {#2950
     date: 2018-08-25 15:22:35.0 Europe/London (+01:00),
   }

//cast to an ISO string
>>> $u->created_at->toIso8601String()
=> "2018-08-25T15:22:35+01:00"
>>>

here demonstrated with the User model and its created_at field

1 like
cmmartin24's avatar

@snapey and @jlrdw all you have to do to reproduce this issue is open the javascript console in Safari and paste in new Date('2021-03-12 21:03:32') and you will see that even 3 years later this is an invalid date format in Safari. It returns Invalid Date

Please or to participate in this conversation.