1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      javascript關(guān)于“時間”的一次探索

      原文對 ISO 8601 時間格式中 T 和 Z 的表述有一些錯誤,我已經(jīng)對原文進行了一些修訂,抱歉給大家造成誤解。

      創(chuàng)新互聯(lián)建站:成立與2013年為各行業(yè)開拓出企業(yè)自己的“網(wǎng)站建設(shè)”服務(wù),為數(shù)千家公司企業(yè)提供了專業(yè)的成都網(wǎng)站建設(shè)、做網(wǎng)站、網(wǎng)頁設(shè)計和網(wǎng)站推廣服務(wù), 按需網(wǎng)站制作由設(shè)計師親自精心設(shè)計,設(shè)計的效果完全按照客戶的要求,并適當?shù)奶岢龊侠淼慕ㄗh,擁有的視覺效果,策劃師分析客戶的同行競爭對手,根據(jù)客戶的實際情況給出合理的網(wǎng)站構(gòu)架,制作客戶同行業(yè)具有領(lǐng)先地位的。

      最近使用 sequelize 過程中發(fā)現(xiàn)一個“奇怪”的問題,將某個時間插入到表中后,通過 sequelize 查詢出來的時間和通過 MySQL 命令行工具查詢出來的時間不一樣。非常困惑,于是研究了下,下面是學習成果。

      基本概念

      我們先來介紹一些可能當年在地理課上學習過的基本概念。

      說起來,時間真是一個神奇的東西。以前人們通過觀察太陽的位置來決定時間(比如:使用日晷),這就使得不同經(jīng)緯度的地區(qū)時間是不一樣的。后來人們進一步規(guī)定以子午線為中心,向東西兩側(cè)延伸,每 15 度劃分一個時區(qū),剛好是 24 個時區(qū)。然后因為一天有 24 小時,地球自轉(zhuǎn)一圈是 360 度,360 度 / 24 小時 = 15 度/小時,所以每差一個時區(qū),時間就差一個小時。

      最開始的標準時間(子午線中心處的時間)是英國倫敦的皇家格林威治天文臺的標準時間(因為它剛好在本初子午線經(jīng)過的地方),這就是我們常說的 GMT(Greenwich Mean Time)。然后其他各個時區(qū)根據(jù)標準時間確定自己的時間,往東的時區(qū)時間晚(表示為 GMT+hh:mm)、往西的時區(qū)時間早(表示為 GMT-hh:mm)。比如,中國標準時間是東八區(qū),我們的時間就總是比 GMT 時間晚 8 小時,他們在凌晨 1 點,我們已經(jīng)是早晨 9 點了。

      但是 GMT 其實是根據(jù)地球自轉(zhuǎn)、公轉(zhuǎn)計算的(太陽每天經(jīng)過英國倫敦皇家格林威治天文臺的時間為中午 12 點),不是非常準確,于是后面提出了根據(jù)原子鐘計算的標準時間 UTC(Coordinated Universal Time)。

      一般情況下,GMT 和 UTC 可以互換,但是實際上,GMT 是一個時區(qū),而 UTC 是一個時間標準。

      可以在這里看到所有的時區(qū):https://www.timeanddate.com/time/map/

      所以,當我們“展示”某個時間時,明確時區(qū)就變得非常重要了。不然你只說現(xiàn)在是 2016-01-11 19:30:00,然后不告訴我時區(qū),我其實是沒法準確知道時間的(當然,我可以認為這個時間是我所在時區(qū)的當?shù)貢r間)。如果你說現(xiàn)在是 2016-01-11 19:30:00 GMT+0800,那我就知道這個時間是東八區(qū)的時間了。如果我在東八區(qū),那時間就是 19:30,如果我在 GMT 時區(qū),那時間就是 11:30(減掉 8 小時)。

      JavaScript 中的“時間”

      我們現(xiàn)在來介紹下 JavaScript 中的“時間”,包括:Date、Date.parse、Date.UTC、Date.now。

      注:下面的代碼示例可以在 node shell 里面運行,如果你運行的時候結(jié)果和下面的不一致,那可能咱們不在一個時區(qū):)

      Date 構(gòu)造器

      構(gòu)造時間的方法有下面幾種:

      new Date();   // 當前時間
      new Date(value);  // 自 1970-01-01 00:00:00 UTC 經(jīng)過的毫秒數(shù)
      new Date(dateString); // 時間字符串
      new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);

      需要注意的是:構(gòu)造出的日期用來顯示時,會被轉(zhuǎn)換為本地時間(調(diào)用 toString 方法):

      > new Date()
      Mon Jan 11 2016 20:15:18 GMT+0800 (CST)

      打印出我寫這篇文章時的本地時間。后面的 GMT+0800 表示是“東八區(qū)”,CST 表示是“中國標準時間(China Standard Time)”。

      有一個很“詭異”的地方是如果我們直接使用 Date,而不是 new Date,得到的將會是字符串,而不是 Date 類型的對象:

      > typeof Date()
      'string'
      > typeof new Date()
      'object'

      時間字符串

      我們先說最復雜的時間字符串形式。它實際上支持兩種格式:一種是 RFC-2822 的標準;另一種是 ISO 8601 的標準。我們主要介紹后一種。

      ISO 8601

      ISO 8601的標準格式是:YYYY-MM-DDTHH:mm:ss.sssZ,分別表示:

      • YYYY:年份,0000 ~ 9999
      • MM:月份,01 ~ 12
      • DD:日,01 ~ 31
      • T:分隔日期和時間
      • HH:小時,00 ~ 24
      • mm:分鐘,00 ~ 59
      • ss:秒,00 ~ 59
      • .sss:毫秒
      • Z:時區(qū),可以是:Z(UFC)、+HH:mm、-HH:mm

      這里我們主要來說下 T、以及 Z。

      T

      T 也可以用空格表示,但是這兩種表示有點不一樣,T 其實表示 UTC,而空格會被認為是本地時區(qū)(前提是不通過 Z 指定時區(qū))。這里的表述是錯誤的,T 僅僅是分隔日期和時間的符號,沒有其他含義。所以下面的例子其實結(jié)果是一樣的。

      > new Date('1970-01-01 00:00:00')
      Thu Jan 01 1970 00:00:00 GMT+0800 (CST)
      
      > new Date('1970-01-01T00:00:00')
      Thu Jan 01 1970 00:00:00 GMT+0800 (CST)
      

      這里補充一點需要注意的,時間字符串這種形式有一個特殊的邏輯:如果你不提供“時間”(也就是 T 分隔后的內(nèi)容),得到的其實是 UTC 時間。比如:

      > new Date('1970-01-01')
      Thu Jan 01 1970 08:00:00 GMT+0800 (CST)
      
      > new Date('1970-01-01T00:00')
      Thu Jan 01 1970 00:00:00 GMT+0800 (CST)
      

      Z

      Z 用來表示傳入時間的時區(qū)(zone),不指定并且沒有使用 T 分隔而是使用空格分隔時,就按本地時區(qū)處理。這個說法也不嚴謹,指定 Z 時表示 UTC 時間,不指定時表示的是本地時間。

      > new Date('1970-01-01T00:00:00')
      Thu Jan 01 1970 00:00:00 GMT+0800 (CST)
      
      > new Date('1970-01-01T00:00:00Z')
      Thu Jan 01 1970 08:00:00 GMT+0800 (CST)
      
      

      示例 1 是東八區(qū)時間,顯示的時間和傳入的時間一致(因為我本地時區(qū)是東八區(qū))。

      示例 2 指定了 Z(也就是 UTC 零時區(qū)),顯示的時間會加上本地時區(qū)的偏移(8 小時)。

      RFC-2822

      RFC-2822 的標準格式大概是這樣:Wed Mar 25 2015 09:56:24 GMT+0100。其實就是上面顯示時間時使用的形式:

      > new Date('Thu Jan 01 1970 00:00:00 GMT+0800 (CST)')
      Thu Jan 01 1970 00:00:00 GMT+0800 (CST)

      除了能表示基本信息,還可以表示星期,但是一點也不容易讀,不建議使用。完整的規(guī)范可以在這里查看:https://tools.ietf.org/html/rfc2822#page-14

      時間戳

      Date 構(gòu)造器還可以接受整數(shù),表示想要構(gòu)造的時間自 UTC 時間 1970-01-01 00:00:00 經(jīng)過的毫秒數(shù)。比如下面的代碼:

      > new Date(1000 * 1)
      Thu Jan 01 1970 08:00:01 GMT+0800 (CST)
      

      傳人 1 秒,等價于:1970-01-01 00:00:01Z,顯示的時間加上了本地時區(qū)的偏移(8 小時)。

      多參數(shù)

      最后,Date 構(gòu)造器還支持傳遞多個參數(shù),這種方法就沒辦法指定時區(qū)了,都當做本地時間處理。比如下面的代碼:

      > new Date(1970, 0, 1, 0, 0, 0)
      Thu Jan 01 1970 00:00:00 GMT+0800 (CST)
      

      顯示時間和傳入時間一致,均是本地時間。注意:月份是從 0 開始的。

      Date.parse

      Date.parse 接受一個時間字符串,如果字符串能正確解析就返回自 UTC 時間 1970-01-01 00:00:00 經(jīng)過的毫秒數(shù),否則返回 NaN:

      > Date.parse('1970-01-01 00:00:00')
      -28800000
      
      > new Date(Date.parse('1970-01-01 00:00:00'))
      Thu Jan 01 1970 00:00:00 GMT+0800 (CST)
      
      > Date.parse('1970-01-01T00:00:00')
      0
      
      > new Date(Date.parse('1970-01-01T00:00:00'))
      Thu Jan 01 1970 08:00:00 GMT+0800 (CST)
      
      

      示例 1,-28800000 換算后剛好是 8 小時表示的毫秒數(shù),28800000 / (1000 * 60 * 60),我們傳入的是本地時區(qū)時間,等于 UTC 時間的 1969-12-31 16:00:00,和 UTC 時間 1970-01-01 00:00:00 相差剛好 -8 小時。

      示例 2,將 parse 后的毫秒數(shù)傳遞給構(gòu)造器,最后顯示的時間加上了本地時區(qū)的偏移(8 小時),所以結(jié)果剛好是 1970-01-01 00:00:00。

      示例 3,傳入的是 UTC 時區(qū)時間,所以結(jié)果為 0。

      示例 4,將 parse 后的毫秒數(shù)傳遞給構(gòu)造器,最后顯示的時間加上了本地時區(qū)的偏移(8 小時),所以結(jié)果剛好是 1970-01-01 08:00:00。

      Date.UTC

      Date.UTC 接受的參數(shù)和 Date 構(gòu)造器多參數(shù)形式一樣,然后返回時間自 UTC 時間 1970-01-01 00:00:00 經(jīng)過的毫秒數(shù):

      > Date.UTC(1970,0,1,0,0,0)
      0
      
      > Date.parse('1970-01-01T00:00:00')
      0
      
      > Date.parse('1970-01-01 00:00:00Z')
      0
      
      

      可以看出,Date.UTC 進行的是一種“絕對運算”,傳入的時間就是 UTC 時間,不會轉(zhuǎn)換為當?shù)貢r間。

      Date.now
      Date.now 返回當前時間距 UTC 時間 1970-01-01 00:00:00 經(jīng)過的毫秒數(shù):

      > Date.now()
      1452520484343
      
      > new Date(Date.now())
      Mon Jan 11 2016 21:54:55 GMT+0800 (CST)
      
      > new Date()
      Mon Jan 11 2016 21:55:00 GMT+0800 (CST)
      
      

      MySQL 中的“時間”

      MySQL 中和時間相關(guān)的數(shù)據(jù)類型主要包括:YEAR、TIME、DATE、DATETIME、TIMESTAMP。

      DATE、YEAR、TIME 比較簡單,大概總結(jié)如下:

      名稱占用字節(jié)取值
      DATE3 字節(jié)1000-01-01 ~ 9999-12-31
      YEAR1 字節(jié)1901 ~ 2155
      TIME3 字節(jié)-838:59:59 ~ 838:59:59

      注:TIME 的小時范圍可以這么大(超過 24 小時),是因為它還可以用來表示兩個時間點之差。

      DATEIME vs TIMESTAMP

      我們主要來說明下 DATETIME 和 TIMESTAMP,可以做下面的總結(jié):

      名稱占用字節(jié)取值受 time_zone 設(shè)置影響
      DATETIME8 字節(jié)1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
      TIMESTAMP4 字節(jié)1970-01-01 00:00:00 ~ 2038-01-19 03:14:07

      第一個區(qū)別是占用字節(jié)不同,導致能表示的時間范圍也不一樣。

      第二個區(qū)別是 DATETIME 是“常量”,保存時就是保存時的值,檢索時是一樣的值,不會改變;而 TIMESTAMP 則是“變量”,保存時數(shù)據(jù)庫服務(wù)器將其從time_zone 時區(qū)轉(zhuǎn)換為 UTC 時間后保存,檢索時將其轉(zhuǎn)換從 UTC 時間轉(zhuǎn)換為 time_zone 時區(qū)時間后返回。

      比如,我們有下面這樣一張表:

      CREATE TABLE `tests` (
       `id` INTEGER NOT NULL auto_increment , 
       `datetime` DATETIME, 
       `timestamp` TIMESTAMP, 
       PRIMARY KEY (`id`)
      ) ENGINE=InnoDB;

      連接到數(shù)據(jù)庫服務(wù)器后,可以執(zhí)行 SHOW VARIABLES LIKE '%time_zone%' 查看當前時區(qū)設(shè)置。類似下面這樣的結(jié)果:

      Variable_nameValue
      system_time_zoneCST
      time_zoneSYSTEM

      說明我目前時區(qū)是 CST(China Standard Time),也就是東八區(qū)。

      我們嘗試插入下面的數(shù)據(jù):

      INSERT INTO `tests` (`id`, `datetime`, `timestamp`) VALUES (DEFAULT, '1970-01-01 00:00:00', '1970-01-01 00:00:00');

      會發(fā)現(xiàn)有一個報錯:Error Code: 1292. Incorrect datetime value: '1970-01-01 00:00:00' for column 'timestamp'。給 timestamp 這一列提供的值不對,因為我們嘗試插入 1970-01-01 00:00:00 時,數(shù)據(jù)庫服務(wù)器會根據(jù) time_zone 的設(shè)置將其轉(zhuǎn)換為 UTC 時間,也就是 1969-12-31 16:00:00,而這個值明顯超過了 TIMESTAMP 類型的范圍。

      我們換個大一點的值:

      INSERT INTO `tests` (`id`, `datetime`, `timestamp`) VALUES (DEFAULT, '2000-01-01 00:00:00', '2000-01-01 00:00:00');

      這次就成功插入了。

      再次檢索時結(jié)果也是正確的(數(shù)據(jù)庫服務(wù)器將值從 UTC 時間轉(zhuǎn)換為 time_zone 設(shè)置的時區(qū)時間):

      SELECT * FROM sample.tests;

      返回:

      iddatetimetimestamp
      12000-01-01 00:00:002000-01-01 00:00:00

      如果我們先將 time_zone 設(shè)置為一個不同的值后再進行檢索就會發(fā)現(xiàn)不同的結(jié)果:

      SET time_zone = '+00:00';
      SELECT * FROM sample.tests;

      返回:

      iddatetimetimestamp
      12000-01-01 00:00:001999-12-31 16:00:00

      可以看到 datetime 列值沒有受 time_zone 設(shè)置的影響,而 timestamp 列值卻改變了。數(shù)據(jù)庫服務(wù)器將其從 UTC 時區(qū)轉(zhuǎn)換為 time_zone 時區(qū)的時間(首先 2000-01-01 00:00:00 在上面進行插入時根據(jù) time_zone 被轉(zhuǎn)換為了 1999-12-31 16:00:00,此次檢索時 time_zone 被設(shè)置為 +00:00,轉(zhuǎn)換回來剛好就是 1999-12-31 16:00:00)。

      那這兩種類型怎么選擇呢?建議優(yōu)先使用 DATETIME,表示范圍大、不容易受服務(wù)器的設(shè)置影響。

      在 JavaScript 和 MySQL 間轉(zhuǎn)換

      分別說明了 JavaScript 和 MySQL 中的“時間”后,我們來聊聊 ORM 框架一般都是怎么樣在兩者間進行正確、合適的轉(zhuǎn)換來避免混亂的。下面的說明將基于 sequelize 框架來解釋,主要是一種思路,其他的框架可以閱讀框架提供的文檔或是源碼。

      sequelize 實際上有一個 timezone 的配置,默認是 +00:00(http://sequelize.readthedocs.org/en/latest/api/sequelize/.)。這個 timezone 有下面的用途:

      • 建立數(shù)據(jù)庫連接時,執(zhí)行 SET time_zone = opts.timezone
      • MySQL 的時間類型和 JavaScript 的時間類型的互相轉(zhuǎn)換

      第一個用途很簡單,體現(xiàn)在源碼里就是執(zhí)行一個 SQL 語句:

      connection.query("SET time_zone = '" + self.sequelize.options.timezone + "'"); /* jshint ignore: line */

      第二個用途主要體現(xiàn)在兩個地方:1)在 JavaScript 中調(diào)用 ORM 方法進行插入、更新時,需要將 Date 類型轉(zhuǎn)為正確的 SQL 語句;2)從 MySQL 服務(wù)器查詢數(shù)據(jù)時,需要將數(shù)據(jù)庫查詢到的值轉(zhuǎn)換為 JavaScript 中的 Date 類型。下面我們分別來看一看。

      JavaScript -> MySQL

      這個轉(zhuǎn)換的核心代碼如下:

      SqlString.dateToString = function(date, timeZone, dialect) {
       if (moment.tz.zone(timeZone)) {
       date = moment(date).tz(timeZone);
       } else {
       date = moment(date).utcOffset(timeZone);
       }
      
       if (dialect === 'mysql' || dialect === 'mariadb') {
       return date.format('YYYY-MM-DD HH:mm:ss');
       } else {
       // ZZ here means current timezone, _not_ UTC
       return date.format('YYYY-MM-DD HH:mm:ss.SSS Z');
       }
      };
      
      

      代碼邏輯如下:

      1. 檢查 timeZone 是否存在,如果存在(存在指的是類似 America/New_York 這樣的表示法),調(diào)用 tz 設(shè)置 date 的時區(qū)。
      2. 如果不存在(類似 +00:00、-07:00 這樣的表示法),調(diào)用 utcOffset 設(shè)置 date 的相對 UTC 的時區(qū)偏移。
      3. 最后使用上面設(shè)置的時區(qū)偏移將其 format 成 MySQL 需要的 YYYY-MM-DD HH:mm:ss 格式。

      舉兩個例子。

      如果 timeZone 等于 +00:00,date 等于 new Date('2016-01-12 09:46:00'),到 UTC 的偏移等于 (timeZone - 本地時區(qū)) + timeZone:(00:00 - 08:00) + 00:00 = -08:00,即 2016-01-12 09:46:00-08:00,于是 format 后的結(jié)果是 2016-01-12 01:46:00。

      如果 timeZone 等于 +08:00,date 等于 new Date('2016-01-12 09:46:00'),到 UTC 的偏移等于 (timeZone - 本地時區(qū)) + timeZone:(08:00 - 08:00) + 08:00 = 08:00,即 2016-01-12 09:46:00+08:00。于是 format 后的結(jié)果是 2016-01-12 09:46:00。

      如果 timeZone 等于 Asia/Shanghai,結(jié)果也會是 2016-01-12 09:46:00,和 +08:00 等價。

      sequelize 的 timezone 默認是 +00:00,所以,我們在 JavaScript 中的時間最后應(yīng)用到數(shù)據(jù)庫中都會被轉(zhuǎn)換成 UTC 的時間(比實際的時間早 8 小時)。

      MySQL -> JavaScript

      這個轉(zhuǎn)換過程實際上是更底層的 node-mysql 庫來實現(xiàn)的。核心代碼如下:

       switch (field.type) {
       case Types.TIMESTAMP:
       case Types.DATE:
       case Types.DATETIME:
       case Types.NEWDATE:
        var dateString = parser.parseLengthCodedString();
        if (dateStrings) {
        return dateString;
        }
        var dt;
      
        if (dateString === null) {
        return null;
        }
      
        var originalString = dateString;
        if (field.type === Types.DATE) {
        dateString += ' 00:00:00';
        }
      
        if (timeZone !== 'local') {
        dateString += ' ' + timeZone;
        }
      
        dt = new Date(dateString);
        if (isNaN(dt.getTime())) {
        return originalString;
        }
      
        return dt;
       // 更多代碼...
      }
      
      

      處理過程大概是這樣:

      1. 用 parser 將服務(wù)器返回的二進制數(shù)據(jù)解析為時間字符串
      2. 如果配置了強制返回字符串 dateStrings 而不是轉(zhuǎn)換回 Date 類型,直接返回 dateString
      3. 如果字段類型是 DATE,時間字符串的時間部分統(tǒng)一為 00:00:00
      4. 如果配置的 timeZone 不是 local(本地時區(qū)),時間字符串加上時區(qū)信息
      5. 將時間字符串傳給 Date 構(gòu)造器,如果構(gòu)造出的時間不合法,返回原始時間字符串,否則返回時間對象

      默認情況下,sequelize 在進行連接時傳遞給 node-mysql 的 timeZone 是 +00:00,所以,第 4 步的時間字符串會是類似這樣的值 2016-01-12 01:46:00+00:00,而這個值傳遞給 Date 構(gòu)造器,在顯示時轉(zhuǎn)換回本地時區(qū)時間,就變成了 2016-01-12 09:46:00(比數(shù)據(jù)庫中的時間晚 8 小時)。

      一個例子

      在使用 sequelize 定義模型時,其實是沒有 TIMESTAMP 類型的,sequelize 只提供了一個 Sequelize.DATE 類型,生成建表語句時被轉(zhuǎn)換為 DATETIME。

      如果是在舊表上定義模型,而這張舊表剛好有 TIMESTAMP 類型的列,對 TIMESTAMP 類型的列定義模型時還是可以使用 Sequelize.DATE,對操作沒有任何影響。但是 TIMESTAMP 是受 time_zone 設(shè)置影響的,這會引起一些困惑。下面我們來看一個例子。

      sequelize 默認將 time_zone 設(shè)置為 +00:00,當我們執(zhí)行下面代碼時:

      Test.create({
       'datetime': new Date('2016-01-10 20:07:00'),
       'timestamp': new Date('2016-01-10 20:07:00')
       });
      

      會進行上面提到的 JavaScript 時間到 MySQL 時間字符串的轉(zhuǎn)換,生成的 SQL 其實是(時間被轉(zhuǎn)換為了 UTC 時間,比本地時間早了 8 小時):

      INSERT INTO `tests` (`id`,`datetime`,`timestamp`) VALUES (DEFAULT,'2016-01-10 12:07:00','2016-01-10 12:07:00');

      當我們執(zhí)行 Test.findAll() 來查詢數(shù)據(jù)時,會進行上面提到的 MySQL 時間到 JavaScript 時間的轉(zhuǎn)換,其實就是返回這樣的結(jié)果(顯示時時間從 UTC 時間轉(zhuǎn)換回了本地時間):

      > new Date('2016-01-10 12:07:00+00:00')
      Sun Jan 10 2016 20:07:00 GMT+0800 (CST)

      和我們插入時的時間是一致的。

      如果我們通過 MySQL 命令行來查詢數(shù)據(jù)時,發(fā)現(xiàn)其實是這樣的結(jié)果:

      iddatetimetimestamp
      12016-01-10 12:07:002016-01-10 20:07:00

      這很好理解,因為我們數(shù)據(jù)庫服務(wù)器的 time_zone 默認是東八區(qū),TIMESTAMP 是受時區(qū)影響的,查詢時被數(shù)據(jù)庫服務(wù)器從 UTC 時間轉(zhuǎn)換回了 time_zone 時區(qū)時間;DATETIME 不受影響,還是 UTC 時間。

      如果我們先執(zhí)行 SET time_zone = '+00:00',再進行查詢,那結(jié)果就都會是 UTC 時間了。所以,不要以為數(shù)據(jù)出錯了哦。

      總結(jié)下就是,sequelize 會將本地時間轉(zhuǎn)換為 UTC 時間后入庫,查詢時再將 UTC 時間轉(zhuǎn)換為本地時間。這能達到最好的兼容性,存儲總是使用 UTC 時間,展示時應(yīng)用端自己轉(zhuǎn)換為本地時區(qū)時間后顯示。當然這個的前提是數(shù)據(jù)類型選用 DATETIME。

      兼容老數(shù)據(jù)

      這里要說的最后一個問題是基于舊表定義 sequelize 模型,并且表中時間值插入時沒有轉(zhuǎn)換為 UTC 時間(全部是東八區(qū)時間),而且 DATETIME 和 TIMESTAMP 混用,該怎么辦?

      在默認配置下,情況如下:

      查詢 DATETIME 類型數(shù)據(jù)時,時間總是會晚 8 小時。比如,數(shù)據(jù)庫中某條老數(shù)據(jù)的時間是 2012-01-01 01:00:00(已經(jīng)是本地時間了,因為沒轉(zhuǎn)換),查詢時被 sequelize 轉(zhuǎn)換為 new Date('2012-01-01 01:00:00+00:00'),顯示時轉(zhuǎn)換為本地時間 2012-01-01 09:00:00,結(jié)果顯然不對。

      查詢 TIMESTAMP 類型數(shù)據(jù)時,時間是正確的。這是因為 TIMESTAMP 受 time_zone 影響,sequelize 默認將其設(shè)置為 +00:00,查詢時數(shù)據(jù)庫服務(wù)器先將時間轉(zhuǎn)換到 time_zone 設(shè)置的時區(qū)時間,由于沒有時區(qū)偏移,剛好查出來的就是數(shù)據(jù)庫中的值。比如:2012-01-01 00:00:00(注意這個值是 UTC 時間),sequelize 將其轉(zhuǎn)換為 new Date('2012-01-01 00:00:00+00:00'),顯示時轉(zhuǎn)換為本地時間 2012-01-01 08:00:00,剛好“僥幸”正確。

      新插入的數(shù)據(jù) sequelize 會進行上一部分說的雙向轉(zhuǎn)換來保證結(jié)果的正確。

      維持默認配置顯然導致查詢 DATETIME 不準確,解決方法就是將 sequelize 的 timezone 配置為 +08:00。這樣一來,情況變成下面這樣:

      查詢 DATETIME 類型數(shù)據(jù)時,時間 2012-01-01 01:00:00 被轉(zhuǎn)換為 new Date('2012-01-01 01:00:00+08:00'),顯示時轉(zhuǎn)換為本地時間 2012-01-01 01:00:00,結(jié)果正確。

      查詢 TIMESTAMP 類型數(shù)據(jù)時,由于 time_zone 被設(shè)置為了 +08:00,數(shù)據(jù)庫服務(wù)器先將庫中 UTC 時間 2011-01-01 00:00:00 轉(zhuǎn)換到 time_zone 時區(qū)時間(加上 8 小時偏移)為 2011-01-01 08:00:00,sequelize 將其轉(zhuǎn)換為 new Date('2011-01-01 08:00:00+08:00'),顯示時轉(zhuǎn)換為本地時間 2011-01-01 08:00:00,結(jié)果正確。

      插入、更新數(shù)據(jù)時,所有 JavaScript 時間會轉(zhuǎn)換為東八區(qū)時間入庫。

      這樣帶來的問題是,所有入庫時間都是東八區(qū)時間,如果有其他應(yīng)用的時區(qū)不是東八區(qū),那就需要自己基于東八區(qū)時間計算偏移并轉(zhuǎn)換時間后顯示了。

      參考資料

      一不小心寫的有點長了,下面列出參考資料供大家進一步學習:

      http://www.timeanddate.com/time/gmt-utc-time.html
      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Datehttps://developer.mozilla.org...
      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse
      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC
      http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15
      http://www.w3schools.com/js/js_date_formats.asp
      https://momentjs.com/timezone/docs/
      https://sequelize.readthedocs.io/en/latest/api/sequelize/
      https://github.com/mysqljs/mysql
      《MySQL 技術(shù)內(nèi)幕》

      以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。


      當前標題:javascript關(guān)于“時間”的一次探索
      文章路徑:http://ef60e0e.cn/article/jehpeh.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        华蓥市| 邵武市| 兴和县| 浦东新区| 乌鲁木齐县| 连城县| 广平县| 望江县| 济阳县| 布拖县| 德州市| 肇东市| 临安市| 南江县| 雷州市| 静乐县| 额尔古纳市| 新宁县| 紫阳县| 贡山| 桑日县| 泽州县| 乌苏市| 海阳市| 翁源县| 南雄市| 疏勒县| 渭南市| 阳山县| 乐亭县| 维西| 邓州市| 天津市| 安阳县| 甘孜县| 荣成市| 弋阳县| 肃宁县| 鲁山县| 临颍县| 碌曲县|