-2

I have a string time coming from a third party (external to my python program), and I need to compare that time to right now. How long ago was that time?

How can I do this?

I've looked at the datetime and time libraries, as well as pytz, and can't find an obvious way to do this. It should automatically incorporate DST because the third party doesn't explicitly state its offset, only the timezone (US/Eastern).

I've tried this, and it fails:

dt = datetime.datetime.strptime('June 10, 2016 12:00PM', '%B %d, %Y %I:%M%p')
dtEt = dt.replace(tzinfo=pytz.timezone('US/Eastern'))
now = datetime.datetime.now()

now - dtEt 

TypeError: can't subtract offset-naive and offset-aware datetimes

Zack Coburn
  • 109
  • 3

2 Answers2

0

Good question Zack! I've had this problem myself.

Here's some code to do so:

from datetime import datetime
import time
import calendar
import pytz

def howLongAgo(thirdPartyString, timeFmt):
  # seconds since epoch
  thirdPartySeconds = calendar.timegm(time.strptime(thirdPartyString, timeFmt))
  nowSecondsUTC = time.time()

  # hour difference with DST
  nowEastern = datetime.now(pytz.timezone('US/Eastern'))
  nowUTC = datetime.now(pytz.timezone('UTC'))
  timezoneOffset = (nowEastern.day - nowUTC.day)*24 + (nowEastern.hour - nowUTC.hour) + (nowEastern.minute - nowUTC.minute)/60.0

  thirdPartySecondsUTC = thirdPartySeconds - (timezoneOffset * 60 * 60)
  return nowSecondsUTC - thirdPartySecondsUTC

howLongAgo('June 09, 2016 at 06:22PM', '%B %d, %Y at %I:%M%p') 
# first argument always provided in ET, either EDT or EST
skier31415
  • 121
  • 5
  • Thanks, that's exactly what I was looking for. Now my thermostat will maintain the perfect temperature! – Zack Coburn Jun 09 '16 at 22:32
  • 1- your answer assumes that US/Eastern has a constant utc offset—it is incorrect 2- if you know that the input time is in US/Eastern timezone then use `(datetime.now(pytz.utc) - pytz.timezone('US/Eastern').localize(datetime.strptime(thirdPartyString, timeFmt), is_dst=None)).total_seconds()` to find the difference in seconds. – jfs Jun 10 '16 at 15:00
  • Localize is definitely a better answer, may have to do some error handling for the one hour / year that is ambiguously defined (when DST actually occurs). My solution assumes that the difference between Eastern and UTC is the same for "now" and the `thirdParty` time (so it won't work for a time six months ago). – skier31415 Jun 11 '16 at 02:24
  • `is_dst` parameter handles ambiguous and non-existent times. In particular, `is_dst=None` raises an exception in such cases (you can choose a different error handling strategy more suitable for your specific application). – jfs Jun 13 '16 at 01:08
0

TypeError: can't subtract offset-naive and offset-aware datetimes

To fix the TypeError, use timezone aware datetime objects:

#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz
tz = pytz.timezone('US/Eastern')

now = datetime.now(tz) # the current time (it works even during DST transitions)
then_naive = datetime.strptime('June 10, 2016 12:00PM', '%B %d, %Y %I:%M%p')
then = tz.localize(then_naive, is_dst=None) 
time_difference_in_seconds = (now - then).total_seconds()

is_dst=None causes an exception for ambiguous/non-existing times. You could also use is_dst=False (default) or is_dst=True, see python converting string in localtime to UTC epoch timestamp.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670