pylover / khayyam

A Persian Date & Time (aka: Jalali Calendar) library with timezone, DST (daylight-saving), full formatting & parsing support for python 2.x & 3.x.
http://khayyam.dobisel.com
GNU General Public License v3.0
140 stars 22 forks source link

DST Conflict #39

Open kooshan75 opened 1 year ago

kooshan75 commented 1 year ago

Since the general policy for Daylight saving time in Iran has been revoked, using TehranTimezone() function will return an incorrect answer starting 1/1/1402.

class TehranTimezone(Timezone):
    """
    Tehran timezone with DST.
    """
    dst_start = (1, 1)
    dst_end = (7, 1)

    def __init__(self):
        super(TehranTimezone, self).__init__(
            timedelta(minutes=210),
            timedelta(minutes=60),
            lambda dt: (self.dst_start[0] < dt.month < self.dst_end[0]) or
                       (self.dst_start[0] == dt.month and self.dst_start[1] <= dt.day) or
                       (self.dst_end[0] == dt.month and self.dst_end[1] > dt.day),
            'Iran/Tehran'
        )

timezones.py needs to be adjusted with the new policy.

So I suggest the following code for timezones.py:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from datetime import tzinfo, timedelta
from khayyam.helpers import force_encoded_string_output
__author__ = 'vahid'

ZERO_DELTA = timedelta(0)
TEHRAN_OFFSET = timedelta(minutes=210)

class Timezone(tzinfo):

    def __init__(self, offset, name=None):
        assert (isinstance(offset, timedelta))
        self._offset = offset
        self._name = name
        super(Timezone, self).__init__()

    def fromutc(self, dt):
        if dt.tzinfo is None:
            raise ValueError('The object: %s is naive.' % dt)

        if dt.tzinfo != self:
            raise ValueError('Datetime timezone mismatch: %s != %s' % (dt.tzinfo, self))

        utc_offset = dt.utcoffset()
        delta = utc_offset

        if delta:
            dt += delta  # convert to standard local time

        return dt

    def utcoffset(self, dt):
        return self._offset

    def dst(self, dt):
        return ZERO_DELTA

    def __unicode__(self):
        off = self._offset
        return '%s%.2d:%.2d' % (
            '+' if off.total_seconds() >= 0 else '-',
            int(off.total_seconds() / 3600),
            int((off.total_seconds() % 3600) / 60),
        )

    __repr__ = force_encoded_string_output(__unicode__)

    def tzname(self, dt):
        if self._name:
            return self._name
        else:
            return repr(self)

    def __hash__(self):
        return hash(self._offset)

class TehranTimezone(Timezone):
    """
    Tehran timezone with a fixed +3:30 GMT offset.
    """

    def __init__(self):
        super(TehranTimezone, self).__init__(
            timedelta(minutes=210),
            'Iran/Tehran'
        )

In this modification, I removed the _dst_offset, _dst_checker, dst_start, and dst_end variables, as well as the _is_dst method. I also updated the TehranTimezone class's init method to only include the fixed offset and the timezone name. I can also make a pull request to your repository if you are willing to.

kooshan75 commented 1 year ago

Is there anyone maintaining this project anymore? @pylover @aida-mirabadi @fouladi @siminbar anyone?