diff --git a/evernote_backup/note_formatter_util.py b/evernote_backup/note_formatter_util.py
index f6e81db..12b1097 100644
--- a/evernote_backup/note_formatter_util.py
+++ b/evernote_backup/note_formatter_util.py
@@ -1,6 +1,6 @@
import base64
import sys
-from datetime import datetime
+from datetime import datetime, timedelta
from typing import Optional
@@ -10,12 +10,15 @@ def fmt_time(timestamp: Optional[int]) -> Optional[str]:
timestamp //= 1000
- if timestamp < _get_max_timestamp():
- date = datetime.utcfromtimestamp(timestamp)
- else:
+ # https://dev.evernote.com/doc/reference/Types.html#Typedef_Timestamp
+ if timestamp < 0:
+ date = _date_from_past(timestamp)
+ elif timestamp >= _get_max_timestamp():
date = _date_from_future(timestamp)
+ else:
+ date = datetime.utcfromtimestamp(timestamp)
- return date.strftime("%Y%m%dT%H%M%SZ")
+ return date.strftime(f"{date.year:04}%m%dT%H%M%SZ")
def fmt_binary(binary_data: bytes) -> str:
@@ -80,13 +83,23 @@ def _date_from_future(timestamp: int) -> datetime: # noqa: WPS210
m = mp + (3 if mp < 10 else -9)
y += m <= 2
- day_time = datetime.utcfromtimestamp(timestamp % 86400)
+ try:
+ day_time = datetime.utcfromtimestamp(timestamp % 86400)
+
+ return datetime(
+ year=y,
+ month=m,
+ day=d,
+ hour=day_time.hour,
+ minute=day_time.minute,
+ second=day_time.second,
+ )
+ except (OverflowError, ValueError, OSError):
+ return datetime.max
- return datetime(
- year=y,
- month=m,
- day=d,
- hour=day_time.hour,
- minute=day_time.minute,
- second=day_time.second,
- )
+
+def _date_from_past(timestamp: int) -> datetime:
+ try:
+ return datetime.utcfromtimestamp(0) - timedelta(seconds=abs(timestamp))
+ except (OverflowError, ValueError, OSError):
+ return datetime.min
diff --git a/tests/test_note_formatter.py b/tests/test_note_formatter.py
index 3dd6ac5..ff3e763 100644
--- a/tests/test_note_formatter.py
+++ b/tests/test_note_formatter.py
@@ -168,7 +168,8 @@ def test_note_from_future(mocker):
formatter = NoteFormatter()
# 9999-12-31 23:59:59
- end_of_times = 253402300799999
+ end_of_times_bad = 999999999999999
+ end_of_times = 243402300799999
# Emulate windows limit
mock_timestamp = mocker.patch(
@@ -178,11 +179,29 @@ def test_note_from_future(mocker):
note_from_future = Note(
title="test",
- created=end_of_times,
+ created=end_of_times_bad,
updated=end_of_times,
)
formatted_note = formatter.format_note(note_from_future)
assert "99991231T235959Z" in formatted_note
- assert "99991231T235959Z" in formatted_note
+ assert "96830210T061319Z" in formatted_note
+
+
+def test_note_from_past(mocker):
+ formatter = NoteFormatter()
+
+ before_times_bad = -999999999999999
+ before_times = -50000000000000
+
+ note_from_future = Note(
+ title="test",
+ created=before_times_bad,
+ updated=before_times,
+ )
+
+ formatted_note = formatter.format_note(note_from_future)
+
+ assert "00010101T000000Z" in formatted_note
+ assert "03850725T070640Z" in formatted_note