Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Entity::jsonSerialize() returns strange dates #8303

Closed
kenjis opened this issue Dec 7, 2023 · 13 comments
Closed

Bug: Entity::jsonSerialize() returns strange dates #8303

kenjis opened this issue Dec 7, 2023 · 13 comments

Comments

@kenjis
Copy link
Member

kenjis commented Dec 7, 2023

PHP Version

8.1

CodeIgniter4 Version

4.4.3 and develop

CodeIgniter4 Installation Method

Git

Which operating systems have you tested for this bug?

macOS

Which server did you use?

cli-server (PHP built-in webserver)

Database

MySQL 8.0.34

What happened?

Entity with dates returns JSON with strange format of dates.

    "created_at": {
        "date": "2023-12-07 04:00:48.000000",
        "timezone_type": 3,
        "timezone": "UTC"
    },

Steps to Reproduce

+----+------------+--------------------+---------+--------------------+--------------------+------------+
| id | name       | email              | country | created_at         | updated_at         | deleted_at |
+----+------------+--------------------+---------+--------------------+--------------------+------------+
| 1  | John Smith | john@example.co... | US      | 2023-12-07 04:0... | 2023-12-07 04:0... |            |
+----+------------+--------------------+---------+--------------------+--------------------+------------+
<?php

namespace App\Models;

use App\Entities\User;
use CodeIgniter\Model;

class UserModel extends Model
{
    protected $table            = 'user';
    protected $returnType       = User::class;
    protected $allowedFields    = [
        'name',
        'email',
        'country',
    ];

    // Dates
    protected $useTimestamps = true;
    protected $dateFormat    = 'datetime';
    protected $createdField  = 'created_at';
    protected $updatedField  = 'updated_at';
    protected $deletedField  = 'deleted_at';
}
<?php

namespace App\Entities;

use CodeIgniter\Entity\Entity;

class User extends Entity
{
    protected $datamap = [];
    protected $dates   = ['created_at', 'updated_at', 'deleted_at'];
    protected $casts   = [];
}
    public function index()
    {
        $users = new UserModel();
        /** @var User $user */
        $user = $users->find(1);
        echo json_encode($user, JSON_PRETTY_PRINT);
    }
{
    "id": "1",
    "name": "John Smith",
    "email": "john@example.com",
    "country": "US",
    "created_at": {
        "date": "2023-12-07 04:00:48.000000",
        "timezone_type": 3,
        "timezone": "UTC"
    },
    "updated_at": {
        "date": "2023-12-07 04:00:48.000000",
        "timezone_type": 3,
        "timezone": "UTC"
    },
    "deleted_at": null
}

Expected Output

{
    "id": "1",
    "name": "John Smith",
    "email": "john@example.com",
    "country": "US",
    "created_at": "2023-12-07 04:00:48",
    "updated_at": "2023-12-07 04:00:48",
    "deleted_at": null
}

Anything else?

See also #8302

@kenjis kenjis added the bug Verified issues on the current code behavior or pull requests that will fix them label Dec 7, 2023
@kenjis kenjis changed the title Bug: Bug: Entty::jsonSerialize() returns strage dates Dec 7, 2023
@kenjis kenjis changed the title Bug: Entty::jsonSerialize() returns strage dates Bug: Entity::jsonSerialize() returns strage dates Dec 7, 2023
@paulbalandan paulbalandan changed the title Bug: Entity::jsonSerialize() returns strage dates Bug: Entity::jsonSerialize() returns strange dates Dec 7, 2023
@michalsn
Copy link
Member

michalsn commented Dec 7, 2023

Seems like the default behavior for the DateTime object.

If we want to change it, the question is, do we really want to lose the time zone information?

@neznaika0
Copy link
Contributor

Yes, it defaut action for JSON dates. Timezone may be set
2023-12-07 04:00:48 +1:00
2023-12-07 04:00:48 Europe/Berlin
?

