2 go.cypherpunks.ru/tai64n -- Pure Go TAI64/TAI64N implementation
3 Copyright (C) 2020-2022 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 // TAI64/TAI64N (http://cr.yp.to/libtai/tai64.html) dealing library.
19 // You can convert time to TAI64/TAI64N and vice versa with it.
21 // tai := new(tai64n.TAI64N)
22 // tai.FromTime(time.Now())
23 // printable := tai64n.Encode(tai[:])
24 // decoded, err := tai64n.Decode(printable)
25 // tai64n.ToTime(tai[:]) == decoded
27 // By default TAI64 timestamps contain initial 1972-01-01 10-seconds
28 // TAI<->UTC difference. If you need honest TAI representation, then you
29 // should also use Leapsecs* functions.
42 TAI64NSize = TAI64Size + 4
43 LocalFmt = "2006-01-02 15:04:05.000000000"
44 Base = 0x4000000000000000 + Leapsecs1972
47 type TAI64 [TAI64Size]byte
48 type TAI64N [TAI64NSize]byte
50 func (dst *TAI64) FromTime(src time.Time) {
51 binary.BigEndian.PutUint64(dst[:], uint64(Base)+uint64(src.Unix()))
54 func (dst *TAI64N) FromTime(src time.Time) {
55 binary.BigEndian.PutUint64(dst[:], uint64(Base)+uint64(src.Unix()))
56 binary.BigEndian.PutUint32(dst[8:], uint32(src.Nanosecond()))
59 func ToTime(tai []byte) time.Time {
63 nano = int64(binary.BigEndian.Uint32(tai[8:]))
66 secs = int64(binary.BigEndian.Uint64(tai[:8])) - Base
68 panic("invalid tai size")
71 panic("dates < 1970-01-01 are not supported")
73 return time.Unix(secs, nano)
76 // Convert TAI64/TAI64N to "@HEX(TAI64)" format.
77 func Encode(tai []byte) string {
78 raw := make([]byte, 1+hex.EncodedLen(len(tai)))
80 hex.Encode(raw[1:], tai)
84 // Convert TAI64/TAI64N "@HEX(TAI64)" format to Time.
85 func Decode(s string) (time.Time, error) {
86 raw, err := hex.DecodeString(strings.TrimPrefix(s, "@"))
87 if !(len(raw) == TAI64Size || len(raw) == TAI64NSize) {
88 err = errors.New("invalid length")
91 return ToTime(raw), nil
93 return time.Time{}, err