]> Cypherpunks.ru repositories - goredo.git/blob - tai64n.go
e6dd28e7fd420cc9d3bc7c46b6115823efbe7c39
[goredo.git] / tai64n.go
1 /*
2 goredo -- redo implementation on pure Go
3 Copyright (C) 2020 Sergey Matveev <stargrave@stargrave.org>
4
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.
8
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.
13
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/>.
16 */
17
18 package main
19
20 import (
21         "bufio"
22         "encoding/binary"
23         "encoding/hex"
24         "errors"
25         "io"
26         "strings"
27         "time"
28 )
29
30 const (
31         TAI64NSize     = 12
32         TAI64NBase     = 0x400000000000000a
33         TAI64NLocalFmt = "2006-01-02 15:04:05.000000000"
34 )
35
36 type TAI64N [TAI64NSize]byte
37
38 func tai64nNow(ts *TAI64N) {
39         t := time.Now()
40         binary.BigEndian.PutUint64(ts[:], uint64(TAI64NBase)+uint64(t.Unix()))
41         binary.BigEndian.PutUint32(ts[8:], uint32(t.Nanosecond()))
42 }
43
44 func tai64nLocal(dst io.StringWriter, src io.Reader) error {
45         scanner := bufio.NewScanner(src)
46         var err error
47         var s string
48         var sep int
49         var ts []byte
50         var secs int64
51         var nano int64
52         var t time.Time
53         for {
54                 if !scanner.Scan() {
55                         if err = scanner.Err(); err != nil {
56                                 return err
57                         }
58                         break
59                 }
60                 s = scanner.Text()
61
62                 if s[0] != '@' {
63                         dst.WriteString(s + "\n")
64                 }
65                 sep = strings.IndexByte(s, byte(' '))
66                 if sep == -1 {
67                         dst.WriteString(s + "\n")
68                 }
69                 ts, err = hex.DecodeString(s[1:sep])
70                 if err != nil {
71                         return err
72                 }
73                 if len(ts) != TAI64NSize {
74                         return errors.New("invalid ts length")
75                 }
76                 secs = int64(binary.BigEndian.Uint64(ts[:8]))
77                 nano = int64(binary.BigEndian.Uint32(ts[8:]))
78                 t = time.Unix(secs-TAI64NBase, nano)
79                 dst.WriteString(t.Format(TAI64NLocalFmt) + s[sep:] + "\n")
80         }
81         return nil
82 }