我有一个问题,我按日期过滤集合,但我希望得到的项目没有在集合中返回,但是如果我打印出集合使用的 SQL 并针对我的数据库运行该项目,则返回该项目。
$from = new \DateTime($lsDate);
$orders = $this->_orderCollectionFactory->create()
->addFieldToSelect(['grand_total', 'created_at'])
->addAttributeToFilter('created_at', array('gteq' => $from->format('Y-m-d H:i:s')))
->addAttributeToFilter('customer_id',$customer->getId())
->setPageSize(10)
->setOrder('created_at', 'desc');
$from->format('Y-m-d H:i:s') // Lets say this is 2019-08-06 15:33:00
$this->logger->info(count($orders)); // This is 0
如果我打印出它生成的 SQL,它看起来像这样:
SELECT `main_table`.`entity_id`, `main_table`.`grand_total`, `main_table`.`created_at` FROM `sales_order` AS `main_table` WHERE (`created_at` >= '2019-08-06 15:33:21')
订单
created_at
应该返回的日期是 2019-08-06 15:34:00
.如果我在我的数据库上运行上面的查询,它会返回上面的一个订单,但是正如你在上面的代码中看到的那样,集合是空的。
如果我将订单日期更改为
2019-08-06 16:34:21
( future 一小时)代码然后返回一个包含一个项目的集合。看起来它与某处的时区有关?也许 DST(夏令时)?编辑
以下是有关
$lsDate
的更多信息多变的。$lsDate
来自客户属性。我这样存储日期: $newDate = new \DateTime();
$customer->setCustomAttribute('ls_start_date', $newDate->format('Y-m-d H:i:s'));
并获取日期:
$lsDate = $customer->getCustomAttribute('ls_start_date')->getValue();
最佳答案
首先,也许我们需要一个通用的 Magento 日期处理解释。
Magento 打算将其所有日期以格林威治标准时间保存在 DB 中。
这种设计选择的原因很简单:Magento 允许您配置可能位于多个时区的多商店。
假设我有一个有 3 家商店的 Magento,我确实在伦敦经营。
这是我的商店:
Europe/London
中配置;这也是我的 Main Store 配置 Asia/Tokyo
时区 America/New_York
现在,让我们举一个商业案例,如果我确实向我的客户 promise “我们在 48 小时内交付,世界范围内,基于您居住的国家/地区首都的时区。”。
然后我在 5 月 1 日 16:15 收到 3 个订单,每个商店一个。
这对我来说非常不方便,在管理员中,将所有三个订单都声明为 5 月 1 日 16:15,以履行我对客户的 promise ,因为我将不得不根据我在订单的管理网格中看到的商店。
对我来说最好的就是看看
为了做到这一点,Magento 将从数据库中检索 GMT 中的日期,然后将当前 sotre 时区应用于该日期。
很容易。
想象一下,如果他们确实在数据库中存储了时区日期,那将会是多么复杂……Magento 需要同时存储日期和时区,并为您必须显示的任何单个日期进行来回转换或时区计算。
非常疯狂的工作要做。
因此,为了遵循 Magento 的工作方式,您最好的选择是以格林威治标准时间将日期存储在数据库中,因此以这种方式创建客户日期:
use Magento\Framework\Stdlib\DateTime\DateTimeFactory;
use Magento\Customer\Model\Customer;
class CustomerLsDate {
private $dateTimeFactory;
public function __construct(DateTimeFactory $dateTimeFactory) {
$this->dateTimeFactory = $dateTimeFactory;
}
public function setLsDate(Customer $customer): CustomerLsDate {
$customer->setCustomAttribute('ls_start_date', $this->dateTimeFactory->create()->gmtDate('Y-m-d H:i:s'));
return $this;
}
}
然后,当您想在此日期查询时,只需按原样使用即可。
如果你想在商店时区向某人说,那么:
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\Customer\Model\Customer;
class CustomerLsDate {
private $timezone;
public function __construct(TimezoneInterface $timezone) {
$this->timezone = $timezone;
}
public function getLsDate(Customer $customer): string {
$date = $this->timezone->date(
new \DateTime(
$customer->getCustomAttribute('ls_start_date')->getValue(),
new \DateTimeZone('GMT')
)
);
Zend_Debug::dump($date->format('Y-m-d H:i:s'));
return $date->format('Y-m-d H:i:s');
}
}
这真的是最适合 Magento 哲学的方法
全
CustomerLsDate
类(class):use Magento\Framework\Stdlib\DateTime\DateTimeFactory;
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\Customer\Model\Customer;
class CustomerLsDate {
private $dateTimeFactory;
private $timezone;
public function __construct(DateTimeFactory $dateTimeFactory, TimezoneInterface $timezone) {
$this->timezone = $timezone;
$this->dateTimeFactory = $dateTimeFactory;
}
public function setLsDate(Customer $customer): CustomerLsDate {
$customer->setCustomAttribute(
'ls_start_date',
$this->dateTimeFactory->create()->gmtDate('Y-m-d H:i:s')
);
return $this;
}
public function getLsDate(Customer $customer): string {
$date = $this->timezone->date(
new \DateTime(
$customer->getCustomAttribute('ls_start_date')->getValue(),
new \DateTimeZone('GMT')
)
);
Zend_Debug::dump($date->format('Y-m-d H:i:s'));
return $date->format('Y-m-d H:i:s');
}
}
里克·詹姆斯有 part of the answer .
自
created_at
是 timestamp
并且默认连接到 MySQL 将 apply the server timezone to a timestamp ,您的手动查询有效。但是现在如果你像 Magento 一样去做
SET time_zone = '+00:00';
SELECT `main_table`.`entity_id`, `main_table`.`grand_total`, `main_table`.`created_at` FROM `sales_order` AS `main_table` WHERE (`created_at` >= '2019-08-06 15:33:21');
您的查询不会像您的 Magento 集合那样返回任何结果。
time_zone
Magento 的设置是在其默认 PDO 适配器实现中完成的:/**
* Creates a PDO object and connects to the database.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*
* @return void
* @throws \Zend_Db_Adapter_Exception
* @throws \Zend_Db_Statement_Exception
*/
protected function _connect()
{
// extra unrelated code comes here...
// As we use default value CURRENT_TIMESTAMP for TIMESTAMP type columns we need to set GMT timezone
$this->_connection->query("SET time_zone = '+00:00'");
// extra unrelated code comes here...
}
来源:Magento/Framework/DB/Adapter/Pdo/Mysql
从那时起,您的答案就在于您的变量
$lsDate
的位置。来自并且如果您能够知道其时区,以便将其转换回 GMT,以获得正确的 GMT 日期以提供给您的集合过滤器。例如,如果您知道您的时区是
'Europe/London'
你可以做$date = new \DateTime('2019-08-06 15:33:21', new \DateTimeZone('Europe/London'));
$date->setTimezone(new \DateTimeZone('GMT'));
echo $date->format('Y-m-d H:i:s'); // echoes 2019-08-06 14:33:21
从您的编辑中,当您创建
new \DateTime()
时你会得到一个 DateTime
绑定(bind)到您的服务器的时区。因此,根据您的喜好,您可以在 GMT 的自定义客户字段中保存日期,也可以保存时区和日期。
1.在客户中以格林威治标准时间保存日期
无论是 PHP 方式
$newDate = new \DateTime('now',new \DateTimeZone('GMT'));
$customer->setCustomAttribute('ls_start_date', $newDate->format('Y-m-d H:i:s'));
并且您最终会在您的客户身上获得格林威治标准时间日期
ls_start_date
或者你也可以用 DI 来做更多的 Magento 方式:
use Magento\Framework\Stdlib\DateTime\DateTimeFactory;
class Whatever {
private $dateTimeFactory;
public function __construct(DateTimeFactory $dateTimeFactory) {
$this->dateTimeFactory = $dateTimeFactory;
}
public function assignThatLsDate($customer) {
$customer->setCustomAttribute('ls_start_date', $this->dateTimeFactory->create()->gmtDate('Y-m-d H:i:s'));
}
}
2. 保存客户本地时区的日期
$newDate = new \DateTime();
$customer->setCustomAttribute('ls_start_date', $newDate->format('Y-m-d H:i:s'));
$customer->setCustomAttribute('ls_start_date_timezone', $newDate->getTimezone ());
然后
$from = new \DateTime(
$customer->getCustomAttribute('ls_start_date')->getValue(),
$customer->getCustomAttribute('ls_start_date_timezone')->getValue()
)->setTimezone(new \DateTimeZone('GMT'));
// query to your collection is unchanged
关于php - Magento 2 Collection Date 按一小时过滤掉,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57380394/