CakePHP: FrozenTime from database without timezone - datetime

I'm on "Europe/Rome":
debug(new \Cake\I18n\Time());
Output:
object(Cake\I18n\Time) {
'time' => '2016-03-23T14:18:17+01:00',
'timezone' => 'Europe/Rome',
'fixedNowTime' => false
}
If I save a post (for example), the datatime is handled properly.
The problem occurs when I retrieve data. This post has been just saved:
debug($post->created);
Output:
object(Cake\I18n\FrozenTime) {
'time' => '2016-03-23T14:14:45+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
}
The datetime is correct, but the timezone of course not.
Now if I do something like this:
debug($post->created > new \Cake\I18n\Time());
the result will obviously be TRUE and not FALSE (as it should be). I conclude that this happens because, in comparison phase, it obviously uses the same timezone.
Where am I doing wrong? Thanks.
EDIT
My bootstrap.php
date_default_timezone_set('UTC');
Instead, my php.ini (I think it's not relevant):
date.timezone = Europe/Rome
So I have to think that the value of $post->created is correct.
But now... why new \Cake\I18n\Time() uses the correct timezone (which is not set) and why the post is saved with the correct timezone?

I would kinda doubt that new \Cake\I18n\Time() will use the timezone set in your INI after date_default_timezone_set() has been used, as the latter should win over the former. Maybe there's a version specific behavior/bug where this doesn't work as expected, not sure, you'll have to debug your environment to figure what's going on there.
That being said, when data is being read, the ORM casts it to PHP datatypes. The date/time type classes responsible for this are using cloned date/time class instances instead of creating new ones, and that base instance is created when the type instance is first built and/or when the mutability is being set, which usually happens at bootstrapping time when Type::build() is invoked.
If you'd then for example change the timezone at a later point, new \Cake\I18n\Time based instances would use the newly set timezone, but the date/time type would still use the instance that was created with the original timezone at bootstrapping time.
tl;dr
Set the proper timezone via date_default_timezone_set() in your bootstrap, and if you need to change the timezone at a later point, then you'll have to make sure that a new base type instance for cloning is being set, which could for example be done by setting the mutability again, like
Type::build('time')->useImmutable();
This feels kinda workaroundish though, you may want to open a ticket over at GitHub and report this behavior.

Related

Why does AliceBundle Fixture DateTime give me an unexpected value?

I'm currently working on a project in which I create fixtures with Alice-bundle to run tests to make sure my API-endpoints work properly. Everything works fine, except for the DateTime properties.
No matter what string I pass it, eg: <dateTime('2019-09-23 14:00:00')>, it always gives me the wrong date and time, usually something like: 1998-10-25T14:29:45+01:00.
Even using <dateTime('now')> does not work -- it gives me some pre-2000s date & time as well, while that's exactly what some examples I'd found do use.
A fixture could look something like this:
Path\To\Task\Entity:
my_task:
title: 'My tasks'
description: 'These are all the tasks just for me!!!'
startsAt: <dateTime('now')>
endsAt: <dateTime('now')>
createdBy: '#some_higher_user'
Ideally I just want to pass it a string so I can define both a Date and Time and make sure it works properly, in the right format.
And help would be appreciated.
Looking here https://github.com/nelmio/alice/blob/master/doc/advanced-guide.md#functions we read:
function can be a Faker or a PHP native (or registered in the global scope) function.
So I would recommend trying a PHP native function that creates a \DateTime object
<date_create_from_format ( 'Y-m-d H:i:s' , '2019-09-23 14:00:00')>
// or
<date_create('now')>
That's how it works. The <dateTime()> function takes an argument called $max. So what it does is create a date between a starting date (not sure which one, probably something in the 1900 range or so) and that $max argument.
I guess you will want to use <dateTimeBetween()> which takes a startDate and an endDate to create a fake date between them. So I suppose if startDate = endDate, then you'll get the desired fixed date.
Take a look at fzaninotto/Faker library documentation. It's the library used by AliceBundle to actually fake data. There you can see what DateTime related functions you can use.

Typo3 6.2.15 DateTime off by 1 hour

I have a model with a DateTime column named "fromDate":
/**
* fromDate
*
* #var \DateTime
*/
protected $fromDate;
now I need this date to do some calculations, but when I try outputting it, it seems to be off exactly 1 hour.
echo $model->getFromDate()->format('Y-m-d H:i:s');
This returns 2016-02-11 01:00:00 instead of 2016-02-11 00:00:00
I checked my server timezone, date_default_timezone_get() returns "Europe/Berlin" (which is correct). I tried to change the typo3 serverTimeZone (I tried 0 and 1, but doesn't change anything).
If I look at the database with phpmyadmin, the entry is "2016-02-11 00:00:00"
What am I missing, why is this happening? Any hints? Because I feel like I'm going insane, a huge calculation script is based on the correctness of $fromDate ... Any help would be greatly appreciated. Thank you!
Try something like
$myDate = $model->getFromDate();
$myDate->setTimezone(new \DateTimeZone('UTC'));
or whatever time zone you use in your raw database table value, if not UTC.
In TYPO3 6.2, at least, doing a findAll() on your repository begins a series of calls -- to \TYPO3\CMS\Extbase\Persistence\Repository->createQuery(), and afterward to \TYPO3\CMS\Extbase\Persistence\Generic\QueryResult->rewind(). rewind() calls initialize(), which calls \TYPO3\CMS\Extbase\Persistence\Generic\Mapper->map(). map() calls mapSingleRow(), which then calls thawProperties() in the same class.
TYPO3\CMS\Extbase\Persistence\Generic\Mapper->thawProperties() has a "switch case" code section based on each property data type. If the type is DateTime, thawProperties() calls mapDateTime() in the same class.
mapDateTime() assumes "native date/datetime values are stored in UTC", so it applies the 'UTC' DateTimeZone to the raw value. But then, mapDateTime() applies the DateTimeZone from the PHP date_default_timezone_get() function, and returns the altered date and timezone property values to thawProperties() and eventually to your Extbase extension.
You can find details in the TYPO3 6.2 API reference for mapDateTime() and its definition in DataMapper.php.
My answer is related to this StackOverflow answer, this TYPO3 Forum thread, and this TYPO3 Forum thread.
This is a problem in the DateTime handling of Extbase, which was recently fixed for TYPO3 7.6 and 8 (dates were not interpreted as UTC). We won’t backport the fix for 6.2 officially, but you can of course apply it yourself.
If you don’t want to patch the core, you can also create an extension class for the relevant part (DataMapper) and override the method (mapDateTime()).

How to properly output DateTime with TYPO3 extbase fluid

I got two dateTime Objects stored in the Database:
2014-11-03 09:00:00
2014-10-21 13:45:00
When i try to output them with the ViewHelper format.date
<f:format.date format="H:i">{termin.datumBeginn}</f:format.date>
I get the following results:
10:00
15:45
So i got a one hour shift and a two hour shift which i can't write a workaround for. How do i set the timezones properly to have a clean output?
Although this is very old, I want to highlight that this was a bug in Extbase until recently, and we fixed it in TYPO3 7.6 and 8. The dates are now properly read as UTC, as which they are stored in the database, and converted to your server timezone.
Ensure that all dates in you database are in same timezone, because that information is not saved there. When you receive some objects from external API calls, they will have timezone in date string and it will be usually UTC. From your internal calls all \DateTime objects will use by default your server default timezone. So set timezone before saving it to database:
$receivedDate = new \DateTime($date);
$reveivedDate->setTimezone(new \DateTimeZone(date_default_timezone_get()));
Setting timezone to server default is convenient, because requires no more changes.. but it's better to save it in 'UTC' I think. In that case you will need to convert it back to your server/user timezone before showing it. It can be done in ViewHelper (not default one from Typo3.Fluid but you can easily extend it in your package - clone and set timezone again). Maybe it's possible now to use doctrine extensions in flow, and save timezone with date to database.. i tried it year ago and couldn't make it..
To solve this issue you need to set $TYPO3_CONF_VARS['SYS']['phpTimeZone'] as "UTC" and $TYPO3_CONF_VARS['SYS']['serverTimeZone'] as "0" (probably only first setting will be enough). You can do it through typo3 backend, using Install tool.
If you have domain model you can use a workaround:
/**
* Returns the startDate
*
* #return \DateTime|NULL $startDate
*/
public function getStartDate() {
$date = $this->startDate;
if($date) {
$date->setTimezone(new \DateTimeZone('UTC'));
}
return $date;
}
Please make sure that you have put setting the Timezone for PHP in the php.ini file
Example: date.timezone = "Asia/Phnom_Penh"
For more information of PHP Timezone please refer to this link: http://php.net/manual/en/timezones.america.php

Custom date format (callback with php logic)

I want to create a dynamic php date format. Example: show the time of the node if it was published today and only the day/month when older then today. I want this format to be available throughout Drupal like the other predefined date formats in Drupal (not just on theme level).
I found the (D7 only) hook for hook_date_format_types but even that one doesn't seem to allow for a callback where I could define this PHP logic.
Does anyone know which hook would make this possible? Or a module which does this?
In Drupal6, format_date() has the dates and times hardcoded. Also, format_date() does not allow callbacks, but it does allow a custom string. That is where you can apply a trick: instead of hardcoding the string in there, you call a function that returns a string.
function mydate_format($timestamp) {
$now = time();
if (($now - $timestamp) < (60*60*24)) {
return "H:i";
}
else {
return "d:m:Y";
}
}
print format_date($timestamp, 'custom', mydate_format($timestamp));
The second option is to re-define a date-timestamp, but that is both hackish and limited. Date-formats are defined with variable_get(), but don't pass the timestamp along; so your example of switching formats based on the value of timestamp is not possible this way.
In settings.php:
$conf['date_format_long'] = $conf['debug'] ? 'r' : 'l, F j, Y - H:i';
This will switch from one value to another, based on whether your settings.php has a flag "debug" set to TRUE or not. As mentioned: the use for this is limited, since you cannot get any context.
The third alternative is to use Date API which offers onlinle configurable time-formats. But that is both clumsy and insecure (inputting executable PHP in your database). It also depends on a very large module-set. And has the same downside as the first solution: you cannot use format_date, but must use a modified function call, instead of format_date(). See all the options at The Drupal.org date themeing handbook.
GOTCHA In all cases Drupal will not call this function for cached content. If you want to have the dates really dynamic you either need to avoid caching alltogether, or implement the date-formatting in clientside javascript.
TL;DR: You cannot have dynamic date-formats without changing some of the code on theme-level. Using a callback-function to generate the "custom" dateformat is the simplest, working solution.
You can use Date API module to add your custom date formatting. Date API module is inside the Date module. After enabling the Date API module you can go the path "admin/settings/date-time/formats/add" to add your custom format.
"admin/settings/date-time/formats/configure" is the path to configure date formats.
Have a look at these. Happy coding.
Thanks
RT
You can go to node.tpl.php(possibly in sites/all/themes/theme_name/node.tpl.php). Here yo can find $created variable, to reformat date you can use your custom function and change the $created as you want.After this all nodes will use your formatted dates.
Regatds,
Chintan.
Use the features module. Create a feature.
In the resulting feature module, on the [feature].module file, create a hook_nodeapi function and format the field with a conditional statement that takes into account the current date() for how the date will be displayed and feed it into the $node->content var.
And that is the way rockstars would do it (-;

Shouldn't changing a user's Drupal locale also change $user->timezone?

I must be missing something really obvious here:
I have a user whose locale is set to America/Los Angeles. When I look in the 'users' database table, they have a value of -28800 for the timezone field. This makes sense; 8 hours before GMT = -28800 seconds.
But now, when the user changes his locale to America/New York, the value of timezone stays the same, rather than switching to -18000, 5 hours before GMT. Why isn't this change happening? If I'm looking in the wrong place, where would I find a timezone value that matches their locale?
The server's timezone is also set to America/Los Angeles, if that matters. Thanks!
Sounds like a bug. What version of Drupal? Either way, you should be able to fix it fairly easily with hook_user. You'll need to do a user_save and explicitly define the new timezone value. It'd be something like this:
function trnAccount_user($op, &$edit, &$account, $category = NULL) {
switch($op) {
case 'update':
user_save($account, array('timezone' => $myTimeZone);
break;
}
$myTimeZone is a placeholder. Do a print_r on the incoming $edit within this hook and you should be able to find where the timezone change has been recorded then just replace $myTimeZone with that array path (for example... $edit['values']['timezone']). If its not coming through at all then something is wrong with the form you're using the change the locale.
If you're using a form you wrote yourself, you could also handle this in the submit function for that form.
ARGGH -- FALSE ALARM. Just as I was wrapping all this up, I thought it might be worth checking another of my Drupal sites to see what happens with $user->timezone there. Turns out that it's working correctly -- change the locale in the user edit page and $user->timezone changes as it ought to. Thus, I'm screwing the pooch somewhere in my current site; Drupal itself seems to be OK. Apologies for wasting your time; but many thanks in any case.

Resources