Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - Convert time to different time zone, keep am/pm

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.

like image 443
Maverick Avatar asked Mar 16 '14 01:03

Maverick


People also ask

How do you change the AM PM in Python?

strptime() function to convert the string to a datetime object, and then using the string method strftime() to output the time in 24-hour format. The format code for 24-hour time is %H:%M whereas the format for 12-hour time is %I:%M with %p appended if the time contains AM/PM.

How do you get AM and PM in Python?

struct_time object, then use library function time. strftime() to format this struct_time into a string of your desired 12-hour format. %I is a directive that tells Python to give the hour in the 12-hour format. Additionally, you may include the %p directive which will display “AM” or “PM”.

How do I convert between time zones in Python?

Converting Between TimezonesUse the datetime. astimezone() method to convert the datetime from one timezone to another. This method uses an instance of the datetime object and returns a new datetime of a given timezone.

How do you convert time format in Python?

Method 1: Program to convert string to DateTime using datetime. strptime() function. strptime() is available in DateTime and time modules and is used for Date-Time Conversion.


2 Answers

For Central, just check if the Eastern time is 12 pm. If it is, then adjust to 11 am. Similarly, if eastern is midnight, then adjust to (11) pm. It'll take a bit of ifs, but you could do it.

The problem is, it's still wrong. Date-time math is hard, and you've forgotten about DST.

Typically, once a year, it's 1 AM in Eastern time (EST), but also 1 AM in Central time (CDT). (Likewise, it's also once 3 AM in Eastern, and 1 AM in Central.)

You can't, with the amount of inputs your function currently takes, account for this: you need to know the full date and time. Once you do, it's easiest to just convert that full Eastern (America/New_York) date and time to UTC, and then convert that to Central (America/Chicago), Mountain (America/Denver) and Pacific (America/Los_Angeles).

The America/… bits are the names for the timezones that the TZ database on most machines uses. America/New_York is the "Eastern" time: it specifies when DST is, when it isn't, and what the offset from UTC is. It even has historical data, as the dates when DST starts & end have changed. (And on a global scale, actually change quite often. Governments…)

Keeping the non-DST aware version:

First, let's get two helper functions going: to_24hour, which converts a (hour, ampm) to a 24-hour format, and to_12hour, which goes the other way. These will make things easier to think about, as we can do the subtractions a lot more easily in 24-hour time.

def to_24hour(hour, ampm):
    """Convert a 12-hour time and "am" or "pm" to a 24-hour value."""
    if ampm == 'am':
        return 0 if hour == 12 else hour
    else:
        return 12 if hour == 12 else hour + 12

def to_12hour(hour):
    """Convert a 24-hour clock value to a 12-hour one."""
    if hour == 0:
        return (12, 'am')
    elif hour < 12:
        return (hour, 'am')
    elif hour == 12:
        return (12, 'pm')
    else:
        return (hour - 12, 'pm')

Once we have those, things get simpler:

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:
        est_24hour = to_24hour(time, time_day)
        hour, ampm = to_12hour((est_24hour - 1 + 24) % 24)
        print(time, time_day, eEst, hour, ampm, cCentral)
        hour, ampm = to_12hour((est_24hour - 2 + 24) % 24)
        print(time, time_day, eEst, hour, ampm, mMountain)
        hour, ampm = to_12hour((est_24hour - 3 + 24) % 24)
        print(time, time_day, eEst, hour, ampm, pPacific)

… with those adjustments:

>>> time_in_24h(1, 'pm')
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)

One last note. Your docstring reads:

(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.

This, of course, is what to_24hour does.

With timezone awareness

Python doesn't really help with timezones; Justin Barber, in a separate answer, suggests pytz; it's a good choice.

If we have some date or time that we know to be in Eastern:

now = datetime.datetime(2014, 3, 14, 12, 34)

Grab the timezones:

et = pytz.timezone('America/New_York')
ct = pytz.timezone('America/Chicago')
mt = pytz.timezone('America/Denver')
pt = pytz.timezone('America/Los_Angeles')

We can convert to Central and the others with:

now_et = et.normalize(et.localize(now))
now_ct = ct.normalize(now_et.astimezone(ct))
now_mt = mt.normalize(now_et.astimezone(mt))
now_pt = pt.normalize(now_et.astimezone(pt))

(As a comment notes, pytz oddly requires a call to normalize when a change might cross a DST boundary, which is basically anything you do.)

Then:

print('{} Eastern in various other timezones:'.format(now_et.strftime('%I %p')))
print('Central : {}'.format(now_ct.strftime('%I %p')))
print('Mountain: {}'.format(now_mt.strftime('%I %p')))
print('Pacific : {}'.format(now_pt.strftime('%I %p')))
like image 125
Thanatos Avatar answered Nov 14 '22 23:11

Thanatos


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 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
like image 26
jfs Avatar answered Nov 14 '22 22:11

jfs