Search code examples
pythonpyside6qdatetime

Is it possible to convert from QDateTime to python datetime without loosing timezone?


I am trying to convert a QDateTime object in pyside6 to a python datetime object. Consider the following code:

from PySide6.QtCore import Qt, QDateTime, QTimeZone
import datetime

qdatetime = QDateTime.currentDateTime()
print(qdatetime.offsetFromUtc())
qdatetime.setTimeZone(QTimeZone.UTC)
print(qdatetime.toString(Qt.ISODate))
print(qdatetime.offsetFromUtc())
pt = qdatetime.toPython()
print(pt)
print(pt.tzinfo)
ptt = pt.replace(tzinfo = datetime.timezone.utc)
print(ptt.tzinfo)
print(ptt)

The output looks like this:

3600
2025-01-06T18:56:43Z
0
2025-01-06 18:56:43.251000
None
UTC
2025-01-06 18:56:43.251000+00:00

Obviously I can attach a timezone both to the QDateTime object and the python datetime object. The conversion however seems to delete the timezone information. The workaround would be to reattach the timezone after conversion. This seems like a complicated way to do this. Is there a way to convert without loosing timezone in the first place?


Solution

  • The toPython() function of PySide originates from the original toPyDateTime() function of PyQt4, and at that time the QDateTime class didn't provide time zone information.

    The behavior wasn't changed even with the more recent PyQt5/6 implementation, which wasn't updated to reflect the time zone info introduced since Qt 5.2.

    For various reasons, including the different implementation between Qt and Python, that was probably not implemented as a choice, and I sincerely doubt it will. Those helper functions were intended for simple cases, and more complex situation may require custom implementation.

    One way to properly convert the QDateTime while preserving the offset could be to just use the explicit date time string for datetime.fromisoformat() and adding the UTC offset from the original QDateTime:

    from PyQt6.QtCore import QDateTime
    from datetime import datetime
    
    def datetimeQt2Py(qDateTime):
        s = qDateTime.offsetFromUtc()
        if not s:
            return datetime.fromisoformat(
                qDateTime.toString(Qt.DateFormat.ISODate))
        sign = '+' if s > 0 else '-'
        s = abs(s)
        h = m = 0
        if s >= 60:
            m = s // 60
            s %= 60
            if m >= 60:
                h = m // 60
                m %= 60
        return datetime.fromisoformat(qDateTime.toUTC().toString(
            f'yyyy-MM-ddTHH:mm:ss{sign}{h:02}:{m:02}:{s:02}'))
    
    now = QDateTime.currentDateTime()
    dt = datetimeQt2Py(now)
    print(now)
    print(dt)
    print(dt.tzinfo)
    

    The above will obviously not preserve the time zone name, nor any DST information. All that could be achieved by dynamically creating datetime.tzinfo objects.