forked from mirror/go-sqlcipher
Support time values with nanosecond precision
This commit is contained in:
parent
f65db67ea3
commit
ce139f706b
25
sqlite3.go
25
sqlite3.go
|
@ -40,9 +40,15 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const SQLiteTimestampFormat = "2006-01-02 15:04:05"
|
// Timestamp formats understood by both this module and SQLite.
|
||||||
const SQLiteDateFormat = "2006-01-02"
|
// The first format in the slice will be used when saving time values
|
||||||
const SQLiteDatetimeFormat = "2006-01-02 15:04:05.000"
|
// into the database. When parsing a string from a timestamp or
|
||||||
|
// datetime column, the formats are tried in order.
|
||||||
|
var SQLiteTimestampFormats = []string{
|
||||||
|
"2006-01-02 15:04:05.999999999",
|
||||||
|
"2006-01-02 15:04:05",
|
||||||
|
"2006-01-02",
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
sql.Register("sqlite3", &SQLiteDriver{})
|
sql.Register("sqlite3", &SQLiteDriver{})
|
||||||
|
@ -213,7 +219,7 @@ func (s *SQLiteStmt) bind(args []driver.Value) error {
|
||||||
}
|
}
|
||||||
rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(p), C.int(len(v)))
|
rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(p), C.int(len(v)))
|
||||||
case time.Time:
|
case time.Time:
|
||||||
b := []byte(v.UTC().Format(SQLiteTimestampFormat))
|
b := []byte(v.UTC().Format(SQLiteTimestampFormats[0]))
|
||||||
rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b)))
|
rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b)))
|
||||||
}
|
}
|
||||||
if rv != C.SQLITE_OK {
|
if rv != C.SQLITE_OK {
|
||||||
|
@ -327,19 +333,14 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||||
|
|
||||||
switch rc.decltype[i] {
|
switch rc.decltype[i] {
|
||||||
case "timestamp", "datetime":
|
case "timestamp", "datetime":
|
||||||
for {
|
for _, format := range SQLiteTimestampFormats {
|
||||||
if dest[i], err = time.Parse(SQLiteTimestampFormat, s); err == nil {
|
if dest[i], err = time.Parse(format, s); err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if dest[i], err = time.Parse(SQLiteDateFormat, s); err == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if dest[i], err = time.Parse(SQLiteDatetimeFormat, s); err == nil {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
// The column is a time value, so return the zero time on parse failure.
|
// The column is a time value, so return the zero time on parse failure.
|
||||||
dest[i] = time.Time{}
|
dest[i] = time.Time{}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
dest[i] = s
|
dest[i] = s
|
||||||
|
|
|
@ -251,7 +251,7 @@ func TestTimestamp(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC)
|
timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC)
|
||||||
timestamp2 := time.Date(2006, time.January, 2, 15, 4, 5, 3000000, time.UTC)
|
timestamp2 := time.Date(2006, time.January, 2, 15, 4, 5, 123456789, time.UTC)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
value interface{}
|
value interface{}
|
||||||
expected time.Time
|
expected time.Time
|
||||||
|
@ -263,7 +263,7 @@ func TestTimestamp(t *testing.T) {
|
||||||
{timestamp1.In(time.FixedZone("TEST", -7*3600)), timestamp1},
|
{timestamp1.In(time.FixedZone("TEST", -7*3600)), timestamp1},
|
||||||
{"2012-11-04", time.Date(2012, time.November, 4, 0, 0, 0, 0, time.UTC)},
|
{"2012-11-04", time.Date(2012, time.November, 4, 0, 0, 0, 0, time.UTC)},
|
||||||
{timestamp2, timestamp2},
|
{timestamp2, timestamp2},
|
||||||
{"2006-01-02 15:04:05.003", timestamp2},
|
{"2006-01-02 15:04:05.123456789", timestamp2},
|
||||||
}
|
}
|
||||||
for i := range tests {
|
for i := range tests {
|
||||||
_, err = db.Exec("INSERT INTO foo(id, ts, dt) VALUES(?, ?, ?)", i, tests[i].value, tests[i].value)
|
_, err = db.Exec("INSERT INTO foo(id, ts, dt) VALUES(?, ?, ?)", i, tests[i].value, tests[i].value)
|
||||||
|
|
Loading…
Reference in New Issue