Background - found during testing with proprietry application derived from the 'light_ctrl' sample in nRF Connect SDK, with Time & Schedule Servers added, on an nRF52833DK. We are using the recommended method of printing time shown at https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.7.1/nrf/libraries/bluetooth_services/mesh/time_srv.html , but with modification to also print seconds.
We tested sending a time message with the example value given in the Bluetooth Mesh Model v1.0.1 spec in Section 5.1.1.1 , plus message fields for Time Zone and TAI-UTC offsets filled in appropriately.
For example, the value 0x20E5369D represents the 2017-06-27T15:30:37 TAI (15:30:00 UTC).
This ended up showing 15:31:14 instead of 15:30:00.
We tracked this down to a bug in the bt_mesh_time_srv_localtime_r() function in how it handles the TAI-UTC delta. According to Section 5.1.1.8 of the spec;
The TAI-UTC Delta Current state represents the value: current_TAI minus current_UTC. For example, on 2017-01-19, this value equals +37. The valid range is -255 through +32512 (i.e., 0x00FF represents a value of 0 and 0x7FFF represents a value of 32512).
The spec says clearly this value represents current_TAI minus current_UTC. Currently this value is +37.
UTC is behind TAI, so this value is positive. So to get from TAI to UTC you need to subtract this value.
However this function adds this value; tai.sec += get_utc_delta(srv, uptime); leading to an error of +1min14 (double the 37sec).
struct tm *bt_mesh_time_srv_localtime_r(struct bt_mesh_time_srv *srv,
int64_t uptime, struct tm *timeptr)
{
if (tai_is_unknown(&srv->data.sync.status.tai) ||
srv->data.sync.uptime > uptime) {
return NULL;
}
struct bt_mesh_time_tai tai = tai_at(srv, uptime);
tai.sec += zone_offset_to_sec(get_zone_offset(srv, uptime));
tai.sec += get_utc_delta(srv, uptime);
tai_to_ts(&tai, timeptr);
return timeptr;
}