From b3adf379587f1586b7ea503ee77888ea1713ae48 Mon Sep 17 00:00:00 2001 From: Brett Logan Date: Mon, 5 Apr 2021 22:30:02 -0400 Subject: [PATCH 1/2] Add Support For Millisecond Timestamps The GitHub Audit Log API introduced timestamps with millisecond granularity. We add support for these timestamps by first parsing the timestamp into a Unix timestamp and then checking to see if the generated timestamp is in the future. If the timestamp is in the future we re-parse it as a Unix timestamp in Milliseconds. Signed-off-by: Brett Logan --- github/enterprise_audit_log_test.go | 2 +- github/orgs_audit_log_test.go | 3 ++- github/timestamp.go | 3 +++ github/timestamp_test.go | 13 +++++++++---- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/github/enterprise_audit_log_test.go b/github/enterprise_audit_log_test.go index 2e13408eed7..ff46d8e1ec7 100644 --- a/github/enterprise_audit_log_test.go +++ b/github/enterprise_audit_log_test.go @@ -55,7 +55,7 @@ func TestEnterpriseService_GetAuditLog(t *testing.T) { } startedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:33:04.000Z") completedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:35:08.000Z") - timestamp := time.Unix(1615077308538, 0) + timestamp := time.Unix(0, 0).Add(time.Duration(1615077308538) * time.Millisecond) want := []*AuditEntry{ { diff --git a/github/orgs_audit_log_test.go b/github/orgs_audit_log_test.go index c6287d87100..7cc486aebbd 100644 --- a/github/orgs_audit_log_test.go +++ b/github/orgs_audit_log_test.go @@ -62,7 +62,8 @@ func TestOrganizationService_GetAuditLog(t *testing.T) { } startedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:33:04.000Z") completedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:35:08.000Z") - timestamp := time.Unix(1615077308538, 0) + timestamp := time.Unix(0, 0).Add(time.Duration(1615077308538) * time.Millisecond) + want := []*AuditEntry{ { Timestamp: &Timestamp{timestamp}, diff --git a/github/timestamp.go b/github/timestamp.go index 90929d5757d..e4a77269bea 100644 --- a/github/timestamp.go +++ b/github/timestamp.go @@ -29,6 +29,9 @@ func (t *Timestamp) UnmarshalJSON(data []byte) (err error) { i, err := strconv.ParseInt(str, 10, 64) if err == nil { t.Time = time.Unix(i, 0) + if t.Time.Year() > 3000 { + t.Time = time.Unix(0, 0).Add(time.Duration(i) * time.Millisecond) + } } else { t.Time, err = time.Parse(`"`+time.RFC3339+`"`, str) } diff --git a/github/timestamp_test.go b/github/timestamp_test.go index 7d5b712e91c..097249519d4 100644 --- a/github/timestamp_test.go +++ b/github/timestamp_test.go @@ -13,10 +13,11 @@ import ( ) const ( - emptyTimeStr = `"0001-01-01T00:00:00Z"` - referenceTimeStr = `"2006-01-02T15:04:05Z"` - referenceTimeStrFractional = `"2006-01-02T15:04:05.000Z"` // This format was returned by the Projects API before October 1, 2017. - referenceUnixTimeStr = `1136214245` + emptyTimeStr = `"0001-01-01T00:00:00Z"` + referenceTimeStr = `"2006-01-02T15:04:05Z"` + referenceTimeStrFractional = `"2006-01-02T15:04:05.000Z"` // This format was returned by the Projects API before October 1, 2017. + referenceUnixTimeStr = `1136214245` + referenceUnixTimeStrMilliSeconds = `1136214245000` // Millisecond-granular timestamps were introduced in the Audit log API. ) var ( @@ -59,12 +60,14 @@ func TestTimestamp_Unmarshal(t *testing.T) { }{ {"Reference", referenceTimeStr, Timestamp{referenceTime}, false, true}, {"ReferenceUnix", referenceUnixTimeStr, Timestamp{referenceTime}, false, true}, + {"ReferenceUnixMillisecond", referenceUnixTimeStrMilliSeconds, Timestamp{referenceTime}, false, true}, {"ReferenceFractional", referenceTimeStrFractional, Timestamp{referenceTime}, false, true}, {"Empty", emptyTimeStr, Timestamp{}, false, true}, {"UnixStart", `0`, Timestamp{unixOrigin}, false, true}, {"Mismatch", referenceTimeStr, Timestamp{}, false, false}, {"MismatchUnix", `0`, Timestamp{}, false, false}, {"Invalid", `"asdf"`, Timestamp{referenceTime}, true, false}, + {"OffByMillisecond", `1136214245001`, Timestamp{referenceTime}, false, false}, } for _, tc := range testCases { var got Timestamp @@ -144,11 +147,13 @@ func TestWrappedTimestamp_Unmarshal(t *testing.T) { }{ {"Reference", referenceTimeStr, WrappedTimestamp{0, Timestamp{referenceTime}}, false, true}, {"ReferenceUnix", referenceUnixTimeStr, WrappedTimestamp{0, Timestamp{referenceTime}}, false, true}, + {"ReferenceUnixMillisecond", referenceUnixTimeStrMilliSeconds, WrappedTimestamp{0, Timestamp{referenceTime}}, false, true}, {"Empty", emptyTimeStr, WrappedTimestamp{0, Timestamp{}}, false, true}, {"UnixStart", `0`, WrappedTimestamp{0, Timestamp{unixOrigin}}, false, true}, {"Mismatch", referenceTimeStr, WrappedTimestamp{0, Timestamp{}}, false, false}, {"MismatchUnix", `0`, WrappedTimestamp{0, Timestamp{}}, false, false}, {"Invalid", `"asdf"`, WrappedTimestamp{0, Timestamp{referenceTime}}, true, false}, + {"OffByMillisecond", `1136214245001`, WrappedTimestamp{0, Timestamp{referenceTime}}, false, false}, } for _, tc := range testCases { var got Timestamp From 9dfcb8ed7f29131fa746302c03072a56544638b2 Mon Sep 17 00:00:00 2001 From: Brett Logan Date: Tue, 6 Apr 2021 10:30:03 -0400 Subject: [PATCH 2/2] Simplify Timestamp Conversion Signed-off-by: Brett Logan --- github/enterprise_audit_log_test.go | 2 +- github/orgs_audit_log_test.go | 2 +- github/timestamp.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/github/enterprise_audit_log_test.go b/github/enterprise_audit_log_test.go index ff46d8e1ec7..d0068158323 100644 --- a/github/enterprise_audit_log_test.go +++ b/github/enterprise_audit_log_test.go @@ -55,7 +55,7 @@ func TestEnterpriseService_GetAuditLog(t *testing.T) { } startedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:33:04.000Z") completedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:35:08.000Z") - timestamp := time.Unix(0, 0).Add(time.Duration(1615077308538) * time.Millisecond) + timestamp := time.Unix(0, 1615077308538*1e6) want := []*AuditEntry{ { diff --git a/github/orgs_audit_log_test.go b/github/orgs_audit_log_test.go index 7cc486aebbd..cc68fc5e65d 100644 --- a/github/orgs_audit_log_test.go +++ b/github/orgs_audit_log_test.go @@ -62,7 +62,7 @@ func TestOrganizationService_GetAuditLog(t *testing.T) { } startedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:33:04.000Z") completedAt, _ := time.Parse(time.RFC3339, "2021-03-07T00:35:08.000Z") - timestamp := time.Unix(0, 0).Add(time.Duration(1615077308538) * time.Millisecond) + timestamp := time.Unix(0, 1615077308538*1e6) want := []*AuditEntry{ { diff --git a/github/timestamp.go b/github/timestamp.go index e4a77269bea..1061a55e68e 100644 --- a/github/timestamp.go +++ b/github/timestamp.go @@ -30,7 +30,7 @@ func (t *Timestamp) UnmarshalJSON(data []byte) (err error) { if err == nil { t.Time = time.Unix(i, 0) if t.Time.Year() > 3000 { - t.Time = time.Unix(0, 0).Add(time.Duration(i) * time.Millisecond) + t.Time = time.Unix(0, i*1e6) } } else { t.Time, err = time.Parse(`"`+time.RFC3339+`"`, str)