-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #27 from ENCODE-DCC/dev
v0.3.0
- Loading branch information
Showing
8 changed files
with
137 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
"""Accurate now() based on cached offset between NTP server | ||
and local system time. | ||
Make sure not to change system time once the offset is cached. | ||
""" | ||
|
||
import logging | ||
from datetime import datetime, timezone | ||
|
||
import ntplib | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
DEFAULT_NTP_SERVER = "pool.ntp.org" | ||
cached_offset_between_ntp_server_and_local_system = None | ||
|
||
|
||
def now_utc(ntp_server=DEFAULT_NTP_SERVER): | ||
global cached_offset_between_ntp_server_and_local_system | ||
|
||
if cached_offset_between_ntp_server_and_local_system is not None: | ||
return ( | ||
datetime.now(timezone.utc) | ||
+ cached_offset_between_ntp_server_and_local_system | ||
) | ||
|
||
try: | ||
resp = ntplib.NTPClient().request(ntp_server) | ||
adjusted_timestamp = resp.tx_time + resp.delay * 0.5 | ||
ntp_server_time = datetime.fromtimestamp(adjusted_timestamp, timezone.utc) | ||
# update cache | ||
cached_offset_between_ntp_server_and_local_system = ( | ||
ntp_server_time - datetime.now(timezone.utc) | ||
) | ||
logger.debug( | ||
"Successfully retrieved time from NTP server {srv}. time:{time}, offset:{offset}".format( | ||
srv=ntp_server, | ||
time=ntp_server_time, | ||
offset=cached_offset_between_ntp_server_and_local_system.total_seconds(), | ||
) | ||
) | ||
return ntp_server_time | ||
|
||
except Exception as e: | ||
logger.debug( | ||
"Failed to retrieve time from NTP server {srv}. error {err}".format( | ||
srv=ntp_server, err=str(e) | ||
) | ||
) | ||
|
||
return datetime.now(timezone.utc) | ||
|
||
|
||
def reset_cached_offset(): | ||
global cached_offset_between_ntp_server_and_local_system | ||
cached_offset_between_ntp_server_and_local_system = None | ||
|
||
|
||
def get_cached_offset(): | ||
global cached_offset_between_ntp_server_and_local_system | ||
return cached_offset_between_ntp_server_and_local_system |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,5 +61,6 @@ def find_meta(meta): | |
"dateparser", | ||
"filelock", | ||
"six>=1.13.0", | ||
"ntplib", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
"""Make sure to run these tests on a machine with correct os time | ||
""" | ||
from datetime import datetime, timedelta, timezone | ||
from unittest.mock import patch | ||
|
||
from autouri.ntp_now import get_cached_offset, now_utc, reset_cached_offset | ||
|
||
|
||
def test_now_utc(): | ||
reset_cached_offset() | ||
|
||
assert abs((now_utc() - datetime.now(timezone.utc)).total_seconds()) < 0.01 | ||
|
||
|
||
class MockedDataTime(datetime): | ||
@classmethod | ||
def now(cls, timezone): | ||
return datetime.now(timezone) - timedelta(0, 25) | ||
|
||
|
||
def test_now_utc_wrong_os_time(): | ||
reset_cached_offset() | ||
with patch("autouri.ntp_now.datetime", MockedDataTime): | ||
ntp_now_utc = now_utc() | ||
|
||
# should be accurate even though system time is 25 second behind NTP server time | ||
assert abs((ntp_now_utc - datetime.now(timezone.utc)).total_seconds()) < 0.01 | ||
|
||
# cache offset should be 25 second | ||
cached_offset_in_seconds = get_cached_offset().total_seconds() | ||
assert cached_offset_in_seconds > 24.99 and cached_offset_in_seconds < 25.01 |