Skip to content

Commit a755cdc

Browse files
committed
Merge branch 'master' of https://github.com/mattn/go-sqlite3
2 parents 59f20de + 80ee1ba commit a755cdc

File tree

3 files changed

+38
-14
lines changed

3 files changed

+38
-14
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ This package can be installed with the go get command:
1616

1717
go get github.com/mattn/go-sqlite3
1818

19+
_go-sqlite3_ is *cgo* package.
20+
If you want to build your app using go-sqlite3, you need gcc.
21+
However, if you install _go-sqlite3_ with `go install github.com/mattn/go-sqlite`, you don't need gcc to build your app anymore.
22+
1923
Documentation
2024
-------------
2125

sqlite3.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,17 @@ import (
9999
// into the database. When parsing a string from a timestamp or
100100
// datetime column, the formats are tried in order.
101101
var SQLiteTimestampFormats = []string{
102+
// By default, store timestamps with whatever timezone they come with.
103+
// When parsed, they will be returned with the same timezone.
104+
"2006-01-02 15:04:05.999999999-07:00",
105+
"2006-01-02T15:04:05.999999999-07:00",
102106
"2006-01-02 15:04:05.999999999",
103107
"2006-01-02T15:04:05.999999999",
104108
"2006-01-02 15:04:05",
105109
"2006-01-02T15:04:05",
106110
"2006-01-02 15:04",
107111
"2006-01-02T15:04",
108112
"2006-01-02",
109-
"2006-01-02 15:04:05-07:00",
110113
}
111114

112115
func init() {
@@ -803,7 +806,7 @@ func (s *SQLiteStmt) bind(args []driver.Value) error {
803806
}
804807
rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(p), C.int(len(v)))
805808
case time.Time:
806-
b := []byte(v.UTC().Format(SQLiteTimestampFormats[0]))
809+
b := []byte(v.Format(SQLiteTimestampFormats[0]))
807810
rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b)))
808811
}
809812
if rv != C.SQLITE_OK {
@@ -902,18 +905,15 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
902905
val := int64(C.sqlite3_column_int64(rc.s.s, C.int(i)))
903906
switch rc.decltype[i] {
904907
case "timestamp", "datetime", "date":
905-
unixTimestamp := strconv.FormatInt(val, 10)
906908
var t time.Time
907-
if len(unixTimestamp) == 13 {
908-
duration, err := time.ParseDuration(unixTimestamp + "ms")
909-
if err != nil {
910-
return fmt.Errorf("error parsing %s value %d, %s", rc.decltype[i], val, err)
911-
}
912-
epoch := time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)
913-
t = epoch.Add(duration)
909+
// Assume a millisecond unix timestamp if it's 13 digits -- too
910+
// large to be a reasonable timestamp in seconds.
911+
if val > 1e12 || val < -1e12 {
912+
val *= int64(time.Millisecond) // convert ms to nsec
914913
} else {
915-
t = time.Unix(val, 0)
914+
val *= int64(time.Second) // convert sec to nsec
916915
}
916+
t = time.Unix(0, val).UTC()
917917
if rc.s.c.loc != nil {
918918
t = t.In(rc.s.c.loc)
919919
}

sqlite3_test.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,8 @@ func TestBooleanRoundtrip(t *testing.T) {
347347
}
348348
}
349349

350+
func timezone(t time.Time) string { return t.Format("-07:00") }
351+
350352
func TestTimestamp(t *testing.T) {
351353
tempFilename := TempFilename(t)
352354
db, err := sql.Open("sqlite3", tempFilename)
@@ -365,30 +367,40 @@ func TestTimestamp(t *testing.T) {
365367
timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC)
366368
timestamp2 := time.Date(2006, time.January, 2, 15, 4, 5, 123456789, time.UTC)
367369
timestamp3 := time.Date(2012, time.November, 4, 0, 0, 0, 0, time.UTC)
370+
tzTest := time.FixedZone("TEST", -9*3600-13*60)
368371
tests := []struct {
369372
value interface{}
370373
expected time.Time
371374
}{
372375
{"nonsense", time.Time{}},
373376
{"0000-00-00 00:00:00", time.Time{}},
374377
{timestamp1, timestamp1},
375-
{timestamp1.Unix(), timestamp1},
376-
{timestamp1.UnixNano() / int64(time.Millisecond), timestamp1},
377-
{timestamp1.In(time.FixedZone("TEST", -7*3600)), timestamp1},
378+
{timestamp2.Unix(), timestamp2.Truncate(time.Second)},
379+
{timestamp2.UnixNano() / int64(time.Millisecond), timestamp2.Truncate(time.Millisecond)},
380+
{timestamp1.In(tzTest), timestamp1.In(tzTest)},
378381
{timestamp1.Format("2006-01-02 15:04:05.000"), timestamp1},
379382
{timestamp1.Format("2006-01-02T15:04:05.000"), timestamp1},
380383
{timestamp1.Format("2006-01-02 15:04:05"), timestamp1},
381384
{timestamp1.Format("2006-01-02T15:04:05"), timestamp1},
382385
{timestamp2, timestamp2},
383386
{"2006-01-02 15:04:05.123456789", timestamp2},
384387
{"2006-01-02T15:04:05.123456789", timestamp2},
388+
{"2006-01-02T05:51:05.123456789-09:13", timestamp2.In(tzTest)},
385389
{"2012-11-04", timestamp3},
386390
{"2012-11-04 00:00", timestamp3},
387391
{"2012-11-04 00:00:00", timestamp3},
388392
{"2012-11-04 00:00:00.000", timestamp3},
389393
{"2012-11-04T00:00", timestamp3},
390394
{"2012-11-04T00:00:00", timestamp3},
391395
{"2012-11-04T00:00:00.000", timestamp3},
396+
{"2006-01-02T15:04:05.123456789Z", timestamp2},
397+
{"2012-11-04Z", timestamp3},
398+
{"2012-11-04 00:00Z", timestamp3},
399+
{"2012-11-04 00:00:00Z", timestamp3},
400+
{"2012-11-04 00:00:00.000Z", timestamp3},
401+
{"2012-11-04T00:00Z", timestamp3},
402+
{"2012-11-04T00:00:00Z", timestamp3},
403+
{"2012-11-04T00:00:00.000Z", timestamp3},
392404
}
393405
for i := range tests {
394406
_, err = db.Exec("INSERT INTO foo(id, ts, dt) VALUES(?, ?, ?)", i, tests[i].value, tests[i].value)
@@ -423,6 +435,14 @@ func TestTimestamp(t *testing.T) {
423435
if !tests[id].expected.Equal(dt) {
424436
t.Errorf("Datetime value for id %v (%v) should be %v, not %v", id, tests[id].value, tests[id].expected, dt)
425437
}
438+
if timezone(tests[id].expected) != timezone(ts) {
439+
t.Errorf("Timezone for id %v (%v) should be %v, not %v", id, tests[id].value,
440+
timezone(tests[id].expected), timezone(ts))
441+
}
442+
if timezone(tests[id].expected) != timezone(dt) {
443+
t.Errorf("Timezone for id %v (%v) should be %v, not %v", id, tests[id].value,
444+
timezone(tests[id].expected), timezone(dt))
445+
}
426446
}
427447

428448
if seen != len(tests) {

0 commit comments

Comments
 (0)