diff --git a/stix2/test/test_utils.py b/stix2/test/test_utils.py index a70853c..dbc0ed5 100644 --- a/stix2/test/test_utils.py +++ b/stix2/test/test_utils.py @@ -15,11 +15,33 @@ eastern = pytz.timezone('US/Eastern') (amsterdam.localize(dt.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'), (eastern.localize(dt.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'), (eastern.localize(dt.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'), + (dt.datetime(2017, 7, 1), '2017-07-01T00:00:00Z'), + (dt.datetime(2017, 7, 1, 0, 0, 0, 1), '2017-07-01T00:00:00.000001Z'), ]) def test_timestamp_formatting(dttm, timestamp): assert stix2.utils.format_datetime(dttm) == timestamp +@pytest.mark.parametrize('timestamp, dttm', [ + (dt.datetime(2017, 1, 1, 0, tzinfo=pytz.utc), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), + (dt.date(2017, 1, 1), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), + ('2017-01-01T00:00:00Z', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), + ('2017-01-01T02:00:00+2:00', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), + ('2017-01-01T00:00:00', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), +]) +def test_parse_datetime(timestamp, dttm): + assert stix2.utils.parse_into_datetime(timestamp) == dttm + + +@pytest.mark.parametrize('ts', [ + 'foobar', + 1, +]) +def test_parse_datetime_invalid(ts): + with pytest.raises(ValueError): + stix2.utils.parse_into_datetime('foobar') + + @pytest.mark.parametrize('data', [ {"a": 1}, '{"a": 1}', diff --git a/stix2/utils.py b/stix2/utils.py index 6776681..bb41937 100644 --- a/stix2/utils.py +++ b/stix2/utils.py @@ -23,11 +23,11 @@ def format_datetime(dttm): # 4. Add subsecond value if non-zero # 5. Add "Z" - try: - zoned = dttm.astimezone(pytz.utc) - except ValueError: + if dttm.tzinfo is None or dttm.tzinfo.utcoffset(dttm) is None: # dttm is timezone-naive; assume UTC - pytz.utc.localize(dttm) + zoned = pytz.utc.localize(dttm) + else: + zoned = dttm.astimezone(pytz.utc) ts = zoned.strftime("%Y-%m-%dT%H:%M:%S") if zoned.microsecond > 0: ms = zoned.strftime("%f") @@ -41,12 +41,12 @@ def parse_into_datetime(value): return value else: # Add a time component - return dt.datetime.combine(value, dt.time(), tzinfo=pytz.utc) + return dt.datetime.combine(value, dt.time(0, 0, tzinfo=pytz.utc)) # value isn't a date or datetime object so assume it's a string try: parsed = parser.parse(value) - except TypeError: + except (TypeError, ValueError): # Unknown format raise ValueError("must be a datetime object, date object, or " "timestamp string in a recognizable format.")