Gle*_*son 4 php mysql datetime magento magento2
我有一个问题,我按日期过滤集合,并且期望得到的项目没有返回到集合中,但是,如果我打印出集合使用的SQL并针对我的数据库运行该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
Run Code Online (Sandbox Code Playgroud)
如果我打印出生成的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')
Run Code Online (Sandbox Code Playgroud)
created_at应退回的订单日期为2019-08-06 15:34:00。
如果我在数据库上运行上述查询,它将返回上面的一个顺序,但是正如您在我上面的代码中看到的那样,该集合为空。
如果我将订单日期更改为2019-08-06 16:34:21(未来一小时),则代码将返回包含一个项目的集合。看起来与时区有关吗?也许是DST(夏令时)?
编辑
这是有关$lsDate变量的更多信息。
$lsDate来自客户属性。我将日期存储为:
$newDate = new \DateTime();
$customer->setCustomAttribute('ls_start_date', $newDate->format('Y-m-d H:i:s'));
Run Code Online (Sandbox Code Playgroud)
并这样获取日期:
$lsDate = $customer->getCustomAttribute('ls_start_date')->getValue();
Run Code Online (Sandbox Code Playgroud)
首先,也许我们需要一个通用的Magento Date处理说明。
Magento打算将其所有日期保存在GMT中的DB中。
选择这种设计的原因很简单:Magento允许您配置可能在多个时区的多存储。
假设我有一家在伦敦设有3家门店的Magento。
这是我的商店:
Europe/London;这也是我的主要商店配置Asia/Tokyo时区配置的日本商店America/New_York现在,让我们以一个商业案例为例,我确实向我的客户保证:“我们将根据您居住的国家首都所在的时区在48小时内交付世界通行证。” 。
然后我得到3个订单,每个商店有5个订单,所有订单都在5月1日16:15分发。
在管理员中,这对我来说极其不便,因为要说所有三个订单都于5月1日16:15下达,以履行我对客户的承诺,因为我必须基于商店,我在订单的管理网格中看到。
对我来说最好的就是看
为了做到这一点,Magento将从数据库中检索格林尼治标准时间的日期,然后将当前的时区时区应用于该日期。
很简单。
想象一下,如果他们确实将时区日期存储在数据库中将会是多么的复杂... 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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,当您要查询该日期时,请直接使用它。
如果您想在商店时区向某人下探,则:
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');
}
}
Run Code Online (Sandbox Code Playgroud)
那确实是最适合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');
}
}
Run Code Online (Sandbox Code Playgroud)
里克·詹姆斯有部分答案。
由于created_at是,timestamp并且与MySQL的默认连接会将服务器时区应用于时间戳,因此您的手动查询有效。
但是现在如果你像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');
Run Code Online (Sandbox Code Playgroud)
您的查询不会像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...
}
Run Code Online (Sandbox Code Playgroud)
资料来源: 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
Run Code Online (Sandbox Code Playgroud)
从您的编辑中,当您创建一个时,new \DateTime()您将获得与DateTime服务器时区的界限。
因此,您可以根据自己的喜好将日期保存在GMT中的自定义客户字段中,也可以保存时区和日期。
两种PHP方式
$newDate = new \DateTime('now',new \DateTimeZone('GMT'));
$customer->setCustomAttribute('ls_start_date', $newDate->format('Y-m-d H:i:s'));
Run Code Online (Sandbox Code Playgroud)
您最终将在客户身上获得格林尼治标准时间 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'));
}
}
Run Code Online (Sandbox Code Playgroud)
$newDate = new \DateTime();
$customer->setCustomAttribute('ls_start_date', $newDate->format('Y-m-d H:i:s'));
$customer->setCustomAttribute('ls_start_date_timezone', $newDate->getTimezone ());
Run Code Online (Sandbox Code Playgroud)
然后
$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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
476 次 |
| 最近记录: |