1package pgtype_test
2
3import (
4	"reflect"
5	"testing"
6	"time"
7
8	"github.com/jackc/pgtype"
9	"github.com/jackc/pgtype/testutil"
10)
11
12func TestTimeTranscode(t *testing.T) {
13	testutil.TestSuccessfulTranscode(t, "time", []interface{}{
14		&pgtype.Time{Microseconds: 0, Status: pgtype.Present},
15		&pgtype.Time{Microseconds: 1, Status: pgtype.Present},
16		&pgtype.Time{Microseconds: 86399999999, Status: pgtype.Present},
17		&pgtype.Time{Status: pgtype.Null},
18	})
19}
20
21// Test for transcoding 24:00:00 separately as github.com/lib/pq doesn't seem to support it.
22func TestTimeTranscode24HH(t *testing.T) {
23	pgTypeName := "time"
24	values := []interface{}{
25		&pgtype.Time{Microseconds: 86400000000, Status: pgtype.Present},
26	}
27
28	eqFunc := func(a, b interface{}) bool {
29		return reflect.DeepEqual(a, b)
30	}
31
32	testutil.TestPgxSuccessfulTranscodeEqFunc(t, pgTypeName, values, eqFunc)
33	testutil.TestDatabaseSQLSuccessfulTranscodeEqFunc(t, "github.com/jackc/pgx/stdlib", pgTypeName, values, eqFunc)
34}
35
36func TestTimeSet(t *testing.T) {
37	type _time time.Time
38
39	successfulTests := []struct {
40		source interface{}
41		result pgtype.Time
42	}{
43		{source: time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC), result: pgtype.Time{Microseconds: 0, Status: pgtype.Present}},
44		{source: time.Date(1900, 1, 1, 1, 0, 0, 0, time.UTC), result: pgtype.Time{Microseconds: 3600000000, Status: pgtype.Present}},
45		{source: time.Date(1900, 1, 1, 0, 1, 0, 0, time.UTC), result: pgtype.Time{Microseconds: 60000000, Status: pgtype.Present}},
46		{source: time.Date(1900, 1, 1, 0, 0, 1, 0, time.UTC), result: pgtype.Time{Microseconds: 1000000, Status: pgtype.Present}},
47		{source: time.Date(1970, 1, 1, 0, 0, 0, 1, time.UTC), result: pgtype.Time{Microseconds: 0, Status: pgtype.Present}},
48		{source: time.Date(1970, 1, 1, 0, 0, 0, 1000, time.UTC), result: pgtype.Time{Microseconds: 1, Status: pgtype.Present}},
49		{source: time.Date(1999, 12, 31, 23, 59, 59, 999999999, time.UTC), result: pgtype.Time{Microseconds: 86399999999, Status: pgtype.Present}},
50		{source: time.Date(2015, 1, 1, 0, 0, 0, 2000, time.Local), result: pgtype.Time{Microseconds: 2, Status: pgtype.Present}},
51		{source: func(t time.Time) *time.Time { return &t }(time.Date(2015, 1, 1, 0, 0, 0, 2000, time.Local)), result: pgtype.Time{Microseconds: 2, Status: pgtype.Present}},
52		{source: nil, result: pgtype.Time{Status: pgtype.Null}},
53		{source: (*time.Time)(nil), result: pgtype.Time{Status: pgtype.Null}},
54		{source: _time(time.Date(1970, 1, 1, 0, 0, 0, 3000, time.UTC)), result: pgtype.Time{Microseconds: 3, Status: pgtype.Present}},
55	}
56
57	for i, tt := range successfulTests {
58		var r pgtype.Time
59		err := r.Set(tt.source)
60		if err != nil {
61			t.Errorf("%d: %v", i, err)
62		}
63
64		if r != tt.result {
65			t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r)
66		}
67	}
68}
69
70func TestTimeAssignTo(t *testing.T) {
71	var tim time.Time
72	var ptim *time.Time
73
74	simpleTests := []struct {
75		src      pgtype.Time
76		dst      interface{}
77		expected interface{}
78	}{
79		{src: pgtype.Time{Microseconds: 0, Status: pgtype.Present}, dst: &tim, expected: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)},
80		{src: pgtype.Time{Microseconds: 3600000000, Status: pgtype.Present}, dst: &tim, expected: time.Date(2000, 1, 1, 1, 0, 0, 0, time.UTC)},
81		{src: pgtype.Time{Microseconds: 60000000, Status: pgtype.Present}, dst: &tim, expected: time.Date(2000, 1, 1, 0, 1, 0, 0, time.UTC)},
82		{src: pgtype.Time{Microseconds: 1000000, Status: pgtype.Present}, dst: &tim, expected: time.Date(2000, 1, 1, 0, 0, 1, 0, time.UTC)},
83		{src: pgtype.Time{Microseconds: 1, Status: pgtype.Present}, dst: &tim, expected: time.Date(2000, 1, 1, 0, 0, 0, 1000, time.UTC)},
84		{src: pgtype.Time{Microseconds: 86399999999, Status: pgtype.Present}, dst: &tim, expected: time.Date(2000, 1, 1, 23, 59, 59, 999999000, time.UTC)},
85		{src: pgtype.Time{Microseconds: 0, Status: pgtype.Null}, dst: &ptim, expected: ((*time.Time)(nil))},
86	}
87
88	for i, tt := range simpleTests {
89		err := tt.src.AssignTo(tt.dst)
90		if err != nil {
91			t.Errorf("%d: %v", i, err)
92		}
93
94		if dst := reflect.ValueOf(tt.dst).Elem().Interface(); dst != tt.expected {
95			t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
96		}
97	}
98
99	pointerAllocTests := []struct {
100		src      pgtype.Time
101		dst      interface{}
102		expected interface{}
103	}{
104		{src: pgtype.Time{Microseconds: 0, Status: pgtype.Present}, dst: &ptim, expected: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)},
105	}
106
107	for i, tt := range pointerAllocTests {
108		err := tt.src.AssignTo(tt.dst)
109		if err != nil {
110			t.Errorf("%d: %v", i, err)
111		}
112
113		if dst := reflect.ValueOf(tt.dst).Elem().Elem().Interface(); dst != tt.expected {
114			t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
115		}
116	}
117
118	errorTests := []struct {
119		src pgtype.Time
120		dst interface{}
121	}{
122		{src: pgtype.Time{Microseconds: 86400000000, Status: pgtype.Present}, dst: &tim},
123	}
124
125	for i, tt := range errorTests {
126		err := tt.src.AssignTo(tt.dst)
127		if err == nil {
128			t.Errorf("%d: expected error but none was returned (%v -> %v)", i, tt.src, tt.dst)
129		}
130	}
131}
132