pythonのdatetimeのtimezone

pythonのdatetimeモジュールはタイムゾーンがない文字列から生成した場合、ローカルタイムとして扱われる

from datetime import datetime, timezone

print(datetime.now())

dt_rfc3339 = datetime.fromisoformat("2021-03-19T11:30:00+00:00")
print("dt_rfc3339: ", dt_rfc3339, dt_rfc3339.tzinfo)


dt = datetime.fromisoformat("2021-03-19T11:30:00")
print("dt_no_tz:   ", dt, dt.tzinfo)

dt_replace_utc = dt.replace(tzinfo=timezone.utc)

print("replace:    ", dt_replace_utc, dt_replace_utc.tzinfo)

dt_astimezone = dt.astimezone(tz=timezone.utc)
print("astimezone: ", dt_astimezone, dt_astimezone.tzinfo)

実行結果

dt_rfc3339:  2021-03-19 11:30:00+00:00 UTC
dt_no_tz:    2021-03-19 11:30:00 None
replace:     2021-03-19 11:30:00+00:00 UTC
astimezone:  2021-03-19 02:30:00+00:00 UTC # astimezoneを使用するとtimezone(JSTで9時間)分ずれてしまう

RDBにおいてDATETIME型として保存されているものでタイムゾーンが含まれないが、

内部でUTCとして扱っている場合、replace(tzinfo=datetime.timezone.utc)を使用してUTCに変換すると良い。

code

github.com

    def astimezone(self, tz=None):
        if tz is None:
            tz = self._local_timezone()
        elif not isinstance(tz, tzinfo):
            raise TypeError("tz argument must be an instance of tzinfo")

        mytz = self.tzinfo
        if mytz is None:
            mytz = self._local_timezone()
            myoffset = mytz.utcoffset(self)
        else:
            myoffset = mytz.utcoffset(self)
            if myoffset is None:
                mytz = self.replace(tzinfo=None)._local_timezone()
                myoffset = mytz.utcoffset(self)

        if tz is mytz:
            return self

        # Convert self to UTC, and attach the new time zone object.
        utc = (self - myoffset).replace(tzinfo=tz)

        # Convert from UTC to tz's local time.
        return tz.fromutc(utc)
   def replace(self, year=None, month=None, day=None, hour=None,
                minute=None, second=None, microsecond=None, tzinfo=True,
                *, fold=None):
        """Return a new datetime with new values for the specified fields."""
        if year is None:
            year = self.year
        if month is None:
            month = self.month
        if day is None:
            day = self.day
        if hour is None:
            hour = self.hour
        if minute is None:
            minute = self.minute
        if second is None:
            second = self.second
        if microsecond is None:
            microsecond = self.microsecond
        if tzinfo is True:
            tzinfo = self.tzinfo
        if fold is None:
            fold = self.fold
        return type(self)(year, month, day, hour, minute, second,
                          microsecond, tzinfo, fold=fold)

環境

python-3.8.2