dongtang1909 2010-04-03 18:22
浏览 327
已采纳

为什么MySQL不支持毫秒/微秒的精度?

So I just found the most frustrating bug ever in MySQL.

Apparently the TIMESTAMP field, and supporting functions do not support any greater precision than seconds!?

So I am using PHP and Doctrine, and I really need those microseconds (I am using the actAs: [Timestampable] property).

I found a that I can use a BIGINT field to store the values. But will doctrine add the milliseconds? I think it just assigns NOW() to the field. I am also worried the date manipulation functions (in SQL) sprinkled through the code will break.

I also saw something about compiling a UDF extension. This is not an acceptable because I or a future maintainer will upgrade and poof, change gone.

Has anyone found a suitable workaround?

  • 写回答

8条回答 默认 最新

  • dongshuo9350 2010-04-05 00:35
    关注

    I found a workaround! It is very clean and doesn't require any application code changes. This works for Doctrine, and can be applied to other ORM's as well.

    Basically, store the timestamp as a string.

    Comparisons and sorting works if the date string is formatted correctly. MySQL time functions will truncate the microsecond portion when passed a date string. This is okay if microsecond precision isn't needed for date_diff etc.

    SELECT DATEDIFF('2010-04-04 17:24:42.000000','2010-04-04 17:24:42.999999');
    > 0
    
    SELECT microsecond('2010-04-04 17:24:42.021343');
    > 21343 
    

    I ended up writing a MicroTimestampable class that will implement this. I just annotate my fields as actAs:MicroTimestampable and voila, microtime precision with MySQL and Doctrine.

    Doctrine_Template_MicroTimestampable

    class Doctrine_Template_MicroTimestampable extends Doctrine_Template_Timestampable
    {
        /**
         * Array of Timestampable options
         *
         * @var string
         */
        protected $_options = array('created' =>  array('name'          =>  'created_at',
                                                        'alias'         =>  null,
                                                        'type'          =>  'string(30)',
                                                        'format'        =>  'Y-m-d H:i:s',
                                                        'disabled'      =>  false,
                                                        'expression'    =>  false,
                                                        'options'       =>  array('notnull' => true)),
                                    'updated' =>  array('name'          =>  'updated_at',
                                                        'alias'         =>  null,
                                                        'type'          =>  'string(30)',
                                                        'format'        =>  'Y-m-d H:i:s',
                                                        'disabled'      =>  false,
                                                        'expression'    =>  false,
                                                        'onInsert'      =>  true,
                                                        'options'       =>  array('notnull' => true)));
    
        /**
         * Set table definition for Timestampable behavior
         *
         * @return void
         */
        public function setTableDefinition()
        {
            if ( ! $this->_options['created']['disabled']) {
                $name = $this->_options['created']['name'];
                if ($this->_options['created']['alias']) {
                    $name .= ' as ' . $this->_options['created']['alias'];
                }
                $this->hasColumn($name, $this->_options['created']['type'], null, $this->_options['created']['options']);
            }
    
            if ( ! $this->_options['updated']['disabled']) {
                $name = $this->_options['updated']['name'];
                if ($this->_options['updated']['alias']) {
                    $name .= ' as ' . $this->_options['updated']['alias'];
                }
                $this->hasColumn($name, $this->_options['updated']['type'], null, $this->_options['updated']['options']);
            }
    
            $this->addListener(new Doctrine_Template_Listener_MicroTimestampable($this->_options));
        }
    }
    

    Doctrine_Template_Listener_MicroTimestampable

    class Doctrine_Template_Listener_MicroTimestampable extends Doctrine_Template_Listener_Timestampable
    {
        protected $_options = array();
    
        /**
         * __construct
         *
         * @param string $options 
         * @return void
         */
        public function __construct(array $options)
        {
            $this->_options = $options;
        }
    
        /**
         * Gets the timestamp in the correct format based on the way the behavior is configured
         *
         * @param string $type 
         * @return void
         */
        public function getTimestamp($type, $conn = null)
        {
            $options = $this->_options[$type];
    
            if ($options['expression'] !== false && is_string($options['expression'])) {
                return new Doctrine_Expression($options['expression'], $conn);
            } else {
                if ($options['type'] == 'date') {
                    return date($options['format'], time().".".microtime());
                } else if ($options['type'] == 'timestamp') {
                    return date($options['format'], time().".".microtime());
                } else {
                    return time().".".microtime();
                }
            }
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(7条)

报告相同问题?

悬赏问题

  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能
  • ¥15 jmeter脚本回放有的是对的有的是错的
  • ¥15 r语言蛋白组学相关问题
  • ¥15 Python时间序列如何拟合疏系数模型
  • ¥15 求学软件的前人们指明方向🥺