@kenjis
Copy link
Member Author

kenjis commented Dec 8, 2023

If we want to change it, the question is, do we really want to lose the time zone information?

Yes. Because this issue is about the default behavior.
And (string) Time::now() returns a string without timezone like 2023-12-08 00:58:44.

Whether timezone is required or not depends on requirement.
If it is needed, a dev can override the jsonSerialize() method.

@michalsn
Copy link
Member

michalsn commented Dec 8, 2023

I don't have a strong opinion about this, but I wouldn't call it a bug.

If we want to change this behavior that should be considered as a breaking change since the default value for JSON will change. Developers who have built an API may rely on this because this is the default behavior in PHP.

@kenjis
Copy link
Member Author

kenjis commented Dec 8, 2023

While it may be true that changing this will be a breaking change, it seems unreasonable to say that this is a specification.
The contents of DateTime are exposed and we don't even know what timezone_type is.

@neznaika0
Copy link
Contributor

Why don't we know? This shows what type of zone is displayed. To restore an object, it is not important, you only need the date and timezone.

Why not add array support with these keys to Time()? It works for me

@kenjis
Copy link
Member Author

kenjis commented Dec 8, 2023

Why don't we know?

Because it is not documented. I don't know the exact meaning.

Why not add array support with these keys to Time()? It works for me

What do you mean?

@kenjis
Copy link
Member Author

kenjis commented Dec 8, 2023

There seem to be maybe three values for timezone_type.
https://3v4l.org/gDGst

@neznaika0
Copy link
Contributor

A DateTimeZone object provides access to three different types of timezone rules: UTC offset (type 1), timezone abbreviation (type 2), and [timezone identifiers](https://www.php.net/manual/en/timezones.php) as published in the IANA timezone database (type 3).
https://www.php.net/manual/en/datetimezone.construct.php#refsect1-datetimezone.construct-description

@neznaika0
Copy link
Contributor

We studied this when there was a bug with Datetime serialization. Don't you remember?
#7780 (comment)

@neznaika0
Copy link
Contributor

Why not add array support with these keys to Time()? It works for me

What do you mean?

<?php

namespace App\Entities\Cast;

use CodeIgniter\Entity\Cast\BaseCast;
use CodeIgniter\Entity\Cast\DatetimeCast;
use CodeIgniter\I18n\Time;
use DateTimeZone;

/**
 * Adds date conversion from a JSON array as:
 * [
 *     'date'          => '2000-11-25 10:20:35.000000'
 *     'timezone_type' =>  3
 *     'timezone'      => 'Europe/Moscow'
 * ]
 */
class ExtendedDatetimeCast extends BaseCast
{
    public static function get($value, array $params = [])
    {
        return DatetimeCast::get($value, $params);
    }

    public static function set($value, array $params = [])
    {
        if (is_array($value) && array_key_exists('date', $value) && array_key_exists('timezone', $value)) {
            return DatetimeCast::get(new Time($value['date'], new DateTimeZone($value['timezone'])));
        }

        return DatetimeCast::set($value, $params);
    }
}

@crustamet
Copy link
Contributor

I don't think it is a bug because if you want the expected output you can just remove the

class User extends Entity
{
    protected $datamap = [];
    //protected $dates   = ['created_at', 'updated_at', 'deleted_at'];
    protected $dates = [];
    protected $casts   = [];
}

and it should work as you wanted.

@kenjis kenjis removed the bug Verified issues on the current code behavior or pull requests that will fix them label Feb 8, 2024
@kenjis
Copy link
Member Author

kenjis commented Feb 8, 2024

The current behavior is the behavior of PHP's DateTime.
So we can think this is not a bug.

echo json_encode(new DateTime('now'));
// {"date":"2024-02-08 22:57:15.503235","timezone_type":3,"timezone":"UTC"}

@kenjis kenjis closed this as completed Feb 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants