chore: minor refactorings to custom time parsing logic

This commit is contained in:
Ferdinand Mütsch 2021-04-25 09:21:21 +02:00
parent 0556efd39a
commit 26ef93c1af
3 changed files with 17 additions and 19 deletions

View File

@ -117,13 +117,14 @@ $ ./wakapi
#### Compile & Run #### Compile & Run
```bash ```bash
# Adapt config to your needs
$ cp config.default.yml config.yml
$ vi config.yml
# Build the executable # Build the executable
$ go build -o wakapi $ go build -o wakapi
# Adapt config to your needs
$ cp config.default.yml config.yml
$ vi config.yml
# Run it # Run it
$ ./wakapi $ ./wakapi
``` ```

View File

@ -6,7 +6,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"gorm.io/gorm" "gorm.io/gorm"
"math"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -30,24 +29,24 @@ type Interval struct {
End time.Time End time.Time
} }
// CustomTime is a wrapper type around time.Time, mainly used for the purpose of transparently unmarshalling Python timestamps in the format <sec>.<nsec> (e.g. 1619335137.3324468)
type CustomTime time.Time type CustomTime time.Time
func (j *CustomTime) MarshalJSON() ([]byte, error) { func (j *CustomTime) MarshalJSON() ([]byte, error) {
return json.Marshal(j.String()) return json.Marshal(j.T())
} }
func (j *CustomTime) UnmarshalJSON(b []byte) error { func (j *CustomTime) UnmarshalJSON(b []byte) error {
s := strings.Replace(strings.Trim(string(b), "\""), ".", "", 1) s := strings.Trim(string(b), "\"")
i, err := strconv.ParseInt(s, 10, 64) ts, err := strconv.ParseFloat(s, 64)
if err != nil { if err != nil {
return err return err
} }
t := time.Unix(0, i*int64(math.Pow10(19-len(s)))) t := time.Unix(0, int64(ts*1e9)) // ms to ns
*j = CustomTime(t) *j = CustomTime(t)
return nil return nil
} }
// heartbeat timestamps arrive as strings for sqlite and as time.Time for postgres
func (j *CustomTime) Scan(value interface{}) error { func (j *CustomTime) Scan(value interface{}) error {
var ( var (
t time.Time t time.Time
@ -56,13 +55,12 @@ func (j *CustomTime) Scan(value interface{}) error {
switch value.(type) { switch value.(type) {
case string: case string:
// with sqlite, some queries (like GetLastByUser()) return dates as strings,
// however, most of the time they are returned as time.Time
t, err = time.Parse("2006-01-02 15:04:05-07:00", value.(string)) t, err = time.Parse("2006-01-02 15:04:05-07:00", value.(string))
if err != nil { if err != nil {
return errors.New(fmt.Sprintf("unsupported date time format: %s", value)) return errors.New(fmt.Sprintf("unsupported date time format: %s", value))
} }
case int64:
t = time.Unix(0, value.(int64))
break
case time.Time: case time.Time:
t = value.(time.Time) t = value.(time.Time)
break break
@ -76,18 +74,17 @@ func (j *CustomTime) Scan(value interface{}) error {
return nil return nil
} }
func (j *CustomTime) Hash() (uint64, error) {
return uint64((j.T().UnixNano() / 1000) / 1000), nil
}
func (j CustomTime) Value() (driver.Value, error) { func (j CustomTime) Value() (driver.Value, error) {
t := time.Unix(0, j.T().UnixNano()/int64(time.Millisecond)*int64(time.Millisecond)) // round to millisecond precision t := time.Unix(0, j.T().UnixNano()/int64(time.Millisecond)*int64(time.Millisecond)) // round to millisecond precision
return t, nil return t, nil
} }
func (j *CustomTime) Hash() (uint64, error) {
return uint64((j.T().UnixNano() / 1000) / 1000), nil
}
func (j CustomTime) String() string { func (j CustomTime) String() string {
t := time.Time(j) return j.T().String()
return t.Format("2006-01-02 15:04:05.000")
} }
func (j CustomTime) T() time.Time { func (j CustomTime) T() time.Time {

View File

@ -272,7 +272,7 @@ def run(params: ConfigParams, update_progress: Callable[[int], None]):
else: else:
for d in data: for d in data:
post_data_sync([d], f'{params.api_url}/heartbeats', params.api_key) post_data_sync([d], f'{params.api_url}/heartbeats', params.api_key)
update_progress(len(d)) update_progress(1)
if __name__ == '__main__': if __name__ == '__main__':