Skip to content

Commit 0f6bd14

Browse files
authored
Merge pull request #1691 from ydb-platform/date32
* Supported wide `Date32`, `Datetime64` and `Timestamp64` types
2 parents 09f3ef5 + 4f85add commit 0f6bd14

File tree

7 files changed

+344
-2
lines changed

7 files changed

+344
-2
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
* Supported wide `Date32`, `Datetime64` and `Timestamp64` types
2+
13
## v3.101.4
24
* Switched internal type of result `ydb.Driver.Query()` from `*internal/query.Client` to `query.Client` interface
35

internal/params/parameters.go

+7
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,13 @@ func (p *Parameter) Date(v time.Time) Builder {
280280
return p.parent
281281
}
282282

283+
func (p *Parameter) Date32(v time.Time) Builder {
284+
p.value = value.Date32ValueFromTime(v)
285+
p.parent.params = append(p.parent.params, p)
286+
287+
return p.parent
288+
}
289+
283290
func (p *Parameter) Datetime(v time.Time) Builder {
284291
p.value = value.DatetimeValueFromTime(v)
285292
p.parent.params = append(p.parent.params, p)

internal/types/types.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,16 @@ func primitiveTypeFromYDB(t Ydb.Type_PrimitiveTypeId) Type {
110110
return Double
111111
case Ydb.Type_DATE:
112112
return Date
113+
case Ydb.Type_DATE32:
114+
return Date32
113115
case Ydb.Type_DATETIME:
114116
return Datetime
117+
case Ydb.Type_DATETIME64:
118+
return Datetime64
115119
case Ydb.Type_TIMESTAMP:
116120
return Timestamp
121+
case Ydb.Type_TIMESTAMP64:
122+
return Timestamp64
117123
case Ydb.Type_INTERVAL:
118124
return Interval
119125
case Ydb.Type_TZ_DATE:
@@ -137,7 +143,7 @@ func primitiveTypeFromYDB(t Ydb.Type_PrimitiveTypeId) Type {
137143
case Ydb.Type_DYNUMBER:
138144
return DyNumber
139145
default:
140-
panic("ydb: unexpected type")
146+
panic(fmt.Sprintf("ydb: unexpected type %v", t))
141147
}
142148
}
143149

@@ -527,8 +533,11 @@ const (
527533
Float
528534
Double
529535
Date
536+
Date32
530537
Datetime
538+
Datetime64
531539
Timestamp
540+
Timestamp64
532541
Interval
533542
TzDate
534543
TzDatetime
@@ -555,8 +564,11 @@ var primitive = [...]*Ydb.Type{
555564
Float: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_FLOAT}},
556565
Double: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DOUBLE}},
557566
Date: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE}},
567+
Date32: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE32}},
558568
Datetime: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME}},
569+
Datetime64: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME64}},
559570
Timestamp: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP}},
571+
Timestamp64: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP64}},
560572
Interval: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL}},
561573
TzDate: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATE}},
562574
TzDatetime: {Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATETIME}},
@@ -584,8 +596,11 @@ var primitiveString = [...]string{
584596
Float: "Float",
585597
Double: "Double",
586598
Date: "Date",
599+
Date32: "Date32",
587600
Datetime: "Datetime",
601+
Datetime64: "Datetime64",
588602
Timestamp: "Timestamp",
603+
Timestamp64: "Timestamp64",
589604
Interval: "Interval",
590605
TzDate: "TzDate",
591606
TzDatetime: "TzDatetime",

internal/value/time.go

+20
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,23 @@ func DateToTime(n uint32) time.Time {
4646
return time.Unix(0, 0).Add(time.Hour * 24 * time.Duration(n))
4747
}
4848

49+
// Date32ToTime up to 11761191-01-20 00:00:00 +0000 UTC.
50+
func Date32ToTime(days int32) time.Time {
51+
return time.Unix(int64(days)*24*60*60, 0)
52+
}
53+
4954
// DatetimeToTime converts seconds to time.Time
5055
// Up to 2106-02-07 06:28:15 +0000 UTC.
5156
func DatetimeToTime(n uint32) time.Time {
5257
return time.Unix(int64(n), 0)
5358
}
5459

60+
// Datetime64ToTime converts seconds to time.Time
61+
// Up to 2106-02-07 06:28:15 +0000 UTC.
62+
func Datetime64ToTime(n int64) time.Time {
63+
return time.Unix(n, 0)
64+
}
65+
5566
// TimestampToTime converts given microseconds to time.Time
5667
// Up to 586524-01-19 08:01:49.000551615 +0000 UTC.
5768
func TimestampToTime(n uint64) time.Time {
@@ -61,6 +72,15 @@ func TimestampToTime(n uint64) time.Time {
6172
return time.Unix(int64(sec), int64(nsec))
6273
}
6374

75+
// Timestamp64ToTime converts given microseconds to time.Time
76+
// Up to 586524-01-19 08:01:49.000551615 +0000 UTC.
77+
func Timestamp64ToTime(n int64) time.Time {
78+
sec := n / microsecondsPerSecond
79+
nsec := (n - (sec * microsecondsPerSecond)) * nanosecondsPerMicrosecond
80+
81+
return time.Unix(sec, nsec)
82+
}
83+
6484
func TzDateToTime(s string) (t time.Time, err error) {
6585
ss := strings.Split(s, ",")
6686
if len(ss) != 2 { //nolint:gomnd

internal/value/value.go

+172-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func nullValueFromYDB(x *Ydb.Value, t types.Type) (_ Value, ok bool) {
7979
}
8080
}
8181

82-
//nolint:funlen
82+
//nolint:funlen,gocyclo
8383
func primitiveValueFromYDB(t types.Primitive, v *Ydb.Value) (Value, error) {
8484
switch t {
8585
case types.Bool:
@@ -112,15 +112,24 @@ func primitiveValueFromYDB(t types.Primitive, v *Ydb.Value) (Value, error) {
112112
case types.Date:
113113
return DateValue(v.GetUint32Value()), nil
114114

115+
case types.Date32:
116+
return Date32Value(v.GetInt32Value()), nil
117+
115118
case types.Datetime:
116119
return DatetimeValue(v.GetUint32Value()), nil
117120

121+
case types.Datetime64:
122+
return Datetime64Value(v.GetInt64Value()), nil
123+
118124
case types.Interval:
119125
return IntervalValue(v.GetInt64Value()), nil
120126

121127
case types.Timestamp:
122128
return TimestampValue(v.GetUint64Value()), nil
123129

130+
case types.Timestamp64:
131+
return Timestamp64Value(v.GetInt64Value()), nil
132+
124133
case types.Float:
125134
return FloatValue(v.GetFloatValue()), nil
126135

@@ -423,6 +432,66 @@ func DateValueFromTime(t time.Time) dateValue {
423432
return dateValue(uint64(t.Sub(epoch)/time.Second) / secondsPerDay)
424433
}
425434

435+
type date32Value int32
436+
437+
func (v date32Value) castTo(dst any) error {
438+
switch vv := dst.(type) {
439+
case *time.Time:
440+
*vv = Date32ToTime(int32(v)).UTC()
441+
442+
return nil
443+
case *driver.Value:
444+
*vv = Date32ToTime(int32(v)).UTC()
445+
446+
return nil
447+
case *int64:
448+
*vv = int64(v)
449+
450+
return nil
451+
case *int32:
452+
*vv = int32(v)
453+
454+
return nil
455+
case *int:
456+
*vv = int(v)
457+
458+
return nil
459+
default:
460+
return xerrors.WithStackTrace(fmt.Errorf(
461+
"%w '%s(%+v)' to '%T' destination",
462+
ErrCannotCast, v.Type().Yql(), v, vv,
463+
))
464+
}
465+
}
466+
467+
func (v date32Value) Yql() string {
468+
return fmt.Sprintf("%s(%q)", v.Type().Yql(), Date32ToTime(int32(v)).UTC().Format(LayoutDate))
469+
}
470+
471+
func (date32Value) Type() types.Type {
472+
return types.Date32
473+
}
474+
475+
func (v date32Value) toYDB(a *allocator.Allocator) *Ydb.Value {
476+
vv := a.Int32()
477+
478+
vv.Int32Value = int32(v)
479+
480+
vvv := a.Value()
481+
vvv.Value = vv
482+
483+
return vvv
484+
}
485+
486+
// Date32Value returns ydb date value by given days since Epoch
487+
func Date32Value(v int32) date32Value {
488+
return date32Value(v)
489+
}
490+
491+
func Date32ValueFromTime(t time.Time) date32Value {
492+
return date32Value(uint64(t.Unix() / 24 / 60 / 60))
493+
}
494+
426495
type datetimeValue uint32
427496

428497
func (v datetimeValue) castTo(dst any) error {
@@ -482,6 +551,57 @@ func DatetimeValueFromTime(t time.Time) datetimeValue {
482551
return datetimeValue(t.Unix())
483552
}
484553

554+
type datetime64Value int64
555+
556+
func (v datetime64Value) castTo(dst any) error {
557+
switch vv := dst.(type) {
558+
case *time.Time:
559+
*vv = Datetime64ToTime(int64(v))
560+
561+
return nil
562+
case *driver.Value:
563+
*vv = Datetime64ToTime(int64(v))
564+
565+
return nil
566+
case *int64:
567+
*vv = int64(v)
568+
569+
return nil
570+
default:
571+
return xerrors.WithStackTrace(fmt.Errorf(
572+
"%w '%s(%+v)' to '%T' destination",
573+
ErrCannotCast, v.Type().Yql(), v, vv,
574+
))
575+
}
576+
}
577+
578+
func (v datetime64Value) Yql() string {
579+
return fmt.Sprintf("%s(%q)", v.Type().Yql(), Datetime64ToTime(int64(v)).UTC().Format(LayoutDatetime))
580+
}
581+
582+
func (datetime64Value) Type() types.Type {
583+
return types.Datetime64
584+
}
585+
586+
func (v datetime64Value) toYDB(a *allocator.Allocator) *Ydb.Value {
587+
vv := a.Int64()
588+
vv.Int64Value = int64(v)
589+
590+
vvv := a.Value()
591+
vvv.Value = vv
592+
593+
return vvv
594+
}
595+
596+
// Datetime64Value makes ydb datetime value from seconds since Epoch
597+
func Datetime64Value(v int64) datetime64Value {
598+
return datetime64Value(v)
599+
}
600+
601+
func Datetime64ValueFromTime(t time.Time) datetime64Value {
602+
return datetime64Value(t.Unix())
603+
}
604+
485605
var _ DecimalValuer = (*decimalValue)(nil)
486606

487607
type decimalValue struct {
@@ -1757,6 +1877,57 @@ func TimestampValueFromTime(t time.Time) timestampValue {
17571877
return timestampValue(t.Sub(epoch) / time.Microsecond)
17581878
}
17591879

1880+
type timestamp64Value int64
1881+
1882+
func (v timestamp64Value) castTo(dst any) error {
1883+
switch vv := dst.(type) {
1884+
case *time.Time:
1885+
*vv = Timestamp64ToTime(int64(v))
1886+
1887+
return nil
1888+
case *driver.Value:
1889+
*vv = Timestamp64ToTime(int64(v))
1890+
1891+
return nil
1892+
case *int64:
1893+
*vv = int64(v)
1894+
1895+
return nil
1896+
default:
1897+
return xerrors.WithStackTrace(fmt.Errorf(
1898+
"%w '%s(%+v)' to '%T' destination",
1899+
ErrCannotCast, v.Type().Yql(), v, vv,
1900+
))
1901+
}
1902+
}
1903+
1904+
func (v timestamp64Value) Yql() string {
1905+
return fmt.Sprintf("%s(%q)", v.Type().Yql(), Timestamp64ToTime(int64(v)).UTC().Format(LayoutTimestamp))
1906+
}
1907+
1908+
func (timestamp64Value) Type() types.Type {
1909+
return types.Timestamp64
1910+
}
1911+
1912+
func (v timestamp64Value) toYDB(a *allocator.Allocator) *Ydb.Value {
1913+
vv := a.Int64()
1914+
vv.Int64Value = int64(v)
1915+
1916+
vvv := a.Value()
1917+
vvv.Value = vv
1918+
1919+
return vvv
1920+
}
1921+
1922+
// Timestamp64Value makes ydb timestamp value by given microseconds since Epoch
1923+
func Timestamp64Value(v int64) timestamp64Value {
1924+
return timestamp64Value(v)
1925+
}
1926+
1927+
func Timestamp64ValueFromTime(t time.Time) timestamp64Value {
1928+
return timestamp64Value(t.UnixMicro())
1929+
}
1930+
17601931
type tupleValue struct {
17611932
t types.Type
17621933
items []Value

internal/value/value_test.go

+25
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,14 @@ func TestValueYql(t *testing.T) {
302302
}()),
303303
literal: `Date("2022-06-17")`,
304304
},
305+
{
306+
value: Date32Value(func() int32 {
307+
v, _ := time.Parse("2006-01-02", "2022-06-17")
308+
309+
return int32(v.Sub(time.Unix(0, 0)) / time.Hour / 24)
310+
}()),
311+
literal: `Date32("2022-06-17")`,
312+
},
305313
{
306314
value: DatetimeValue(func() uint32 {
307315
v, _ := time.Parse("2006-01-02 15:04:05", "2022-06-17 05:19:20")
@@ -310,6 +318,14 @@ func TestValueYql(t *testing.T) {
310318
}()),
311319
literal: `Datetime("2022-06-17T05:19:20Z")`,
312320
},
321+
{
322+
value: Datetime64Value(func() int64 {
323+
v, _ := time.Parse("2006-01-02 15:04:05", "2022-06-17 05:19:20")
324+
325+
return int64(v.UTC().Sub(time.Unix(0, 0)).Seconds())
326+
}()),
327+
literal: `Datetime64("2022-06-17T05:19:20Z")`,
328+
},
313329
{
314330
value: TzDateValue("2022-06-17,Europe/Berlin"),
315331
literal: `TzDate("2022-06-17,Europe/Berlin")`,
@@ -331,6 +347,15 @@ func TestValueYql(t *testing.T) {
331347
}()),
332348
literal: `Timestamp("1997-12-14T03:09:42.123456Z")`,
333349
},
350+
{
351+
value: Timestamp64ValueFromTime(func() time.Time {
352+
tt, err := time.Parse(LayoutTimestamp, "1997-12-14T03:09:42.123456Z")
353+
require.NoError(t, err)
354+
355+
return tt.UTC()
356+
}()),
357+
literal: `Timestamp64("1997-12-14T03:09:42.123456Z")`,
358+
},
334359
{
335360
value: TzTimestampValue("1997-12-14T03:09:42.123456,Europe/Berlin"),
336361
literal: `TzTimestamp("1997-12-14T03:09:42.123456,Europe/Berlin")`,

0 commit comments

Comments
 (0)