如果我这样做unix_timestamp(some_date)
,它会在内部转换some_date
为 UTC,而some_date
已经是 UTC。有没有办法获得当前的 Unix 时间戳?
编辑:我需要 UTC 时间的 Unix 时间戳。
您应该能够首先使用以下方法将其从 UTC 转换为本地时区CONVERT_TZ
:
UNIX_TIMESTAMP(CONVERT_TZ(some_date, '+00:00', @@global.time_zone))
以下是其他几种方法:
SELECT UNIX_TIMESTAMP(myDate)+UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(UTC_TIMESTAMP())
FROM myTable
SELECT UNIX_TIMESTAMP(myDate)-TIMESTAMPDIFF(SECOND, NOW(), UTC_TIMESTAMP())
FROM myTable
这对我来说很好:
UNIX_TIMESTAMP(CONVERT_TZ("some_date", '+00:00', 'SYSTEM'))
您可以从 UTC 日期时间值获取 MySQL 中的 UNIX 时间戳,如下所示:
SELECT
UNIX_TIMESTAMP(CONVERT_TZ("some_date", '+00:00', @@session.time_zone))
FROM `table_name`
我在这里做了一个备忘单:MySQL 是否应该将其时区设置为 UTC?
因为两个原因:
UNIX_TIMESTAMP
并采用我通常不希望/能够更改FROM_UNIXTIME
的存储时区,以及@@global.time_zone
我首选的解决方案是编写自己的函数,将其转换为 Unix 时间戳并返回:
DELIMITER $$
CREATE FUNCTION UnixTimestamp(utcstamp DATETIME) RETURNS BIGINT UNSIGNED DETERMINISTIC
BEGIN
DECLARE y INT UNSIGNED;
SET y = YEAR(utcstamp);
RETURN (y - 1970) * 365 * 24 * 60 * 60 -- total seconds in full years since 1970
+ FLOOR((y - 1969) / 4) * 24 * 60 * 60 -- add to that total seconds in extra days for each leap year
- FLOOR((y - 1901) / 100) * 24 * 60 * 60 -- subtract seconds for each day in a year that is divisible by 100 because those are not leap years
+ FLOOR((y - 1601) / 400) * 24 * 60 * 60 -- but add back each day in a leap year that is divisible by 400 because those are leap years
+ (DAYOFYEAR(utcstamp) - 1) * 24 * 60 * 60 -- total seconds in full days since beginning of year
+ HOUR(utcstamp) * 60 * 60 -- total seconds for each full hour passed since beginning of day
+ MINUTE(utcstamp) * 60 -- total seconds for each full minute since last full hour
+ SECOND(utcstamp); -- seconds since last full minute
END$$
DELIMITER ;
DELIMITER $$
CREATE FUNCTION FromUnixtime(utcstamp BIGINT UNSIGNED) RETURNS DATETIME DETERMINISTIC
BEGIN
DECLARE s INT UNSIGNED;
DECLARE d INT UNSIGNED;
DECLARE y INT UNSIGNED;
IF utcstamp = 0 THEN RETURN '1970-01-01 00:00:00';
END IF;
SET s = utcstamp % (24 * 60 * 60);
SET d = FLOOR(utcstamp / (24 * 60 * 60)) + 365 * 370 + 90; -- days since 1600-01-01, last full leap year period
SET y = 1600 + FLOOR(d / (400 * 365 + 97)) * 400; -- year is now 1600 + 400 * n, where n >= 0
SET d = d - (400 * 365 + 97) * FLOOR(d / (400 * 365 + 97)); -- days since 1600 + 400 * n, less than 400 years
IF d > 0 THEN
SET y = y + FLOOR((d - 1) / (100 * 365 + 24)) * 100; -- year is now 1600 + 400 * n + 100 * m, where 4 > m >= 0
SET d = d - (100 * 365 + 24) * FLOOR((d - 1) / (100 * 365 + 24)); -- days since 1600 + 400 * n + 100 * m, less than 100 years
SET y = y + FLOOR(d / (4 * 365 + 1)) * 4; -- year is now 1600 + 400 * n + 100 * m + 4 * l, where 25 > l >= 0
SET d = d - (4 * 365 + 1) * FLOOR(d / (4 * 365 + 1)); -- days since 1600 + 400 * n + 100 * m + 4 * l, less than 4 years
IF d > 0 THEN
SET y = y + FLOOR(d / 365); -- year is now 1600 + 400 * n + 100 * m + 4 * l + k, where 4 > k >= 0
SET d = d - 365 * FLOOR(d / 365); -- days since 1600 + 400 * n + 100 * m + 4 * l + k, less than a year
IF (y % 400 = 0 OR (y % 4 = 0 AND y % 100 <> 0)) THEN -- if it's a leap year
IF d > 0 THEN -- and if it's not day 0
SET d = d + 1; -- add a day we dropped in a previous step
ELSEIF d = 0 THEN -- otherwise if it's day 0
SET d = 365; -- then it's actually New Year's Eve
SET y = y - 1; -- on the year before
END IF;
END IF;
ELSE SET d = d + 1;
END IF;
ELSE SET d = d + 1;
END IF;
RETURN CONCAT(MAKEDATE(y, d), ' ', LPAD(FLOOR(s / 3600), 2, 0), ':', LPAD(FLOOR((s - FLOOR(s / 3600) * 3600) / 60), 2, 0), ':', LPAD(s % 60, 2, 0));
END$$
DELIMITER ;
您可以通过执行以下命令来检查这些功能:
SELECT UTC_TIMESTAMP() AS CurrentTime, FromUnixtime(UnixTimestamp(UTC_TIMESTAMP())) AS Result;
CurrentTime
并且Result
应该是一样的。