| 
					
				 | 
			
			
				@@ -18,7 +18,7 @@ logger = create_logger() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .errors import Error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .fs import get_keys_dir 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from .time import format_time, isoformat_time, to_localtime, safe_timestamp, safe_s 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from .time import OutputTimestamp, format_time, to_localtime, safe_timestamp, safe_s 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .usergroup import uid2user 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .. import __version__ as borg_version 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .. import __version_tuple__ as borg_version_tuple 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -549,12 +549,11 @@ 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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def format_item_json(self, item): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return json.dumps(self.get_item_data(item)) + '\n' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return json.dumps(self.get_item_data(item), cls=BorgJsonEncoder) + '\n' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def get_item_data(self, archive_info): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.name = archive_info.name 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -588,12 +587,7 @@ class ArchiveFormatter(BaseFormatter): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         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) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return OutputTimestamp(ts) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class ItemFormatter(BaseFormatter): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -669,7 +663,6 @@ class ItemFormatter(BaseFormatter): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         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) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -681,19 +674,19 @@ class ItemFormatter(BaseFormatter): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             'dcsize': partial(self.sum_unique_chunks_metadata, lambda chunk: chunk.csize), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             'num_chunks': self.calculate_num_chunks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             'unique_chunks': partial(self.sum_unique_chunks_metadata, lambda chunk: 1), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'isomtime': partial(self.format_time, 'mtime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'isoctime': partial(self.format_time, 'ctime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'isoatime': partial(self.format_time, 'atime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'mtime': partial(self.time, 'mtime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'ctime': partial(self.time, 'ctime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            'atime': partial(self.time, 'atime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            'isomtime': partial(self.format_iso_time, 'mtime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            'isoctime': partial(self.format_iso_time, 'ctime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            'isoatime': partial(self.format_iso_time, 'atime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            'mtime': partial(self.format_time, 'mtime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            'ctime': partial(self.format_time, 'ctime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            'atime': partial(self.format_time, 'atime'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def format_item_json(self, item): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return json.dumps(self.get_item_data(item)) + '\n' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return json.dumps(self.get_item_data(item), cls=BorgJsonEncoder) + '\n' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def add_key(self, key, callable_with_item): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.call_keys[key] = callable_with_item 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -768,15 +761,10 @@ class ItemFormatter(BaseFormatter): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return hash.hexdigest() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def format_time(self, key, item): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        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) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return OutputTimestamp(safe_timestamp(item.get(key) or item.mtime)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    def time(self, key, item): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return safe_timestamp(item.get(key) or item.mtime) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def format_iso_time(self, key, item): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return self.format_time(key, item).isoformat() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 def file_status(mode): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -887,6 +875,8 @@ class BorgJsonEncoder(json.JSONEncoder): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 'stats': o.stats(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if callable(getattr(o, 'to_json', None)): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return o.to_json() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return super().default(o) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -899,7 +889,7 @@ def basic_json_data(manifest, *, cache=None, extra=None): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             'mode': key.ARG_NAME, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    data['repository']['last_modified'] = isoformat_time(to_localtime(manifest.last_timestamp.replace(tzinfo=timezone.utc))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    data['repository']['last_modified'] = OutputTimestamp(manifest.last_timestamp.replace(tzinfo=timezone.utc)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if key.NAME.startswith('key file'): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         data['encryption']['keyfile'] = key.find_key() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if cache: 
			 |