[已解决] Golang从SQLite3数据库中读取日期时间的方法
[已解决] Golang从SQLite3数据库中读取日期时间的方法 我刚开始使用Go,现在正尝试从Sqlite3数据库中读取一个日期时间字段。在这个例子中,我试图读取 added 字段。

我使用了下面的代码。我知道包含特定video_id的记录是存在的,因为如果我从同一个表读取整数或字符串字段,一切正常,但当我尝试读取日期时间字段时就不行了。每次返回的都是 0001-01-01 00:00:00 +0000 UTC,而不是该字段中实际的日期。我猜我可能犯了一个非常低级的错误,但我就是没看出来。有人知道如何处理日期和Sqlite吗?
package database
import (
"database/sql"
"fmt"
"time"
entities "github.com/hultan/softtube/softtube.entities"
)
const databasePath = "/home/per/temp/test.db"
const connectionString = "file:" + databasePath + "?parseTime=true"
const sqlStatementGetDate = "select added from Videos where video_id='wacVZa4DQ6g'"
// GetDate : Get the added field
func GetDate() (*time.Time, error) {
// Open database
db, err := sql.Open(driverName, connectionString)
if err != nil {
return nil, err
}
rows, err := db.Query(sqlStatementGetDate)
if err != nil {
return nil, err
}
defer rows.Close()
var added time.Time
if rows.Next() {
if err = rows.Scan(&added); err != nil {
panic(err)
}
}
fmt.Println(added) // Prints : 0001-01-01 00:00:00 +0000 UTC
// Return the date
return &added, nil
}
更多关于[已解决] Golang从SQLite3数据库中读取日期时间的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
请在 if 语句中添加打印,以确认是否真的找到了条目。
更多关于[已解决] Golang从SQLite3数据库中读取日期时间的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你的意思是:
fmt.Println(rows.Next())
在行
if rows.Next() {
之前吗?
如果是这样的话,是的,它会打印 true…
不,我的意思是在里面打印一个任意字符串。你不应该在未实际消费行数据的情况下调用 next。这会不必要地推进游标。
否则很难判断。
你能在 GitHub 上提供一个包含示例数据集的最小化项目来演示这个问题吗?
我在考虑的一件事是如何将导入语句
_ "github.com/mattn/go-sqlite3"
添加到代码中。如果我添加它并保存文件,这一行会被移除。我想我必须在某个地方使用它,但我不确定具体怎么做。对于代码运行(处理字符串和整数)来说,它似乎不是必需的,但难道不应该需要它吗?
忽略这个问题,显然我在另一个文件中已经有了这个导入。我猜导入在整个包或类似范围内都有效。我稍后会研究一下……
找到了问题的解决方案,我改为将日期作为字符串读取,并在离开 GetDate() 函数之前解析日期。这可能不是最佳解决方案,但至少让我可以继续处理其他问题:
// 更改 1:先将日期转换为 varchar
const sqlStatementGetDate = "select cast(added as varchar) from Videos where video_id='wacVZa4DQ6g'"
// GetDate:获取日期
func GetDate() (*time.Time, error) {
// 打开数据库
db, err := sql.Open(driverName, connectionString)
if err != nil {
return nil, err
}
rows, err := db.Query(sqlStatementGetDate)
if err != nil {
return nil, err
}
defer rows.Close()
// 更改 2:将值作为字符串读取
var added string
if rows.Next() {
if err = rows.Scan(&added); err != nil {
panic(err)
}
}
// 更改 3:解析字符串
layout := "2006-01-02T15:04:05-0700"
date, err := time.Parse(layout, added)
// 返回日期
return &date, nil
}
在Go中从SQLite读取日期时间字段时,需要正确处理SQLite的日期时间格式。SQLite默认将日期时间存储为TEXT、REAL或INTEGER格式,而Go的database/sql包需要明确知道如何解析这些值。
以下是修正后的代码示例:
package database
import (
"database/sql"
"fmt"
"time"
_ "github.com/mattn/go-sqlite3"
)
const databasePath = "/home/per/temp/test.db"
const connectionString = "file:" + databasePath + "?parseTime=true"
const sqlStatementGetDate = "select added from Videos where video_id='wacVZa4DQ6g'"
// GetDate : Get the added field
func GetDate() (*time.Time, error) {
// Open database
db, err := sql.Open("sqlite3", connectionString)
if err != nil {
return nil, err
}
defer db.Close()
// 使用自定义类型处理日期时间
var addedStr string
err = db.QueryRow(sqlStatementGetDate).Scan(&addedStr)
if err != nil {
return nil, err
}
// 解析SQLite日期时间格式
// SQLite支持多种格式:YYYY-MM-DD HH:MM:SS, YYYY-MM-DDTHH:MM:SS等
layouts := []string{
"2006-01-02 15:04:05",
"2006-01-02T15:04:05",
"2006-01-02T15:04:05Z",
time.RFC3339,
}
var added time.Time
for _, layout := range layouts {
parsed, err := time.Parse(layout, addedStr)
if err == nil {
added = parsed
break
}
}
// 如果所有格式都失败,尝试使用time.ParseInLocation
if added.IsZero() {
loc, _ := time.LoadLocation("Local")
added, _ = time.ParseInLocation("2006-01-02 15:04:05", addedStr, loc)
}
fmt.Println(added) // 现在会显示正确的日期时间
return &added, nil
}
或者,使用自定义类型扫描器更简洁地处理:
package database
import (
"database/sql"
"database/sql/driver"
"fmt"
"time"
_ "github.com/mattn/go-sqlite3"
)
// SQLiteTime 自定义时间类型
type SQLiteTime struct {
time.Time
}
// Scan 实现sql.Scanner接口
func (st *SQLiteTime) Scan(value interface{}) error {
if value == nil {
st.Time = time.Time{}
return nil
}
switch v := value.(type) {
case string:
layouts := []string{
"2006-01-02 15:04:05",
"2006-01-02T15:04:05",
"2006-01-02T15:04:05Z",
time.RFC3339,
}
for _, layout := range layouts {
t, err := time.Parse(layout, v)
if err == nil {
st.Time = t
return nil
}
}
case []byte:
return st.Scan(string(v))
case time.Time:
st.Time = v
return nil
}
return fmt.Errorf("无法解析时间: %v", value)
}
// Value 实现driver.Valuer接口
func (st SQLiteTime) Value() (driver.Value, error) {
return st.Time.Format("2006-01-02 15:04:05"), nil
}
const databasePath = "/home/per/temp/test.db"
const connectionString = "file:" + databasePath + "?parseTime=true"
const sqlStatementGetDate = "select added from Videos where video_id='wacVZa4DQ6g'"
// GetDate : Get the added field
func GetDate() (*time.Time, error) {
db, err := sql.Open("sqlite3", connectionString)
if err != nil {
return nil, err
}
defer db.Close()
var added SQLiteTime
err = db.QueryRow(sqlStatementGetDate).Scan(&added)
if err != nil {
return nil, err
}
fmt.Println(added.Time) // 显示正确的日期时间
return &added.Time, nil
}
如果数据库中的日期时间存储为UNIX时间戳(INTEGER类型),可以这样处理:
func GetDate() (*time.Time, error) {
db, err := sql.Open("sqlite3", connectionString)
if err != nil {
return nil, err
}
defer db.Close()
var timestamp int64
err = db.QueryRow(sqlStatementGetDate).Scan(×tamp)
if err != nil {
return nil, err
}
added := time.Unix(timestamp, 0)
fmt.Println(added)
return &added, nil
}
确保在连接字符串中正确设置了parseTime=true参数,并且使用了正确的SQLite驱动。


