فهرست منبع

always use microseconds for ISO 8601 output

Marian Beermann 7 سال پیش
والد
کامیت
ab4981eff6
4فایلهای تغییر یافته به همراه26 افزوده شده و 21 حذف شده
  1. 11 11
      docs/internals/frontends.rst
  2. 1 1
      src/borg/helpers/parseformat.py
  3. 12 7
      src/borg/helpers/time.py
  4. 2 2
      src/borg/testsuite/archiver.py

+ 11 - 11
docs/internals/frontends.rst

@@ -209,9 +209,9 @@ Standard output
 *stdout* is different and more command-dependent than logging. Commands like :ref:`borg_info`, :ref:`borg_create`
 *stdout* is different and more command-dependent than logging. Commands like :ref:`borg_info`, :ref:`borg_create`
 and :ref:`borg_list` implement a ``--json`` option which turns their regular output into a single JSON object.
 and :ref:`borg_list` implement a ``--json`` option which turns their regular output into a single JSON object.
 
 
-Dates are formatted according to ISO-8601 in local time. Neither an explicit time zone nor microseconds
-are specified *at this time* (subject to change). The equivalent strftime format string is '%Y-%m-%dT%H:%M:%S',
-e.g. 2017-08-07T12:27:20.
+Dates are formatted according to ISO 8601 in local time. No explicit time zone is specified *at this time*
+(subject to change). The equivalent strftime format string is '%Y-%m-%dT%H:%M:%S.%f',
+e.g. ``2017-08-07T12:27:20.123456``.
 
 
 The root object at least contains a *repository* key with an object containing:
 The root object at least contains a *repository* key with an object containing:
 
 
@@ -268,7 +268,7 @@ Example *borg info* output::
         },
         },
         "repository": {
         "repository": {
             "id": "0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
             "id": "0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
-            "last_modified": "2017-08-07T12:27:20",
+            "last_modified": "2017-08-07T12:27:20.789123",
             "location": "/home/user/testrepo"
             "location": "/home/user/testrepo"
         },
         },
         "security_dir": "/home/user/.config/borg/security/0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
         "security_dir": "/home/user/.config/borg/security/0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
@@ -329,7 +329,7 @@ Example of a simple archive listing (``borg list --last 1 --json``)::
             {
             {
                 "id": "80cd07219ad725b3c5f665c1dcf119435c4dee1647a560ecac30f8d40221a46a",
                 "id": "80cd07219ad725b3c5f665c1dcf119435c4dee1647a560ecac30f8d40221a46a",
                 "name": "host-system-backup-2017-02-27",
                 "name": "host-system-backup-2017-02-27",
-                "start": "2017-08-07T12:27:20"
+                "start": "2017-08-07T12:27:20.789123"
             }
             }
         ],
         ],
         "encryption": {
         "encryption": {
@@ -337,7 +337,7 @@ Example of a simple archive listing (``borg list --last 1 --json``)::
         },
         },
         "repository": {
         "repository": {
             "id": "0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
             "id": "0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
-            "last_modified": "2017-08-07T12:27:20",
+            "last_modified": "2017-08-07T12:27:20.789123",
             "location": "/home/user/repository"
             "location": "/home/user/repository"
         }
         }
     }
     }
@@ -355,14 +355,14 @@ The same archive with more information (``borg info --last 1 --json``)::
                 ],
                 ],
                 "comment": "",
                 "comment": "",
                 "duration": 5.641542,
                 "duration": 5.641542,
-                "end": "2017-02-27T12:27:20",
+                "end": "2017-02-27T12:27:20.789123",
                 "hostname": "host",
                 "hostname": "host",
                 "id": "80cd07219ad725b3c5f665c1dcf119435c4dee1647a560ecac30f8d40221a46a",
                 "id": "80cd07219ad725b3c5f665c1dcf119435c4dee1647a560ecac30f8d40221a46a",
                 "limits": {
                 "limits": {
                     "max_archive_size": 0.0001330855110409714
                     "max_archive_size": 0.0001330855110409714
                 },
                 },
                 "name": "host-system-backup-2017-02-27",
                 "name": "host-system-backup-2017-02-27",
-                "start": "2017-02-27T12:27:20",
+                "start": "2017-02-27T12:27:20.789123",
                 "stats": {
                 "stats": {
                     "compressed_size": 1880961894,
                     "compressed_size": 1880961894,
                     "deduplicated_size": 2791,
                     "deduplicated_size": 2791,
@@ -388,7 +388,7 @@ The same archive with more information (``borg info --last 1 --json``)::
         },
         },
         "repository": {
         "repository": {
             "id": "0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
             "id": "0cbe6166b46627fd26b97f8831e2ca97584280a46714ef84d2b668daf8271a23",
-            "last_modified": "2017-08-07T12:27:20",
+            "last_modified": "2017-08-07T12:27:20.789123",
             "location": "/home/user/repository"
             "location": "/home/user/repository"
         }
         }
     }
     }
