|
@@ -717,11 +717,17 @@ def safe_timestamp(item_timestamp_ns):
|
|
|
|
|
|
|
|
|
def format_time(t):
|
|
|
- """use ISO-8601 date and time format
|
|
|
+ """use ISO-8601-like date and time format (human readable, with wkday and blank date/time separator)
|
|
|
"""
|
|
|
return t.strftime('%a, %Y-%m-%d %H:%M:%S')
|
|
|
|
|
|
|
|
|
+def isoformat_time(t):
|
|
|
+ """use ISO-8601 date and time format (machine readable, no wkday, no microseconds either)
|
|
|
+ """
|
|
|
+ return t.strftime('%Y-%m-%dT%H:%M:%S') # note: first make all datetime objects tz aware before adding %z here.
|
|
|
+
|
|
|
+
|
|
|
def format_timedelta(td):
|
|
|
"""Format timedelta in a human friendly format
|
|
|
"""
|
|
@@ -1654,6 +1660,7 @@ class ArchiveFormatter(BaseFormatter):
|
|
|
if self.json:
|
|
|
self.item_data = {}
|
|
|
self.format_item = self.format_item_json
|
|
|
+ self.format_time = self.format_time_json
|
|
|
else:
|
|
|
self.item_data = static_keys
|
|
|
|
|
@@ -1670,8 +1677,8 @@ class ArchiveFormatter(BaseFormatter):
|
|
|
'archive': remove_surrogates(archive_info.name),
|
|
|
'barchive': archive_info.name,
|
|
|
'id': bin_to_hex(archive_info.id),
|
|
|
- 'time': format_time(to_localtime(archive_info.ts)),
|
|
|
- 'start': format_time(to_localtime(archive_info.ts)),
|
|
|
+ 'time': self.format_time(archive_info.ts),
|
|
|
+ 'start': self.format_time(archive_info.ts),
|
|
|
})
|
|
|
for key in self.used_call_keys:
|
|
|
item_data[key] = self.call_keys[key]()
|
|
@@ -1689,7 +1696,15 @@ class ArchiveFormatter(BaseFormatter):
|
|
|
return remove_surrogates(self.archive.comment) if rs else self.archive.comment
|
|
|
|
|
|
def get_ts_end(self):
|
|
|
- return format_time(to_localtime(self.archive.ts_end))
|
|
|
+ return self.format_time(self.archive.ts_end)
|
|
|
+
|
|
|
+ def format_time(self, ts):
|
|
|
+ t = to_localtime(ts)
|
|
|
+ return format_time(t)
|
|
|
+
|
|
|
+ def format_time_json(self, ts):
|
|
|
+ t = to_localtime(ts)
|
|
|
+ return isoformat_time(t)
|
|
|
|
|
|
|
|
|
class ItemFormatter(BaseFormatter):
|
|
@@ -1762,6 +1777,12 @@ class ItemFormatter(BaseFormatter):
|
|
|
'archiveid': archive.fpr,
|
|
|
}
|
|
|
static_keys.update(self.FIXED_KEYS)
|
|
|
+ if self.json_lines:
|
|
|
+ self.item_data = {}
|
|
|
+ self.format_item = self.format_item_json
|
|
|
+ self.format_time = self.format_time_json
|
|
|
+ else:
|
|
|
+ self.item_data = static_keys
|
|
|
self.format = partial_format(format, static_keys)
|
|
|
self.format_keys = {f[1] for f in Formatter().parse(format)}
|
|
|
self.call_keys = {
|
|
@@ -1781,11 +1802,6 @@ class ItemFormatter(BaseFormatter):
|
|
|
for hash_function in hashlib.algorithms_guaranteed:
|
|
|
self.add_key(hash_function, partial(self.hash_item, hash_function))
|
|
|
self.used_call_keys = set(self.call_keys) & self.format_keys
|
|
|
- if self.json_lines:
|
|
|
- self.item_data = {}
|
|
|
- self.format_item = self.format_item_json
|
|
|
- else:
|
|
|
- self.item_data = static_keys
|
|
|
|
|
|
def format_item_json(self, item):
|
|
|
return json.dumps(self.get_item_data(item)) + '\n'
|
|
@@ -1863,7 +1879,12 @@ class ItemFormatter(BaseFormatter):
|
|
|
return hash.hexdigest()
|
|
|
|
|
|
def format_time(self, key, item):
|
|
|
- return format_time(safe_timestamp(item.get(key) or item.mtime))
|
|
|
+ t = self.time(key, item)
|
|
|
+ return format_time(t)
|
|
|
+
|
|
|
+ def format_time_json(self, key, item):
|
|
|
+ t = self.time(key, item)
|
|
|
+ return isoformat_time(t)
|
|
|
|
|
|
def time(self, key, item):
|
|
|
return safe_timestamp(item.get(key) or item.mtime)
|
|
@@ -2191,7 +2212,7 @@ def basic_json_data(manifest, *, cache=None, extra=None):
|
|
|
'mode': key.ARG_NAME,
|
|
|
},
|
|
|
})
|
|
|
- data['repository']['last_modified'] = format_time(to_localtime(manifest.last_timestamp.replace(tzinfo=timezone.utc)))
|
|
|
+ data['repository']['last_modified'] = isoformat_time(to_localtime(manifest.last_timestamp.replace(tzinfo=timezone.utc)))
|
|
|
if key.NAME.startswith('key file'):
|
|
|
data['encryption']['keyfile'] = key.find_key()
|
|
|
if cache:
|