Go读取MySQL Date类型的避坑指南

 更新时间:2025年12月01日 09:45:23   作者:凉凉的知识库  
文章讨论了在Go中读取MySQL中的DATETIME和DATE类型数据时遇到的格式转换问题,并解释了parseTime参数的作用,并展示了在不同情况下,Go字段类型定义对读取到的时间字符串格式的影响,需要的朋友可以参考下

一不小心就踩坑

先举一个实际的:

我们先创建一个表,并插入一行数据。注意表中两个字段一个是DATETIME类型,一个是DATE类型的

CREATE TABLE `t_test` (
  `id` int NOT NULL AUTO_INCREMENT,
  `f_one` datetime DEFAULT NULL,
  `f_two` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

INSERT INTO `test`.`t_test` (`f_one`, `f_two`) VALUES ('2025-11-29 10:25:05', '2025-11-29');

当我们查询数据可以看到和插入的数据一致

  • f_one datetime展示为2025-11-29 10:25:05
  • f_two date展示为2025-11-29
mysql> select * from t_test where id = 1;
+----+---------------------+------------+
| id | f_one               | f_two      |
+----+---------------------+------------+
|  1 | 2025-11-29 10:25:05 | 2025-11-29 |
+----+---------------------+------------+
1 row in set (0.003 sec)

现在使用Go来读取上面的数据

package main

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type Test struct {
	ID   int    `gorm:"column:id;primaryKey"`
	FOne string `gorm:"column:f_one"` // 注意这里我们定义成了string类型
	FTwo string `gorm:"column:f_two"` // 注意这里我们定义成了string类型
}

func (t Test) TableName() string {
	return "t_test"
}

func TestRead(t *testing.T) {
	// 数据库连接配置
	dsn := "root:root@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"

	db, err := gorm.Open(mysql.Open(dsn))
	assert.Nil(t, err)

	var result Test
	err = db.Where("id = ?", 1).Find(&result).Error
	assert.Nil(t, err)

	assert.Equal(t, "2025-11-29 10:25:05", result.FOne)
	assert.Equal(t, "2025-11-29", result.FTwo)
}

可以在这里暂停思考下,上面的单元测试是否会通过。下面是实际执行的结果。

Error: Not equal: 
       expected: "2025-11-29 10:25:05"
       actual  : "2025-11-29T10:25:05+08:00"

Error: Not equal: 
       expected: "2025-11-29"
       actual  : "2025-11-29T00:00:00+08:00"

结果非常Amazing啊

f_one我们期望的是2025-11-29 10:25:05,实际Go读取到是 2025-11-29T10:25:05+08:00,额外添加了T分隔符和时区信息

f_two我们期望的是2025-11-29, 实际Go读取到是 2025-11-29T00:00:00+08:00,不仅额外添加了T分隔符和时区信息,还添加了时分秒

你看,如果你对Go读取到字符串按MySQL时间格式处理,可能一不注意就踩坑里了。

问题出在哪里?

你可能已经注意到了,Go结构体的定义使用了string类型,但不知道你有没有注意到数据库连接中的另外一个参数parseTime=True

parseTime是什么?parseTime是 Go 的 MySQL 驱动 (github.com/go-sql-driver/mysql) 中的一个连接参数,控制是否将 MySQL 时间类型自动转换为 Go 的 time.Time对象:

  • parseTime=false 禁用自动转换(默认值)
  • parseTime=true 启用自动转换

当Go的定义为string类型时,问题就出在自动转换上

parseTime=false时, 转化方式为DATETIME/DATE(MySQL)->string(Go) ,不会出现上面的问题,Go中读取到的字符串和MySQL的格式一致:2025-11-29 10:25:052025-11-29

parseTime=true时,Go的MySQL驱动首先尝试将 MySQL的 DATETIME/DATE(MySQL)解析为 Go 的 time.Time对象,当发现目标字段是 string类型时,驱动会自动调用 time.TimeString()方法进行转换,time.String()按照RFC3339格式输出,与MySQL中展示的格式不一致,就形成了上文的效果。也就是说

# 开启parseTime=true且Go类型定义为string时

`DATETIME(MySQL)` 
      |
      v
`time.Time`(golang) 
      |
      | ->这里的`time.time`到`string`这一步出现了转化差异
      v
`string(golang)`          

总结

下面总结不同parseTime和Go类型定义的情况下,Go程序读取到的值。

Go字段类型定义parseTime=falseparseTime=true
stringYYYY-MM-DD[ HH:MM:SS[.fraction]]
即:
DATE->YYYY-MM-DD
DATETIME->YYYY-MM-DD HH:MM:SS
DATETIME(3)->YYYY-MM-DD HH:MM:SS.sss
DATETIME(6)->YYYY-MM-DD HH:MM:SS.ssssss
零值->0000-00-00[ 00:00:00]

此时Go中时间字符串的格式和MySQL默认格式一致
RFC3339
YYYY-MM-DDTHH:MM:SS±HH:MM

此时Go中时间字符串的格式和MySQL默认格式不一致!!
time.Time报错 (类型不兼容)Gotime.Time实例
如果零值也是零值time.Time实例

由此也引出了比较合理的使用姿势

  • 如果启用了parseTime=true,我建议你在Go中定义成time.Time类型
type Test struct {
	ID   int       `gorm:"column:id;primaryKey"`
	FOne time.Time `gorm:"column:f_one"`
	FTwo time.Time `gorm:"column:f_two"`
}
  • 如果没有启用,即parseTime=false,在Go只能定义成string
type Test struct {
	ID   int    `gorm:"column:id;primaryKey"`
	FOne string `gorm:"column:f_one"`
	FTwo string `gorm:"column:f_two"`
}

到此这篇关于Go读取MySQL Date类型的避坑指南的文章就介绍到这了,更多相关Go读取MySQL Date类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用Golang创建单独的WebSocket会话

    使用Golang创建单独的WebSocket会话

    WebSocket是一种在Web开发中非常常见的通信协议,它提供了双向、持久的连接,适用于实时数据传输和实时通信场景,本文将介绍如何使用 Golang 创建单独的 WebSocket 会话,包括建立连接、消息传递和关闭连接等操作,需要的朋友可以参考下
    2023-12-12
  • Go语言LeetCode题解706设计哈希映射

    Go语言LeetCode题解706设计哈希映射

    这篇文章主要为大家介绍了Go语言LeetCode题解706设计哈希映射示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • 在Mac中搭建go语言开发环境的操作步骤

    在Mac中搭建go语言开发环境的操作步骤

    go语言在开发效率和运行效率中的优势让很多人青睐,所以有倾向打算转向go语言的开发。下面介绍在Mac中golang的开发环境配置。有需要的可以参考借鉴。
    2016-08-08
  • 详解Go语言中的内存对齐

    详解Go语言中的内存对齐

    前面我们学习了Go语言空结构体详解,最近又在看unsafe包的知识,在查阅相关资料时不免会看到内存对齐相关的内容。虽然不会,但可以学呀,那么这篇文章,我们就一起来看下什么是内存对齐吧
    2022-10-10
  • 手把手带你走进Go语言之循环语句

    手把手带你走进Go语言之循环语句

    在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句。一组被重复执行的语句称之为循环体,能否继续重复,决定循环的终止条件,本文给大家介绍的非常详细,跟着小编往下看吧
    2021-09-09
  • golang bufio包中Write方法的深入讲解

    golang bufio包中Write方法的深入讲解

    这篇文章主要给大家介绍了关于golang bufio包中Write方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-02-02
  • GO语言文件的创建与打开实例分析

    GO语言文件的创建与打开实例分析

    这篇文章主要介绍了GO语言文件的创建与打开的具体用法,实例分析了GO语言文件创建与打开操作中所涉及的函数具体用法,具有一定的参考借鉴价值,需要的朋友可以参考下
    2014-12-12
  • 在golang xorm中使用postgresql的json,array类型的操作

    在golang xorm中使用postgresql的json,array类型的操作

    这篇文章主要介绍了在golang xorm中使用postgresql的json,array类型的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • GoLang中Module的基本使用方法

    GoLang中Module的基本使用方法

    Go module是从Go 1.11版本才引入的新功能,下面这篇文章主要给大家介绍了关于GoLang中Module的基本使用方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • 浅谈go语言内存逃逸现象

    浅谈go语言内存逃逸现象

    本文主要介绍了浅谈go语言内存逃逸现象,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-10-10

最新评论