Python - Convert time to different time zone with am/pm
Question: In Python, using this function (takes Eastern Standard Time (EST) with am/pm,
should output it in 3 time formats. Central Time (CT), Mountain Time(MT), and
Pacific Time(PT) all in the correct am/pm):

    
    
    def time_in_24h(time,time_day): #time is eastern time
    ''' (number, str)--> number
    This function converts a 12-hour time, represented by am/pm,to its equivalent 24-hour time. 
    Returns time in the 24-hour format.
    '''
    cCentral = 'Central Time(CT)' #-1 hour offset
    mMountain = 'Mountain Time(MT)'#-2 hours offset
    pPacific = 'Pacific Time(PT)'#-3 hours offset
    eEst = 'EST is'
    
    if time_day!='pm' and time_day!='am':
    
        print('Input is not in the right format')  #this is where input is not in the right format
        return 0
    
    else:
        print(time, time_day, eEst, time-1, cCentral)
        print(time, time_day, eEst, time-2, mMountain)
        print(time, time_day, eEst, time-3, pPacific)
    

Using this command:

    
    
    time_in_24h(7,'am')
    

I get this output:

    
    
    7 am EST is 6 Central Time(CT)
    7 am EST is 5 Mountain Time(MT)
    7 am EST is 4 Pacific Time(PT)
    

I am trying to output the correct 3 times based on the input of EST,am/pm to
Central Time (CT), Mountain Time(MT), and Pacific Time(PT) all in the correct
am/pm. How can I get the correct am/pm outputted based on the offsets? For
example, 2pm EST input, should output:

    
    
    1 pm EST is 12 pm Central Time(CT)
    1 pm EST is 11 am Mountain Time(MT)
    1 pm EST is 10 am Pacific Time(PT)
    

As you see, pm/am change based on the offsets and it is not consistent. What
would be the best way to handle this as it varies based on the time (am/pm)?
Anything built in python already to handle this without an issue? Any solution
to my dilemma? I gave it my all and really stuck on this one.


Answer: If you are talking about timezones then you must specify a date (year, month,
day) in addition to the time.

To convert given `hours` and `am_or_pm` to a different timezone:

  1. convert to 24 hours
  2. add date
  3. create timezone-aware datetime object in the source timezone
  4. convert it to the given timezones

`time_in_24h` shouldn't try to do too much. Let it do what its name implies,
namely: convert input hours, am or pm to 24 hours format:

    
    
    def time_in_24h(hours, am_or_pm):
        """Convert to 24 hours."""
        if not (1 <= hours <= 12):
            raise ValueError("hours must be in 01,..,12 range, got %r" % (hours,))
        hours %= 12 # accept 12am as 00, and 12pm as 12
        am_or_pm = am_or_pm.lower()
        if am_or_pm == 'am':
            pass
        elif am_or_pm == 'pm':
            hours += 12
        else:
            raise ValueError("am_or_pm must be 'am' or 'pm', got: %r" % (am_or_pm,))
        return hours
    

You could also implement it using `strptime()`:

    
    
    from datetime import datetime
    
    def time_in_24h(hours, am_or_pm):
        return datetime.strptime("%02d%s" % (hours, am_or_pm), '%I%p').hour
    

Then you could define `print_times()` function that prints times in the 3
different timezones:

    
    
    from datetime import datetime, time
    import pytz
    
    def astimezone(aware_dt, dest_tz):
        """Convert the time to `dest_tz` timezone"""
        return dest_tz.normalize(aware_dt.astimezone(dest_tz))
    
    def print_times(hours, am_or_pm, date=None, is_dst=None):
        source_tz = pytz.timezone('US/Eastern')
    
        # 2. add date
        if date is None: # if date is not specified; use today
            date = datetime.now(source_tz).date()
        naive_dt = datetime.combine(date, time(time_in_24h(hours, am_or_pm), 0, 0))
    
        # 3. create timezone-aware datetime object in the source timezone
        source_dt = source_tz.localize(naive_dt, is_dst=is_dst)
    
        #NOTE: these timezone names are deprecated,
        #      use Continent/City format instead
        fmt = '%I %p %Z'
        for tzname in 'US/Central', 'US/Mountain', 'US/Pacific':
            dest_dt = astimezone(source_dt, pytz.timezone(tzname))
            print("{source_dt:{fmt}} is {dest_dt:{fmt}} ({tzname})".format(
                **locals()))
    

It is important to specify the date correctly, otherwise you won't know the
correct UTC offset. The code uses `pytz` module to access timezone
information. [`strftime()` format
codes](http://docs.python.org/2/library/datetime.html#strftime-strptime-
behavior) are used for printing.

Example:

    
    
    >>> print_times(7, 'am')
    07 AM EDT is 06 AM CDT (US/Central)
    07 AM EDT is 05 AM MDT (US/Mountain)
    07 AM EDT is 04 AM PDT (US/Pacific)
    >>> print_times(1, 'pm')
    01 PM EDT is 12 PM CDT (US/Central)
    01 PM EDT is 11 AM MDT (US/Mountain)
    01 PM EDT is 10 AM PDT (US/Pacific)
    >>> print_times(9, 'pm')
    09 PM EDT is 08 PM CDT (US/Central)
    09 PM EDT is 07 PM MDT (US/Mountain)
    09 PM EDT is 06 PM PDT (US/Pacific)
    

Special note:

  * `datetime.now(source_tz)` allows to get the correct current time in the given timezone. `datetime.now()` would be incorrect here if the local timezone is not `source_tz`
  * `is_dst=None` means that `tz.localize()` method raises an exception for ambiguous or non-existing local times. Otherwise it just defaults to `is_dst=False` that might not be what you want
  * `tz.normalize()` might be necessary if the conversion happens across DST boundary

