Commit a9e2badf authored by Kirill Smelkov's avatar Kirill Smelkov

go/zodb += TidFromTime

In ZODB transaction ID is connected with time. We already have
functionality to convert tid to time (see bac6c953 "go/zodb: Tid
connection with time"), but the functionality for converting in another
way - time -> tid - was missing.

Fix it.
parent 2f061c0c
// Copyright (C) 2017 Nexedi SA and Contributors. // Copyright (C) 2017-2019 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com> // Kirill Smelkov <kirr@nexedi.com>
// //
// This program is free software: you can Use, Study, Modify and Redistribute // This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your // it under the terms of the GNU General Public License version 3, or (at your
...@@ -53,7 +53,7 @@ func (t TimeStamp) XFmtString(b []byte) []byte { ...@@ -53,7 +53,7 @@ func (t TimeStamp) XFmtString(b []byte) []byte {
// Time converts tid to time. // Time converts tid to time.
func (tid Tid) Time() TimeStamp { func (tid Tid) Time() TimeStamp {
// the same as _parseRaw in TimeStamp/py // the same as _parseRaw in TimeStamp/py
// https://github.com/zopefoundation/persistent/blob/aba23595/persistent/timestamp.py#L75 // https://github.com/zopefoundation/persistent/blob/8c645429/persistent/timestamp.py#L72
a := uint64(tid) >> 32 a := uint64(tid) >> 32
b := uint64(tid) & (1 << 32 - 1) b := uint64(tid) & (1 << 32 - 1)
min := a % 60 min := a % 60
...@@ -77,11 +77,40 @@ func (tid Tid) Time() TimeStamp { ...@@ -77,11 +77,40 @@ func (tid Tid) Time() TimeStamp {
return TimeStamp{t} return TimeStamp{t}
} }
// TidFromTime converts time to tid.
func TidFromTime(t time.Time) Tid {
t = t.UTC()
// TODO TidFromTime() // the same as _makeRaw in TimeStamp/py
// TODO TidFromTimeStamp() // https://github.com/zopefoundation/persistent/blob/8c645429/persistent/timestamp.py#L66
// TODO TidForNow() ? year := uint64(t.Year())
month := uint64(t.Month())
day := uint64(t.Day())
hour := uint64(t.Hour())
min := uint64(t.Minute())
sec := uint64(t.Second())
nsec := uint64(t.Nanosecond())
a := ((year - 1900)*12 + month - 1) * 31 + day - 1
a = (a * 24 + hour) * 60 + min
// for seconds/nseconds: use 2 extra bits of precision to be able to
// round after / 1E9 and / 60 divisions. We are safe to use 2 bits,
// since 10^9 ≤ 2^30 and it all fits into uint32. However for b for
// intermediate values we are free to use whole uint64, so x can be >
// than 2 too.
const x = 2
b := sec << (32+x)
b += (nsec << (32+x)) / 1E9
b /= 60
roundup := (b & ((1<<x)-1)) >= (1<<(x-1))
b /= (1<<x)
if roundup {
b += 1
}
return Tid((a << 32) | b)
}
// δtid returns distance from tid1 to tid2 in term of time. // δtid returns distance from tid1 to tid2 in term of time.
// //
......
// Copyright (C) 2017 Nexedi SA and Contributors. // Copyright (C) 2017-2019 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com> // Kirill Smelkov <kirr@nexedi.com>
// //
// This program is free software: you can Use, Study, Modify and Redistribute // This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your // it under the terms of the GNU General Public License version 3, or (at your
...@@ -19,7 +19,10 @@ ...@@ -19,7 +19,10 @@
package zodb package zodb
import "testing" import (
"testing"
"time"
)
func TestTidTime(t *testing.T) { func TestTidTime(t *testing.T) {
var testv = []struct {tid Tid; timeStr string; timeFloat float64} { var testv = []struct {tid Tid; timeStr string; timeFloat float64} {
...@@ -42,5 +45,13 @@ func TestTidTime(t *testing.T) { ...@@ -42,5 +45,13 @@ func TestTidTime(t *testing.T) {
if timeFloat != tt.timeFloat { if timeFloat != tt.timeFloat {
t.Errorf("%v: timeFloat = %.9f ; want %.9f", tt.tid, timeFloat, tt.timeFloat) t.Errorf("%v: timeFloat = %.9f ; want %.9f", tt.tid, timeFloat, tt.timeFloat)
} }
locv := []*time.Location{time.UTC, time.FixedZone("UTC+4", +4*60*60)}
for _, loc := range locv {
tid := TidFromTime(tidtime.In(loc))
if tid != tt.tid {
t.Errorf("%v: ->time(%s)->tid != identity (= %v; δ: %s)", tt.tid, loc, tid, tt.tid - tid)
}
}
} }
} }
  • /cc @jerome (this shows that for approxidate we need to have only functionality to convert human string to time, and then the time can be converted 1-1 to tid with regular ZODB functionality. zodb/py also have this)

Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment