bonbon.langes
bonbon.langes

Reputation: 1818

python timezone conversion issues using pytz

I'm using pytz to do datetime conversions but on cases where it's about 8AM EST DST active, pytz shows unexpected data.

eight_35 = datetime.now(pytz.timezone('US/Eastern')) # assume today's 8:35AM EST
eight_am = datetime(eight_35.year, eight_35.month, eight_35.day, 8, 0, 0, 0, tzinfo=pytz.timezone('US/Eastern'))

I noticed though that eight_35 has tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST> while eight_am has tzinfo=<DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD> and I'm not sure which one is the right one.

If I do conversions to UTC, I get the following results:

eight_35.astimezone(pytz.utc) >>> 12:35PM UTC
eight_am.astimezone(pytz.utc) >>> 12:56PM UTC

My code supposedly checks if the user already logged in anything greater than 8AM EST. Django does the conversions to UTC automatically when creating querysets.

UserLoginLog.objects.create(user=user, date_login=now) date logged is 12:35PM UTC

# this will result in no items because eight_am is translated as 12:56PM
UserLoginLog.objects.filter(user=user, date_login__gte=eight_am)

As you can see, user logged in 8:35AM so if I get all logs after 8AM What's the best way to deal with it so I can detect Daylight Saving Time but still be able to accurately compare data?

Upvotes: 2

Views: 1535

Answers (2)

bonbon.langes
bonbon.langes

Reputation: 1818

you guys are all helpful! so what i did was to make something like

@staticmethod
def est_localize(datetime_object):
    # remove tzinfo
    new_datetime = datetime_object.replace(tzinfo=None)
    # finally, localize the datetime
    new_datetime = pytz.timezone('US/Eastern').localize(new_datetime)
    return new_datetime

and every datetime objects i create, i wrap them all inside est_localize(), including the ones where I have to use +timedelta() and +relativedelta(). all are translated correctly as long as i wrap them inside est_localize(). thanks all!

eight_35 = datetime.now(pytz.timezone('US/Eastern')) # assume today's 8:35AM EST
eight_am = est_localize(datetime(eight_35.year, eight_35.month, eight_35.day, 8))

Upvotes: 0

jfs
jfs

Reputation: 414215

  • datetime.now(pytz.timezone('US/Eastern')) -- correct
  • datetime(..same time.., tzinfo=pytz.timezone('US/Eastern')) -- incorrect

See this answer on why you should not use tzinfo parameter with pytz timezones that may have different utc offsets at different times.

.now(tz) uses UTC time internally (tz.fromutc(utc_time)) and therefore it allows the timezone to choose the correct utc offset that corresponds to the given time.

If you change an aware datetime object (so that the resulting time might have a different utc offset) then you should call dt = tz.normalize(dt) to get the correct tzinfo. See Localized times and date arithmetic.

Upvotes: 2

Related Questions