【问题标题】:Symfony2 datetime best way to store timestamps?Symfony2 datetime 存储时间戳的最佳方式?
【发布时间】:2012-07-15 08:11:33
【问题描述】:

我不知道在数据库中存储时间戳的最佳方式是什么。我想用小时分钟和秒存储整个日期,但它只存储日期(例如 2012-07-14),我想存储 2012-07-14 HH:MM:SS。我正在使用 dateTime 对象。代码如下:

在控制器中:

$user->setCreated(new \DateTime());

在实体中:

/**
 * @var date $created
 *
 * @ORM\Column(name="created", type="date")
 */
private $created;

将日期和时间分别存储在数据库中更好吗?还是更好地像 YYYY-MM-DD HH:MM:SS 一样存储在一起?然后我将不得不比较日期并计算剩余时间,因此这对于简化以后的操作很重要。所以你怎么看 ?有人可以帮我吗?

【问题讨论】:

  • 如果您需要处理不同的时区,请阅读docs

标签: php datetime symfony doctrine-orm timestamp


【解决方案1】:

如果您的数据库支持该类型,那么在数据库中存储时间戳的最佳方式显然是使用时间戳列。而且由于您可以将该列设置为在创建时自动更新,因此您甚至不必为其提供设置器。

有一个 Timestampable behavior extension for Doctrine 2 也可以从用户端执行此操作:

时间戳行为将自动更新您的实体或文档上的日期字段。它通过注释工作,可以在创建、更新甚至特定属性值更改时更新字段。

特点:

  • 在创建、更新甚至记录属性更改时自动更新预定义日期字段
  • ORM 和 ODM 支持使用相同的侦听器
  • 属性的特定注释,无需接口
  • 可以对特定属性或对特定值的关系更改做出反应
  • 可以与其他行为嵌套
  • 对扩展的注解、Yaml 和 Xml 映射支持

有了这种行为,你需要做的就是把你的注释改成

/**
 * @var datetime $created
 *
 * @Gedmo\Timestampable(on="create")
 * @ORM\Column(type="datetime")
 */
private $created;

那么你不需要在你的代码中调用setCreated。首次创建实体时会自动设置该字段。

【讨论】:

  • 如果您处理不同的时区,Timestampable 并不是很有帮助。
  • 好的,我会试试的,这个选项看起来不错。谢谢!
  • @meze 在问题的任何地方都没有提到不同的时区,我认为时区与“创建”字段无关。
  • @Gordon 为这篇精彩的帖子 +1。我尝试了您的方法将其与我使用的方法进行比较(见下文)。我得到的时间非常相似,但仍然不同。(您的方法:2012-07-25 00:07:29;我的方法:2012-07-25 00:00:29)这是什么原因?哪个时间更准确?谢谢
  • @Sydney_o9 我不知道原因。有七个小时的差异,这让我假设时区在这两种方法中都没有正确设置。
【解决方案2】:

为了在不使用Timestampable行为原则的情况下存储创建日期,你也可以使用LifeCycle Callbacks,通过在声明类时添加注解@ORM\HasLifecycleCallbacks。以下是在您的情况下将 YYYY-MM-DD HH:MM:SS 存储在数据库中的方法。

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="yourTable")
 */
class Nasy
{

    /**
    * @ORM\Column(name="created", type="string", length=255)
    */

    private $created;
    /**
     * @ORM\PrePersist
     */
    public function doStuffOnPrePersist()
    {
        $this->created = date('Y-m-d H:i:s');
    }

最后,如果您遇到时区问题,您可以在登录时使用事件监听器在会话中设置时区。 Matt Drolette 在他的博客here 上做了很棒的工作。 无论如何,您可能总是将时间存储在服务器所在的时区中。然后使用会话中设置的时区向用户显示正确的时间。祝你好运。

【讨论】:

  • 您的代码的问题是您将它存储在一个字符串中,这使得对其执行 sql 操作并仍然有效。
  • 您的格式存在错误:月与分钟。正确的格式是 ...date('Y-m-d H:i:s');
  • 如果你的属性是datetime而不是string,你应该使用:$this->created = new \DateTime();
【解决方案3】:

基于@Pratt 的回答,我做到了这一点。我的实体中有 2 个字段,一个用于创建,一个用于修改。

/**
* @ORM\Column(type="datetime")
 */
protected $created_at;

/**
* @ORM\Column(type="datetime")
 */
protected $modified_at;

然后使用注释我在 prePersist 和 preUpdate 上调用它

/**
 * @ORM\PrePersist
 * @ORM\PreUpdate
 */
public function updatedTimestamps()
{
    $this->setModifiedAt(new \DateTime(date('Y-m-d H:i:s')));

    if($this->getCreatedAt() == null)
    {
        $this->setCreatedAt(new \DateTime(date('Y-m-d H:i:s')));
    }
}

该函数可以分解为 2 个函数,一个用于创建一个用于更新,但这是有效的,所以当它正常工作时,我认为没有任何额外代码的原因。

【讨论】:

    【解决方案4】:

    你可以像这样使用@Version:

    /**
     * @var date $created
     *
     * @ORM\Column(name="created", type="datetime")
     * @ORM\Version
     */
    private $created;
    

    这仅适用于日期时间类型。

    【讨论】:

    • 我更喜欢它,而不是为此下载 Gedmo 扩展...但是 Version 到底做了什么?
    猜你喜欢
    • 2015-05-11
    • 1970-01-01
    • 2017-03-03
    • 2017-01-18
    • 1970-01-01
    • 1970-01-01
    • 2020-10-25
    • 2015-01-24
    相关资源
    最近更新 更多