Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community!

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Stuck with Python timezone issue

I think half the problem is I'm not entirely sure what the end result it's expecting is - weather to use a pytz. notation approach or the .astimezone() approach (maybe neither?). But I'm stuck on this:

Create a function named to_timezone that takes a timezone name as a string. Convert starter to that timezone using pytz's timezones and return the new datetime.

Here's what I've got, which is obviously incorrect, and I've been stuck here for a few days:

import datetime

import pytz

starter = pytz.utc.localize(datetime.datetime(2015, 10, 21, 23, 29))

def to_timezone(new_timezone):
  starter.astimezone(new_timezone)
  return starter

Hi Chris,

Just fixed the formatting to help make it more readable. I haven't yet gotten to this step in Python, but I'm not far behind. I'll keep an eye on this thread and when I reach a point I can answer it, I'll do so if no one else has. This could take days - because, learning timezones is like running through mud for me.

1 Answer

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,332 Points

The Timezone Strings Challenge asks:

Create a function named to_timezone that takes a timezone name as a string. Convert starter to that timezone using pytz's timezones and return the new datetime.

The function will need to do three things: create a new timezone, create a new datetime object based on starter, and return the new datetime object. Here is one solution:

import datetime
import pytz

starter = pytz.utc.localize(datetime.datetime(2015, 10, 21, 23, 29))

def to_timezone(new_timezone):
  # generate timezone from string
  new_tz = pytz.timezone(new_timezone) 
  # convert starter to new datetime
  new_dt = starter.astimezone(new_tz) 
  # Return new datetime object
  return new_dt

The last two statement could be combined and return the new datetime directly:

  # Return new datetime object
  return starter.astimezone(new_tz) 

Of if you insist on approaching unreadable, you could do:

def to_timezone(new_timezone):
  return starter.astimezone( pytz.timezone(new_timezone) )

Thanks, that did the trick, and reading it makes total sense.

I'll really need to go back at some point and spend a lot more time here. Very frustrating stuff.

But a quick question: Why wouldn't it (or would it?) work to just skip creating new_dt and plug in the argument straight into the .astimezone part? If we assume the string is a timezone, why wouldn't it work to just say:

return starter.astimezone(string)?

Chris Freeman
Chris Freeman
Treehouse Moderator 68,332 Points

Chris White: While going straight to return starter.astimezone(string) looks inviting, it definately will not work! Coding would be a breeze if it did. Why? it's all about type.

Functions expect parameters of a specific object type: integer (int), string ('str'), etc. Some functions take other functions (as callable object) as parameters!

The function pytz.timezone() expects a string parameter and returns a timezone object. Whereas, starter is a "timzone aware" datetime object with an astimezone() method which expects a timezone object and returns and updated datetime object. Say THAT 10 times fast!

If you're unsure what is being produced by a statement, you can inspect the output using type() and dir(). Doing this on the above code yields this:

In [229]: import pytz
In [230]: import datetime
In [231]: starter = pytz.utc.localize(datetime.datetime(2015, 10, 21, 23, 29))
In [232]: new_tz = pytz.timezone('US/Eastern')
In [233]: type(new_tz)
Out[233]: pytz.tzfile.US/Eastern

In [234]: dir(new_tz)
Out[234]: 
['__class__',  '__delattr__',  '__dict__',  '__doc__',  '__format__',  '__getattribute__',  '__hash__',  '__init__',  '__module__',  '__new__',  '__reduce__',  '__reduce_ex__',  '__repr__',  '__setattr__',  '__sizeof__',  '__str__', '__subclasshook__',  '__weakref__',  '_dst',  '_transition_info',  '_tzinfos',  '_tzname',  '_utc_transition_times',  '_utcoffset',  'dst',  'fromutc',  'localize',  'normalize',  'tzname',  'utcoffset',  'zone']

In [235]: new_dt = starter.astimezone(new_tz) 
In [236]: type(new_dt)
Out[236]: datetime.datetime

In [237]: dir(new_dt)
Out[237]: 
['__add__',  '__class__',  '__delattr__',  '__doc__',  '__eq__',  '__format__',  '__ge__',  '__getattribute__',  '__gt__', '__hash__',  '__init__',  '__le__',  '__lt__',  '__ne__',  '__new__',  '__radd__',  '__reduce__',  '__reduce_ex__',  '__repr__',  '__rsub__',  '__setattr__',  '__sizeof__',  '__str__',  '__sub__',  '__subclasshook__',  'astimezone',  'combine',  'ctime',  'date',  'day',  'dst',  'fromordinal',  'fromtimestamp',  'hour',  'isocalendar',  'isoformat',  'isoweekday',  'max',  'microsecond', 'min',  'minute',  'month',  'now',  'replace',  'resolution',  'second',  'strftime',  'strptime',  'time',  'timetuple',  'timetz', 'today',  'toordinal',  'tzinfo',  'tzname',  'utcfromtimestamp',  'utcnow',  'utcoffset',  'utctimetuple',  'weekday',  'year']

For grins, let's try calling starter.astimezone() with a string argument:

In [238]: starter.astimezone('US/Eastern')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-238-d536f300de46> in <module>()
----> 1 starter.astimezone('US/Eastern')

TypeError: astimezone() argument 1 must be datetime.tzinfo, not str

As you can see, the astimezone() method does not care for a string input.