diff --git a/fbclock/cpp_test/test.cpp b/fbclock/cpp_test/test.cpp index b10e7d51..18a5a099 100644 --- a/fbclock/cpp_test/test.cpp +++ b/fbclock/cpp_test/test.cpp @@ -193,6 +193,18 @@ TEST(fbclock_test, test_fbclock_calculate_time) { EXPECT_EQ(truetime.latest_ns, 1647290691804195223); } +TEST(fbclock_test, test_fbclock_apply_utc_offset) { + int err; + fbclock_truetime truetime; + truetime.earliest_ns = 1647269091803102338; + truetime.latest_ns = 1647269091803103576; + + fbclock_apply_utc_offset(&truetime); + + EXPECT_EQ(truetime.earliest_ns, 1647269054803102338); + EXPECT_EQ(truetime.latest_ns, 1647269054803103576); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/fbclock/fbclock.c b/fbclock/fbclock.c index eeecfb43..105290ac 100644 --- a/fbclock/fbclock.c +++ b/fbclock/fbclock.c @@ -221,6 +221,24 @@ int fbclock_gettime(fbclock_lib* lib, fbclock_truetime* truetime) { error_bound, h_value, state.ingress_time_ns, res.ts, truetime); } +void fbclock_apply_utc_offset(fbclock_truetime* truetime) { + truetime->earliest_ns += UTC_TAI_OFFSET; + truetime->latest_ns += UTC_TAI_OFFSET; +} + +// When/if new leap second is announced, we would need to update this function +// to do smearing, and fetch offset from fbclock daemon. +// For now, we apply the offset, as leap seconds will be abandoned by 2035 +// and it is possible we won't have any at all. +int fbclock_gettime_utc(fbclock_lib* lib, fbclock_truetime* truetime) { + int rcode = fbclock_gettime(lib, truetime); + if (rcode != 0) { + return rcode; + } + fbclock_apply_utc_offset(truetime); + return 0; +} + const char* fbclock_strerror(int err_code) { const char* err_info = "unknown error"; switch (err_code) { diff --git a/fbclock/fbclock.go b/fbclock/fbclock.go index 33e20b23..a5c3d16a 100644 --- a/fbclock/fbclock.go +++ b/fbclock/fbclock.go @@ -87,3 +87,17 @@ func (f *FBClock) GetTime() (*TrueTime, error) { return &TrueTime{Earliest: earliest, Latest: latest}, nil } + +// GetTimeUTC returns TrueTime in UTC +func (f *FBClock) GetTimeUTC() (*TrueTime, error) { + tt := &C.fbclock_truetime{} + errCode := C.fbclock_gettime_utc(f.cFBClock, tt) + if errCode != 0 { + return nil, fmt.Errorf("reading FBClock TrueTime UTC: %s", strerror(errCode)) + } + + earliest := time.Unix(0, int64(tt.earliest_ns)) + latest := time.Unix(0, int64(tt.latest_ns)) + + return &TrueTime{Earliest: earliest, Latest: latest}, nil +} diff --git a/fbclock/fbclock.h b/fbclock/fbclock.h index cf730e28..a86ea546 100644 --- a/fbclock/fbclock.h +++ b/fbclock/fbclock.h @@ -35,6 +35,9 @@ typedef atomic_uint_fast64_t atomic_uint64; #define FBCLOCK_E_WOU_TOO_BIG -6 #define FBCLOCK_E_PHC_IN_THE_PAST -7 +// until new leap second is introduced, UTC is exactly 37 seconds behind TAI +#define UTC_TAI_OFFSET (int64_t)(-37e9) + #ifdef __cplusplus extern "C" { #endif @@ -85,11 +88,13 @@ int fbclock_calculate_time( int64_t ingress_time_ns, int64_t phctime_ns, fbclock_truetime* truetime); +void fbclock_apply_utc_offset(fbclock_truetime* truetime); // methods we provide to end users int fbclock_init(fbclock_lib* lib, const char* shm_path); int fbclock_destroy(fbclock_lib* lib); int fbclock_gettime(fbclock_lib* lib, fbclock_truetime* truetime); +int fbclock_gettime_utc(fbclock_lib* lib, fbclock_truetime* truetime); // turn error code into err msg const char* fbclock_strerror(int err_code);