aboutsummaryrefslogtreecommitdiff
path: root/nimpb/wkt/timestamp.nim
blob: 3df18b50ee28372d01b9a0b3126b3eb7f70a05ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import json
import pegs
import strutils
import times

include timestamp_pb

proc toJson*(message: google_protobuf_Timestamp): JsonNode =
    let t = utc(fromUnix(message.seconds))

    if t.year < 1 or t.year > 9999:
        raise newException(ValueError, "invalid timestamp")

    var s = format(t, "yyyy-MM-dd'T'HH:mm:ss")
    if message.nanos != 0:
        add(s, ".")
        add(s, intToStr(message.nanos, 9))
        removeSuffix(s, '0')
    add(s, "Z")
    result = %s

proc parsegoogle_protobuf_Timestamp*(node: JsonNode): google_protobuf_Timestamp =
    if node.kind != JString:
        raise newException(nimpb_json.ParseError, "string expected")

    var pattern = peg"""
timestamp <- year '-' month '-' day 'T' hours ':' mins ':' secs {frac?} {offset}
year <- \d\d\d\d
month <- \d\d
day <- \d\d
hours <- \d\d
mins <- \d\d
secs <- \d\d
frac <- '.' \d+
offset <- 'Z' / (('+' / '-') \d\d ':' \d\d)
"""

    var matches: array[2, string]
    var s = node.str
    var nanos = 0

    if not match(s, pattern, matches):
        raise newException(nimpb_json.ParseError, "invalid timestamp")

    if len(matches[0]) > 0:
        # Delete the fractions if they were found so that times.parse() can
        # parse the rest of the timestamp.
        let first = len(s) - len(matches[1]) - len(matches[0])
        let last = len(s) - len(matches[1]) - 1
        delete(s, first, last)

        var factor = 100_000_000
        for ch in matches[0][1..^1]:
            nanos = nanos + factor * (ord(ch) - ord('0'))
            factor = factor div 10

        if nanos > 999_999_999:
            raise newException(nimpb_json.ParseError, "nanos out of bounds")

    var dt: DateTime

    try:
        dt = times.parse(s, "yyyy-MM-dd'T'HH:mm:sszzz", utc())
    except Exception as exc:
        raise newException(nimpb_json.ParseError, exc.msg)

    if dt.year < 1 or dt.year > 9999:
        raise newException(nimpb_json.ParseError, "year out of bounds")

    result = newgoogle_protobuf_Timestamp()

    result.seconds = toUnix(toTime(dt))
    result.nanos = int32(nanos)