Skip to content

Commit f1149fa

Browse files
author
Mike Kistler
committed
fix: Handle conversions for naive datetime values
1 parent f67a1d9 commit f1149fa

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

ibm_cloud_sdk_core/utils.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,19 @@ def cleanup_value(value: any) -> any:
7171
def datetime_to_string(val: datetime.datetime) -> str:
7272
"""Convert a datetime object to string.
7373
74+
If the supplied datetime does not specify a timezone,
75+
it is assumed to be UTC.
76+
7477
Args:
7578
val: The datetime object.
7679
7780
Returns:
7881
datetime serialized to iso8601 format.
7982
"""
8083
if isinstance(val, datetime.datetime):
84+
if val.tzinfo is None:
85+
return val.isoformat() + 'Z'
86+
val = val.astimezone(datetime.timezone.utc)
8187
return val.isoformat().replace('+00:00', 'Z')
8288
return val
8389

@@ -90,7 +96,10 @@ def string_to_datetime(string: str) -> datetime.datetime:
9096
Returns:
9197
the de-serialized string as a datetime object.
9298
"""
93-
return date_parser.parse(string)
99+
val = date_parser.parse(string)
100+
if val.tzinfo is not None:
101+
return val
102+
return val.replace(tzinfo=datetime.timezone.utc)
94103

95104
def date_to_string(val: datetime.date) -> str:
96105
"""Convert a date object to string.

test/test_utils.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,45 @@
11
# pylint: disable=missing-docstring
2+
import datetime
23
import os
34

45
from ibm_cloud_sdk_core import string_to_datetime, datetime_to_string, get_authenticator_from_environment
56
from ibm_cloud_sdk_core import string_to_date, date_to_string
67
from ibm_cloud_sdk_core import convert_model, convert_list
78
from ibm_cloud_sdk_core.authenticators import BasicAuthenticator, IAMAuthenticator
89

9-
def test_datetime_conversion():
10+
def test_string_to_datetime():
11+
# If the specified string does not include a timezone, it is assumed to be UTC
1012
date = string_to_datetime('2017-03-06 16:00:04.159338')
1113
assert date.day == 6
12-
res = datetime_to_string(date)
13-
assert res == '2017-03-06T16:00:04.159338'
14+
assert date.hour == 16
15+
assert date.tzinfo.utcoffset(None) == datetime.timezone.utc.utcoffset(None)
16+
# Test date string with TZ specified as '+xxxx'
17+
date = string_to_datetime('2017-03-06 16:00:04.159338+0600')
18+
assert date.day == 6
19+
assert date.hour == 16
20+
assert date.tzinfo.utcoffset(None).total_seconds() == 6*60*60
21+
# Test date string with TZ specified as 'Z'
22+
date = string_to_datetime('2017-03-06 16:00:04.159338Z')
23+
assert date.day == 6
24+
assert date.hour == 16
25+
assert date.tzinfo.utcoffset(None) == datetime.timezone.utc.utcoffset(None)
26+
27+
def test_datetime_to_string():
28+
# If specified date is None, return None
1429
assert datetime_to_string(None) is None
30+
# If the specified date is "naive", it is interpreted as a UTC date
31+
date = datetime.datetime(2017, 3, 6, 16, 0, 4, 159338)
32+
res = datetime_to_string(date)
33+
assert res == '2017-03-06T16:00:04.159338Z'
34+
# Test date with UTC timezone
35+
date = datetime.datetime(2017, 3, 6, 16, 0, 4, 159338, datetime.timezone.utc)
36+
res = datetime_to_string(date)
37+
assert res == '2017-03-06T16:00:04.159338Z'
38+
# Test date with non-UTC timezone
39+
tzn = datetime.timezone(datetime.timedelta(hours=-6))
40+
date = datetime.datetime(2017, 3, 6, 10, 0, 4, 159338, tzn)
41+
res = datetime_to_string(date)
42+
assert res == '2017-03-06T16:00:04.159338Z'
1543

1644
def test_date_conversion():
1745
date = string_to_date('2017-03-06')

0 commit comments

Comments
 (0)