[已解决] Golang从SQLite3数据库中读取日期时间的方法

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

videos_table

我使用了下面的代码。我知道包含特定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

7 回复

请在 if 语句中添加打印,以确认是否真的找到了条目。

更多关于[已解决] Golang从SQLite3数据库中读取日期时间的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你的意思是: fmt.Println(rows.Next()) 在行 if rows.Next() { 之前吗?

如果是这样的话,是的,它会打印 true…

不,我的意思是在里面打印一个任意字符串。你不应该在未实际消费行数据的情况下调用 next。这会不必要地推进游标。

否则很难判断。

你能在 GitHub 上提供一个包含示例数据集的最小化项目来演示这个问题吗?

这是一个示例项目:

GitHub

GitHub

头像

Hultan/test_sqlite

通过在GitHub上创建帐户,为Hultan/test_sqlite的开发做出贡献。

我在考虑的一件事是如何将导入语句

_ "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(&timestamp)
    if err != nil {
        return nil, err
    }

    added := time.Unix(timestamp, 0)
    fmt.Println(added)

    return &added, nil
}

确保在连接字符串中正确设置了parseTime=true参数,并且使用了正确的SQLite驱动。

回到顶部