diff --git a/Whatsapp_Chat_Exporter/__main__.py b/Whatsapp_Chat_Exporter/__main__.py index aeac9d5..d9ff970 100644 --- a/Whatsapp_Chat_Exporter/__main__.py +++ b/Whatsapp_Chat_Exporter/__main__.py @@ -198,6 +198,14 @@ def main(): default=None, help="Path to contact database in crypt15 format" ) + parser.add_argument( + "--time-offset", + dest="timezone_offset", + default=0, + type=int, + choices=range(-12, 15), + help="Offset in hours (-12 to 14) for time displayed in the output" + ) args = parser.parse_args() # Check for updates @@ -328,11 +336,11 @@ def main(): if os.path.isfile(msg_db): with sqlite3.connect(msg_db) as db: db.row_factory = sqlite3.Row - messages(db, data, args.media) + messages(db, data, args.media, args.timezone_offset) media(db, data, args.media) vcard(db, data, args.media) if args.android: - extract.calls(db, data) + extract.calls(db, data, args.timezone_offset) if not args.no_html: create_html( data, diff --git a/Whatsapp_Chat_Exporter/data_model.py b/Whatsapp_Chat_Exporter/data_model.py index 926acaf..d7d678b 100644 --- a/Whatsapp_Chat_Exporter/data_model.py +++ b/Whatsapp_Chat_Exporter/data_model.py @@ -1,10 +1,19 @@ #!/usr/bin/python3 import os -from datetime import datetime +from datetime import datetime, tzinfo, timedelta from typing import Union +class TimeZone(tzinfo): + def __init__(self, offset): + self.offset = offset + def utcoffset(self, dt): + return timedelta(hours=self.offset) + def dst(self, dt): + return timedelta(0) + + class ChatStore(): def __init__(self, type, name=None, media=None): if name is not None and not isinstance(name, str): @@ -55,11 +64,11 @@ class ChatStore(): class Message(): - def __init__(self, from_me: Union[bool,int], timestamp: int, time: Union[int,float,str], key_id: int): + def __init__(self, from_me: Union[bool,int], timestamp: int, time: Union[int,float,str], key_id: int, timezone_offset: int = 0): self.from_me = bool(from_me) self.timestamp = timestamp / 1000 if timestamp > 9999999999 else timestamp if isinstance(time, int) or isinstance(time, float): - self.time = datetime.fromtimestamp(timestamp).strftime("%H:%M") + self.time = datetime.fromtimestamp(timestamp, TimeZone(timezone_offset)).strftime("%H:%M") elif isinstance(time, str): self.time = time else: diff --git a/Whatsapp_Chat_Exporter/extract.py b/Whatsapp_Chat_Exporter/extract.py index 5cbe5dd..3520c5d 100644 --- a/Whatsapp_Chat_Exporter/extract.py +++ b/Whatsapp_Chat_Exporter/extract.py @@ -165,7 +165,7 @@ def contacts(db, data): row = c.fetchone() -def messages(db, data, media_folder): +def messages(db, data, media_folder, timezone_offset): # Get message history c = db.cursor() try: @@ -320,6 +320,7 @@ def messages(db, data, media_folder): timestamp=content["timestamp"], time=content["timestamp"], key_id=content["key_id"], + timezone_offset=timezone_offset ) if isinstance(content["data"], bytes): message.data = ("The message is binary data and its base64 is " @@ -595,7 +596,7 @@ def vcard(db, data, media_folder): print(f"Processing vCards...({index + 1}/{total_row_number})", end="\r") -def calls(db, data): +def calls(db, data, timezone_offset): c = db.cursor() c.execute("""SELECT count() FROM call_log""") total_row_number = c.fetchone()[0] @@ -626,6 +627,7 @@ def calls(db, data): timestamp=content["timestamp"], time=content["timestamp"], key_id=content["call_id"], + timezone_offset=timezone_offset ) _jid = content["raw_string"] name = data[_jid].name if _jid in data else content["chat_subject"] or None diff --git a/Whatsapp_Chat_Exporter/extract_iphone.py b/Whatsapp_Chat_Exporter/extract_iphone.py index c89bbe9..a71e7fb 100644 --- a/Whatsapp_Chat_Exporter/extract_iphone.py +++ b/Whatsapp_Chat_Exporter/extract_iphone.py @@ -24,7 +24,7 @@ def contacts(db, data): content = c.fetchone() -def messages(db, data, media_folder): +def messages(db, data, media_folder, timezone_offset): c = db.cursor() # Get contacts c.execute("""SELECT count() FROM ZWACHATSESSION""") @@ -110,6 +110,7 @@ def messages(db, data, media_folder): timestamp=ts, time=ts, # TODO: Could be bug key_id=content["ZSTANZAID"][:17], + timezone_offset=timezone_offset ) invalid = False if is_group_message and content["ZISFROMME"] == 0: