首先,也许我们需要一个通用的 Magento 日期处理说明。
Magento 打算将其所有日期保存在 GMT 的数据库中。
这种设计选择的原因很简单:Magento 允许您配置可能位于多个时区的多商店。
假设我有一个 Magento,有 3 家商店,我在伦敦经营。
这是我的商店:
- 我的伦敦商店,配置在
Europe/London;这也是我的 Main Store 配置
- 日本商店,配置为
Asia/Tokyo 时区
- 北美商店,配置时区
America/New_York
现在,让我们来看一个商业案例,如果我确实向我的客户承诺“我们会在 48 小时内交付,全球范围内,基于您所居住国家/地区首都的时区。” .
然后我收到了 3 个订单,每个商店都有一个订单,都是 5 月 1 日 16:15 的订单。
这对我来说是极其不方便的,在管理员中,将所有三个订单声明为 5 月 1 日 16:15 下达,以履行我对客户的承诺,因为我必须根据我在订单的管理网格中看到的商店。
对我来说最好的就是看到
-
5 月 1 日 16:15 在伦敦商店下单
-
4 月 30 日 20:15 在东京商店下单
-
5 月 1 日 21:15 在纽约商店下单
为了做到这一点,Magento 会从数据库中检索 GMT 日期,然后将当前的时区应用于日期。
很简单。
想象一下,如果他们确实将时区日期存储在数据库中会有多复杂... Magento 需要同时存储日期和时区,并为您必须显示的任何单个日期进行来回转换或时区计算.
非常疯狂的工作。
因此,为了遵循 Magento 的工作方式,您最好的选择是将您的日期存储在 GMT 的数据库中,并以这种方式创建您的客户日期:
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类:
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');
}
}
Rick James 有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 集合那样返回任何结果。
Magento 的 time_zone 设置在其默认 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。
因此,根据您的喜好,您可以将日期保存在 GMT 的自定义客户字段中,也可以保存时区和日期。
1。在客户中保存 GMT 日期
PHP 方式
$newDate = new \DateTime('now',new \DateTimeZone('GMT'));
$customer->setCustomAttribute('ls_start_date', $newDate->format('Y-m-d H:i:s'));
您最终会在您的客户ls_start_date 上获得 GMT 日期
或者您也可以使用更多 Magento 方式,使用 DI:
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