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

Formatter ignore timeZone #5328

Closed
ostashevdv opened this issue Oct 3, 2014 · 10 comments
Closed

Formatter ignore timeZone #5328

ostashevdv opened this issue Oct 3, 2014 · 10 comments
Assignees
Labels
type:docs Documentation
Milestone

Comments

@ostashevdv
Copy link
Contributor

i set timezone in my.conf

default_time_zone = "+04:00"

in my php.ini:

[Date]
date.timezone = "Europe/Moscow"

in application config:

return [  
    'language' => 'ru',
    'charset' => 'utf-8',
    'timeZone' => 'Europe/Moscow',
    'components' => []
...

then i use this example

$date = date("Y-m-d H:i:s");
$timestamp = strtotime($date);

echo (new \DateTime($date))->format('Y-m-d H:i:s'); # 2014-10-03 14:09:20
echo \Yii::$app->formatter->asTime($date, "php:Y-m-d H:i:s"); # 2014-10-03 18:09:2
echo \Yii::$app->formatter->asTime($date, 'HH:mm'); # 18:09

echo (new \DateTime())->setTimestamp($timestamp)->format("Y-m-d H:i:s"); # 2014-10-03 14:09:20
echo \Yii::$app->formatter->asTime($timestamp, "php:Y-m-d H:i:s"); # 2014-10-03 14:09:20
echo \Yii::$app->formatter->asTime($timestamp, 'HH:mm'); # 14:09

Formatter added +4 hours if use date as string, but all ok if use timestamp.
i think this problem in framework\i18n\Formatter method normalizeDatetimeValue
(https://github.com/yiisoft/yii2/blob/master/framework/i18n/Formatter.php#L565-L592)

 protected function normalizeDatetimeValue($value)
    {
        if ($value === null || $value instanceof DateTime) {
            // skip any processing
            return $value;
        }
        if (empty($value)) {
            $value = 0;
        }
        try {
            if (is_numeric($value)) { // process as unix timestamp
                if (($timestamp = DateTime::createFromFormat('U', $value, new DateTimeZone('UTC'))) === false) {
                    throw new InvalidParamException("Failed to parse '$value' as a UNIX timestamp.");
                }
                return $timestamp;
            } elseif (($timestamp = DateTime::createFromFormat('Y-m-d', $value, new DateTimeZone('UTC'))) !== false) { // try Y-m-d format (support invalid dates like 2012-13-01)
                return $timestamp;
            } elseif (($timestamp = DateTime::createFromFormat('Y-m-d H:i:s', $value, new DateTimeZone('UTC'))) !== false) { // try Y-m-d H:i:s format (support invalid dates like 2012-13-01 12:63:12)
                return $timestamp;
            }
            // finally try to create a DateTime object with the value
            $timestamp = new DateTime($value, new DateTimeZone('UTC'));
            return $timestamp;
        } catch(\Exception $e) {
            throw new InvalidParamException("'$value' is not a valid date time value: " . $e->getMessage()
                . "\n" . print_r(DateTime::getLastErrors(), true), $e->getCode(), $e);
        }
    }

there set DateTimeZone('UTC') and string time converted in this timezone , but i think need use $this->timeZone.

@cebe
Copy link
Member

cebe commented Oct 3, 2014

The formatter uses UTC as the input timezone when you input a value that has no timezone specified explicitly. You should always store date/time values in UTC and convert them to the right timezone when displaying. If you store them in another timezone you have to specify the timezone explicitly:

// assuming Yii::$app->timeZone = 'Europe/Berlin';

\Yii::$app->formatter->asTime('2014-08-10 12:41:00'); // 14:41:00
\Yii::$app->formatter->asTime('2014-08-10 14:41:00 CEST'); // 14:41:00

See also 6267b9e

@cebe cebe added the type:docs Documentation label Oct 3, 2014
@cebe cebe added this to the 2.0 GA milestone Oct 3, 2014
@cebe cebe self-assigned this Oct 3, 2014
@ostashevdv
Copy link
Contributor Author

thnk u! i'm understood.

@cebe
Copy link
Member

cebe commented Oct 6, 2014

dfd6895

@cebe cebe closed this as completed Oct 6, 2014
@Renkas
Copy link
Contributor

Renkas commented Oct 8, 2014

There is still a problem with this when you use DatePicker

I give you an example:
I have a form with a date field (and a required email field).
If I submit the form with date field filled and email not filled I get the page back from server with validation error messages.
The problem is that date field's contents have advanced one day.
I have debugged it so far that the culprit is the formatter as formatter takes my input date. Converts it to unix timestamp (thinking that the date is in UTC). And then the formatter formats the date back to the configured format - but because the timezone is now GMT+3 and time local time is 55 minutes past midnight - I get a +1 day to the formatted date.

I don't know what is the best fix for this in overall. But in this specific case it seems that using same timezone in initial conversion would fix it. But where should this be handled? In the DatePicker widget? In the formatter?

@cebe
Copy link
Member

cebe commented Oct 9, 2014

This is a general problem with dates because they are not really timezone related. Can you please open a new issue for this? will try to find a solution for this. maybe for date values that do not include time, we should normalize them differently than full time values.

@cebe
Copy link
Member

cebe commented Jun 6, 2017

Europe/Moscow

this timezone changed the rules recently, so your server may not be up to date.

See http://www.yiiframework.com/doc-2.0/guide-tutorial-i18n.html#setup-environment for how to update.

Also note that a UNIX timestamp is, per definition, always in UTC, so defaultTimeZone has no effect on it.

@cebe
Copy link
Member

cebe commented Jun 6, 2017

updated docs: b056dff hope its more clear now.

@Renkas
Copy link
Contributor

Renkas commented Jun 6, 2017

@cebe I think no one here has had problem understanding that timestamp is in UTC.

The problem is that all the user input dates are treated as in UTC - although they should be treated as the same timeZone the application output is set at. Because user inputs dates/times in the same timezone he uses the app at.

PS! Correct me if I'm wrong. I haven't tested it lately - maybe this is a non issue and has been fixed already.
For my own issue I remember doing some ugly hack conversion at the time ...

@cebe
Copy link
Member

cebe commented Jun 6, 2017

@Renkas my reply was to a comment that has been deleted, so I can not re-check if I maybe understood the problem wrong.

For user input, it should not be formatted directly with Formatter but it should be converted by DateValidator first, so you get a value in UTC or whatever you have configured as defaultTimeZone. which you can then format using the formatter.

@cebe
Copy link
Member

cebe commented Jun 6, 2017

Newer ICU: 57.1 with ICU Data: 57.1, which isshipped with PHP 7.1.3

ICU is not shipped with PHP, it depends on the libraries that are installed on your server.
Its not the job of Yii framework to keep your server environment up to date.
In the docs there are two links that describe how you can keep timezone data of PHP and ICU up to date: http://www.yiiframework.com/doc-2.0/guide-tutorial-i18n.html#setup-environment

PHP date function works correct with time zones at any server, so using it makes code more portable and independent from the environment.

  1. this is not true, it also depends on a timezone database, see the documentation linked above.
  2. PHP date functions only work with english locale. No dates like 15. Dezember 2017 (german) are possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:docs Documentation
Projects
None yet
Development

No branches or pull requests

3 participants