github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/tests/time_test.go (about) 1 package tests 2 3 import ( 4 "context" 5 "fmt" 6 "reflect" 7 "testing" 8 "time" 9 10 "github.com/ncruces/go-sqlite3" 11 "github.com/ncruces/go-sqlite3/driver" 12 _ "github.com/ncruces/go-sqlite3/embed" 13 _ "github.com/ncruces/go-sqlite3/tests/testcfg" 14 ) 15 16 func TestTimeFormat_Encode(t *testing.T) { 17 t.Parallel() 18 19 reference := time.Date(2013, 10, 7, 4, 23, 19, 120_000_000, time.FixedZone("", -4*3600)) 20 21 tests := []struct { 22 fmt sqlite3.TimeFormat 23 time time.Time 24 want any 25 }{ 26 {sqlite3.TimeFormatDefault, reference, "2013-10-07T04:23:19.12-04:00"}, 27 {sqlite3.TimeFormatJulianDay, reference, 2456572.849526851851852}, 28 {sqlite3.TimeFormatUnix, reference, int64(1381134199)}, 29 {sqlite3.TimeFormatUnixFrac, reference, 1381134199.120}, 30 {sqlite3.TimeFormatUnixMilli, reference, int64(1381134199_120)}, 31 {sqlite3.TimeFormatUnixMicro, reference, int64(1381134199_120000)}, 32 {sqlite3.TimeFormatUnixNano, reference, int64(1381134199_120000000)}, 33 {sqlite3.TimeFormat7, reference, "2013-10-07T08:23:19.120"}, 34 } 35 for _, tt := range tests { 36 t.Run("", func(t *testing.T) { 37 if got := tt.fmt.Encode(tt.time); !reflect.DeepEqual(got, tt.want) { 38 t.Errorf("%q.Encode(%v) = %v, want %v", tt.fmt, tt.time, got, tt.want) 39 } 40 }) 41 } 42 } 43 44 func TestTimeFormat_Decode(t *testing.T) { 45 t.Parallel() 46 47 const offset = -4 * 3600 48 zone := time.FixedZone("", offset) 49 reference := time.Date(2013, 10, 7, 4, 23, 19, 120_000_000, zone) 50 refnodate := time.Date(2000, 01, 1, 4, 23, 19, 120_000_000, zone) 51 52 tests := []struct { 53 fmt sqlite3.TimeFormat 54 val any 55 want time.Time 56 wantDelta time.Duration 57 wantOff int 58 wantErr bool 59 }{ 60 {sqlite3.TimeFormatJulianDay, "2456572.849526851851852", reference, 0, 0, false}, 61 {sqlite3.TimeFormatJulianDay, 2456572.849526851851852, reference, time.Millisecond, 0, false}, 62 {sqlite3.TimeFormatJulianDay, int64(2456572), reference, 24 * time.Hour, 0, false}, 63 {sqlite3.TimeFormatJulianDay, false, time.Time{}, 0, 0, true}, 64 65 {sqlite3.TimeFormatUnix, "1381134199.120", reference, time.Microsecond, 0, false}, 66 {sqlite3.TimeFormatUnix, 1381134199.120, reference, time.Microsecond, 0, false}, 67 {sqlite3.TimeFormatUnix, int64(1381134199), reference, time.Second, 0, false}, 68 {sqlite3.TimeFormatUnix, "abc", time.Time{}, 0, 0, true}, 69 {sqlite3.TimeFormatUnix, false, time.Time{}, 0, 0, true}, 70 71 {sqlite3.TimeFormatUnixMilli, "1381134199120", reference, 0, 0, false}, 72 {sqlite3.TimeFormatUnixMilli, 1381134199.120e3, reference, 0, 0, false}, 73 {sqlite3.TimeFormatUnixMilli, int64(1381134199_120), reference, 0, 0, false}, 74 {sqlite3.TimeFormatUnixMilli, "abc", time.Time{}, 0, 0, true}, 75 {sqlite3.TimeFormatUnixMilli, false, time.Time{}, 0, 0, true}, 76 77 {sqlite3.TimeFormatUnixMicro, "1381134199120000", reference, 0, 0, false}, 78 {sqlite3.TimeFormatUnixMicro, 1381134199.120e6, reference, 0, 0, false}, 79 {sqlite3.TimeFormatUnixMicro, int64(1381134199_120000), reference, 0, 0, false}, 80 {sqlite3.TimeFormatUnixMicro, "abc", time.Time{}, 0, 0, true}, 81 {sqlite3.TimeFormatUnixMicro, false, time.Time{}, 0, 0, true}, 82 83 {sqlite3.TimeFormatUnixNano, "1381134199120000000", reference, 0, 0, false}, 84 {sqlite3.TimeFormatUnixNano, 1381134199.120e9, reference, 0, 0, false}, 85 {sqlite3.TimeFormatUnixNano, int64(1381134199_120000000), reference, 0, 0, false}, 86 {sqlite3.TimeFormatUnixNano, "abc", time.Time{}, 0, 0, true}, 87 {sqlite3.TimeFormatUnixNano, false, time.Time{}, 0, 0, true}, 88 89 {sqlite3.TimeFormatAuto, "2456572.849526851851852", reference, time.Millisecond, 0, false}, 90 {sqlite3.TimeFormatAuto, "2456572", reference, 24 * time.Hour, 0, false}, 91 {sqlite3.TimeFormatAuto, "1381134199.120", reference, time.Microsecond, 0, false}, 92 {sqlite3.TimeFormatAuto, "1381134199.120e3", reference, time.Microsecond, 0, false}, 93 {sqlite3.TimeFormatAuto, "1381134199.120e6", reference, time.Microsecond, 0, false}, 94 {sqlite3.TimeFormatAuto, "1381134199.120e9", reference, time.Microsecond, 0, false}, 95 {sqlite3.TimeFormatAuto, "1381134199", reference, time.Second, 0, false}, 96 {sqlite3.TimeFormatAuto, "1381134199120", reference, 0, 0, false}, 97 {sqlite3.TimeFormatAuto, "1381134199120000", reference, 0, 0, false}, 98 {sqlite3.TimeFormatAuto, "1381134199120000000", reference, 0, 0, false}, 99 {sqlite3.TimeFormatAuto, "2013-10-07 04:23:19.12-04:00", reference, 0, offset, false}, 100 {sqlite3.TimeFormatAuto, "04:23:19.12-04:00", refnodate, 0, offset, false}, 101 {sqlite3.TimeFormatAuto, "abc", time.Time{}, 0, 0, true}, 102 {sqlite3.TimeFormatAuto, false, time.Time{}, 0, 0, true}, 103 104 {sqlite3.TimeFormat3, "2013-10-07 04:23:19.12-04:00", reference, 0, offset, false}, 105 {sqlite3.TimeFormat3, "2013-10-07 08:23:19.12", reference, 0, 0, false}, 106 {sqlite3.TimeFormat9, "04:23:19.12-04:00", refnodate, 0, offset, false}, 107 {sqlite3.TimeFormat9, "08:23:19.12", refnodate, 0, 0, false}, 108 {sqlite3.TimeFormat3, false, time.Time{}, 0, 0, true}, 109 {sqlite3.TimeFormat9, false, time.Time{}, 0, 0, true}, 110 111 {sqlite3.TimeFormatDefault, "2013-10-07T04:23:19.12-04:00", reference, 0, offset, false}, 112 {sqlite3.TimeFormatDefault, "2013-10-07T08:23:19.12Z", reference, 0, 0, false}, 113 {sqlite3.TimeFormatDefault, false, time.Time{}, 0, 0, true}, 114 } 115 116 for _, tt := range tests { 117 t.Run("", func(t *testing.T) { 118 got, err := tt.fmt.Decode(tt.val) 119 if (err != nil) != tt.wantErr { 120 t.Errorf("%q.Decode(%v) error = %v, wantErr %v", tt.fmt, tt.val, err, tt.wantErr) 121 return 122 } 123 if got.Sub(tt.want).Abs() > tt.wantDelta { 124 t.Errorf("%q.Decode(%v) = %v, want %v", tt.fmt, tt.val, got, tt.want) 125 } 126 if _, off := got.Zone(); off != tt.wantOff { 127 t.Errorf("%q.Decode(%v) = %v, want %v", tt.fmt, tt.val, off, tt.wantOff) 128 } 129 }) 130 } 131 } 132 133 func TestTimeFormat_Scanner(t *testing.T) { 134 t.Parallel() 135 136 ctx, cancel := context.WithCancel(context.Background()) 137 defer cancel() 138 139 db, err := driver.Open(":memory:", nil) 140 if err != nil { 141 t.Fatal(err) 142 } 143 defer db.Close() 144 145 conn, err := db.Conn(ctx) 146 if err != nil { 147 t.Fatal(err) 148 } 149 defer conn.Close() 150 151 _, err = conn.ExecContext(ctx, `CREATE TABLE test (col)`) 152 if err != nil { 153 t.Fatal(err) 154 } 155 156 reference := time.Date(2013, 10, 7, 4, 23, 19, 120_000_000, time.FixedZone("", -4*3600)) 157 158 _, err = conn.ExecContext(ctx, `INSERT INTO test VALUES (?)`, sqlite3.TimeFormat7TZ.Encode(reference)) 159 if err != nil { 160 t.Fatal(err) 161 } 162 163 var got time.Time 164 err = conn.QueryRowContext(ctx, "SELECT * FROM test").Scan(sqlite3.TimeFormatAuto.Scanner(&got)) 165 if err != nil { 166 t.Fatal(err) 167 } 168 if !got.Equal(reference) { 169 t.Errorf("got %v, want %v", got, reference) 170 } 171 } 172 173 func TestDB_timeCollation(t *testing.T) { 174 t.Parallel() 175 176 db, err := sqlite3.Open(":memory:") 177 if err != nil { 178 t.Fatal(err) 179 } 180 defer db.Close() 181 182 err = db.Exec(`CREATE TABLE times (tstamp COLLATE TIME)`) 183 if err != nil { 184 t.Fatal(err) 185 } 186 187 stmt, _, err := db.Prepare(`INSERT INTO times VALUES (?), (?), (?)`) 188 if err != nil { 189 t.Fatal(err) 190 } 191 defer stmt.Close() 192 193 stmt.BindTime(1, time.Unix(0, 0).UTC(), sqlite3.TimeFormatDefault) 194 stmt.BindTime(2, time.Unix(0, -1).UTC(), sqlite3.TimeFormatDefault) 195 stmt.BindTime(3, time.Unix(0, +1).UTC(), sqlite3.TimeFormatDefault) 196 stmt.Step() 197 198 err = stmt.Close() 199 if err != nil { 200 t.Fatal(err) 201 } 202 203 stmt, _, err = db.Prepare(`SELECT tstamp FROM times ORDER BY tstamp`) 204 if err != nil { 205 t.Fatal(err) 206 } 207 208 var t0 time.Time 209 for stmt.Step() { 210 t1 := stmt.ColumnTime(0, sqlite3.TimeFormatAuto) 211 if t0.After(t1) { 212 t.Errorf("got %v after %v", t0, t1) 213 } 214 t0 = t1 215 } 216 err = stmt.Close() 217 if err != nil { 218 t.Fatal(err) 219 } 220 } 221 222 func TestDB_isoWeek(t *testing.T) { 223 t.Parallel() 224 225 db, err := sqlite3.Open(":memory:") 226 if err != nil { 227 t.Fatal(err) 228 } 229 defer db.Close() 230 231 stmt, _, err := db.Prepare(`SELECT strftime('%G-W%V-%u', ?)`) 232 if err != nil { 233 t.Fatal(err) 234 } 235 defer stmt.Close() 236 237 tend := time.Date(2500, 1, 1, 0, 0, 0, 0, time.UTC) 238 tstart := time.Date(1500, 1, 1, 12, 0, 0, 0, time.UTC) 239 for tm := tstart; tm.Before(tend); tm = tm.AddDate(0, 0, 1) { 240 stmt.BindTime(1, tm, sqlite3.TimeFormatDefault) 241 if stmt.Step() { 242 y, w := tm.ISOWeek() 243 d := tm.Weekday() 244 if d == 0 { 245 d = 7 246 } 247 want := fmt.Sprintf("%04d-W%02d-%d", y, w, d) 248 if got := stmt.ColumnText(0); got != want { 249 t.Errorf("got %q, want %q (%v)", got, want, tm) 250 } 251 } 252 stmt.Reset() 253 } 254 }