@@ -406,8 +406,8 @@ Refer to the *borg list* documentation for the available keys and their meaning.
 
 
 Example (excerpt) of ``borg list --json-lines``::
 Example (excerpt) of ``borg list --json-lines``::
 
 
-    {"type": "d", "mode": "drwxr-xr-x", "user": "user", "group": "user", "uid": 1000, "gid": 1000, "path": "linux", "healthy": true, "source": "", "linktarget": "", "flags": null, "isomtime": "2017-02-27T12:27:20", "size": 0}
-    {"type": "d", "mode": "drwxr-xr-x", "user": "user", "group": "user", "uid": 1000, "gid": 1000, "path": "linux/baz", "healthy": true, "source": "", "linktarget": "", "flags": null, "isomtime": "2017-02-27T12:27:20", "size": 0}
+    {"type": "d", "mode": "drwxr-xr-x", "user": "user", "group": "user", "uid": 1000, "gid": 1000, "path": "linux", "healthy": true, "source": "", "linktarget": "", "flags": null, "mtime": "2017-02-27T12:27:20.023407", "size": 0}
+    {"type": "d", "mode": "drwxr-xr-x", "user": "user", "group": "user", "uid": 1000, "gid": 1000, "path": "linux/baz", "healthy": true, "source": "", "linktarget": "", "flags": null, "mtime": "2017-02-27T12:27:20.585407", "size": 0}
 
 
 .. _msgid:
 .. _msgid:
 
 

+ 1 - 1
src/borg/helpers/parseformat.py

@@ -764,7 +764,7 @@ class ItemFormatter(BaseFormatter):
         return OutputTimestamp(safe_timestamp(item.get(key) or item.mtime))
         return OutputTimestamp(safe_timestamp(item.get(key) or item.mtime))
 
 
     def format_iso_time(self, key, item):
     def format_iso_time(self, key, item):
-        return self.format_time(key, item).to_json()
+        return self.format_time(key, item).isoformat()
 
 
 
 
 def file_status(mode):
 def file_status(mode):

+ 12 - 7
src/borg/helpers/time.py

@@ -86,16 +86,19 @@ def safe_timestamp(item_timestamp_ns):
     return datetime.fromtimestamp(t_ns / 1e9)
     return datetime.fromtimestamp(t_ns / 1e9)
 
 
 
 
-def format_time(t):
-    """use ISO-8601-like date and time format (human readable, with wkday and blank date/time separator)
+def format_time(ts: datetime):
     """
     """
-    return t.strftime('%a, %Y-%m-%d %H:%M:%S')
+    Convert *ts* to a human-friendly format with textual weekday.
+    """
+    return ts.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)
+def isoformat_time(ts: datetime):
+    """
+    Format *ts* according to ISO 8601.
     """
     """
-    return t.strftime('%Y-%m-%dT%H:%M:%S')  # note: first make all datetime objects tz aware before adding %z here.
+    # note: first make all datetime objects tz aware before adding %z here.
+    return ts.strftime('%Y-%m-%dT%H:%M:%S.%f')
 
 
 
 
 def format_timedelta(td):
 def format_timedelta(td):
@@ -127,5 +130,7 @@ class OutputTimestamp:
     def __str__(self):
     def __str__(self):
         return '{}'.format(self)
         return '{}'.format(self)
 
 
-    def to_json(self):
+    def isoformat(self):
         return isoformat_time(self.ts)
         return isoformat_time(self.ts)
+
+    to_json = isoformat

+ 2 - 2
src/borg/testsuite/archiver.py

@@ -61,7 +61,7 @@ from . import key
 
 
 src_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
 src_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
 
 
-ISO_FORMAT = '%Y-%m-%dT%H:%M:%S'
+ISO_FORMAT = '%Y-%m-%dT%H:%M:%S.%f'
 
 
 
 
 def exec_cmd(*args, archiver=None, fork=False, exe=None, input=b'', binary_output=False, **kw):
 def exec_cmd(*args, archiver=None, fork=False, exe=None, input=b'', binary_output=False, **kw):
@@ -1864,7 +1864,7 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         file1 = items[1]
         file1 = items[1]
         assert file1['path'] == 'input/file1'
         assert file1['path'] == 'input/file1'
         assert file1['size'] == 81920
         assert file1['size'] == 81920
-        assert datetime.strptime(file1['isomtime'], ISO_FORMAT)  # must not raise
+        assert datetime.strptime(file1['mtime'], ISO_FORMAT)  # must not raise
 
 
         list_archive = self.cmd('list', '--json-lines', '--format={sha256}', self.repository_location + '::test')
         list_archive = self.cmd('list', '--json-lines', '--format={sha256}', self.repository_location + '::test')
         items = [json.loads(s) for s in list_archive.splitlines()]
         items = [json.loads(s) for s in list_archive.splitlines()]