9

I have a few records inside a column which represent either EST or EDT Time. I need to convert these times to GMT time. The format of the time are:

10/1/2010   0:0:0
10/1/2010   0:6:0
...
10/1/2010   23:54:0
...
10/3/2010   0:0:0
...

Can someone help me out here? thanks

widget
  • 945
  • 3
  • 13
  • 22
  • 5
    Those look like dates (1st day of October, 2010), not times ... please explain. – John Machin Mar 30 '11 at 19:34
  • 1
    Why do you keep asking the same question? What was wrong with your prior attempts at this? http://stackoverflow.com/questions/5490141/how-to-format-time-and-convert-to-gmt-time and http://stackoverflow.com/questions/5464410/how-to-tell-if-a-date-is-between-two-other-dates-in-python. Perhaps it would be simpler if you could ask your **real** question instead of these other, incorrect questions that you keep having to change. – S.Lott Mar 31 '11 at 01:20
  • @S.Lott: in this second posting I was trying to convert the time to GMT time manually, which turns out unefficient. For the first posting, I was simplily thinking that people stop viewing that post. thought about deleting the first one but couldn't because it had answers already – widget Mar 31 '11 at 02:36

6 Answers6

18

The easiest, most reliable way I know to convert between timezones is to use the third-party pytz module:

import pytz
import datetime as dt

utc=pytz.utc
eastern=pytz.timezone('US/Eastern')
fmt='%Y-%m-%d %H:%M:%S %Z%z'

text='''\
10/1/2010   0:0:0
10/1/2010   0:6:0
10/1/2010   23:54:0
10/3/2010   0:0:0
'''

for datestring in text.splitlines():
    date=dt.datetime.strptime(datestring,"%m/%d/%Y %H:%M:%S")
    date_eastern=eastern.localize(date,is_dst=None)
    date_utc=date_eastern.astimezone(utc)
    print(date_utc.strftime(fmt))

yields:

2010-10-01 04:00:00 UTC+0000
2010-10-01 04:06:00 UTC+0000
2010-10-02 03:54:00 UTC+0000
2010-10-03 04:00:00 UTC+0000

Note however, your data does not specify if the datetime is in the EST or EDT timezone. There are some times which are ambiguous when you don't specify EST or EDT. For example, '10/27/2002 1:30:00' would be ambiguous:

>>> eastern.localize(datetime(2002, 10, 27, 1, 30, 00), is_dst=None)
AmbiguousTimeError: 2002-10-27 01:30:00

since this time happened twice due to Daylight Savings Time. Also some datetimes, like 2002-04-07 02:30:00, are nonexistent. See this link for a discussion of these and even more bizarre issues that arise when dealing with localtimes.

If you are willing to overlook these knotty corner cases, and if your machine is setup in the local timezone (e.g. EST/EDT), there is a way to convert between the local and UTC timezones which does not require the installation of pytz. The idea is to convert the datetime --> timetuple --> timestamp --> UTC datetime. The chain of conversions is done with

dt.datetime.utcfromtimestamp(time.mktime(date.timetuple()))

For example:

import time
import datetime as dt
import pytz

utc=pytz.utc
eastern=pytz.timezone('US/Eastern')
fmt='%Y-%m-%d %H:%M:%S %Z%z'

text='''\
10/1/2010   0:0:0
10/1/2010   0:6:0
10/1/2010   23:54:0
10/3/2010   0:0:0
3/13/2011   1:55:0
3/13/2011   3:00:0
'''
for datestring in text.splitlines():
    date=dt.datetime.strptime(datestring,"%m/%d/%Y %H:%M:%S")
    date_est=eastern.localize(date,is_dst=None)
    date_utc=date_est.astimezone(utc)
    date_utc2=dt.datetime.utcfromtimestamp(time.mktime(date.timetuple()))
    print('{d} --> {d_utc}    {d_utc2}'.format(
        d=date.strftime(fmt),
        d_utc=date_utc.strftime(fmt),
        d_utc2=date_utc2.strftime(fmt),
        ))
    assert date_utc.hour == date_utc2.hour

yields

2010-10-01 00:00:00 EDT-0400 --> 2010-10-01 04:00:00 UTC+0000    2010-10-01 04:00:00 
2010-10-01 00:06:00 EDT-0400 --> 2010-10-01 04:06:00 UTC+0000    2010-10-01 04:06:00 
2010-10-01 23:54:00 EDT-0400 --> 2010-10-02 03:54:00 UTC+0000    2010-10-02 03:54:00 
2010-10-03 00:00:00 EDT-0400 --> 2010-10-03 04:00:00 UTC+0000    2010-10-03 04:00:00 
2011-03-13 01:55:00 EST-0500 --> 2011-03-13 06:55:00 UTC+0000    2011-03-13 06:55:00 
2011-03-13 03:00:00 EDT-0400 --> 2011-03-13 07:00:00 UTC+0000    2011-03-13 07:00:00 

The last two dates tested above show the conversion works correctly even with times close to the switch between EST and EDT.


In summary, using the alternate method (without pytz), here is how to convert datetime objects representing local time to datetime objects representing GMT time, and vice versa:

In [83]: import datetime as dt
In [84]: import time
In [85]: import calendar

In [86]: date=dt.datetime(2010,12,1,0,0,0)    
In [87]: date
Out[87]: datetime.datetime(2010, 12, 1, 0, 0)

In [88]: date_utc=dt.datetime.utcfromtimestamp(time.mktime(date.timetuple()))    
In [89]: date_utc
Out[89]: datetime.datetime(2010, 12, 1, 5, 0)

In [90]: date_local=dt.datetime.fromtimestamp(calendar.timegm(date_utc.timetuple()))    
In [91]: date_local
Out[91]: datetime.datetime(2010, 12, 1, 0, 0)
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • @unutbu: """when the date is in daylight-savings timezone and UTC is not"""????? UTC is immutable wrt daylight-savings. Currently the UK is on BST (British Summer Time) which is **defined** as UTC+1 – John Machin Mar 30 '11 at 21:56
  • @unutbu: I just tried your codes(the second method). The problem with the first one is that I dont have pytz package. For the second way, now i have result 2010-12-01 05:00:00 out of '12/1/2010 0:0:0' so it seems perfect. Anyway, is there a way to to convert it to the original format: '12/1/2010 5:0:0'? Now I know that to convert other formats to date format I could use something like date=dt.datetime.strptime(text,"%m/%d/%Y %H:%M:%S") , but don't know how to format date format to others. Also, Another questions is that what if I have a GMT time and wanna convert it to EST/EDT time? – widget Mar 30 '11 at 22:26
  • @widget: You can format `datetime` objects with the `strftime` method. For example, `date.strftime('%m/%d/%Y%l:%M:%S')` would return `'12/01/2010 5:00:00'`. There is no builtin format for single digit minutes and seconds however. You could finagle that with more code, but it's ugly. Do you really really need and want that? – unutbu Mar 30 '11 at 23:14
  • @widget: You can look at the available strftime format string directives here: http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior. – unutbu Mar 30 '11 at 23:23
  • @widget: Try the instructions here: http://pytz.sourceforge.net/#installation. If you run into trouble, please open a new question and include what OS you are using. – unutbu Mar 31 '11 at 12:22
  • @unutbu: i made it work. tks. the date formatting knowledge would be very useful – widget Mar 31 '11 at 19:21
  • @widget: Has your date formatting question been answered, or is there something more you are looking for? – unutbu Mar 31 '11 at 19:30
  • @unutbu: I just found a question in your codes using pytz package: date_est=eastern.localize(date,is_dst=None). If it is a series of different dates, how could u simply use: is_dst=None to localize the naive datetime? It does not convert the times correcrly. If you set it to None, then it's adding 5 hrs to all the time no matter if it is EDT or EST. can you please explain? tks – widget Mar 31 '11 at 19:54
2

Pseudocode for each record:

make a timestamp string: field[0].strip() + " " + field[1].strip()

use datetime.datetime.strptime() to convert that into a datetime.datetime instance

add a timedelta e.g. timedelta(hours=-4) to your timestamp

use timestamp.strftime() to produce whatever string representation you want for the output.

For the case where the time field is empty: If that means 0:0:0, modify the above to suit. If it means "time unknown", you'll need to do something else ...

John Machin
  • 81,303
  • 11
  • 141
  • 189
2

Assume that we have a datetime string as "2019-04-09T23:59:55ET" in US/Eastern time. Here is the function to convert string to UTC:

from datetime import datetime
import pytz

eastern = pytz.timezone('US/Eastern')

def convent_est_to_utc(datetime_str):
    dt = datetime.strptime(datetime_str, '%Y-%m-%dT%H:%M:%SET')
    return dt.replace(tzinfo=eastern).astimezone(pytz.utc)

# testing
convent_est_to_utc("2019-04-09T23:59:55ET")

# The result: 2019-04-10 04:55:55+00:00

David P
  • 71
  • 3
1

Without an associated time, the time zone doesn't matter ... nor can the date be translated to a different time zone. Is there a related time in another column?

EDIT: Alright, now that there IS a time, I'll let the python guru's take over. ;]

Joe McBride
  • 3,789
  • 2
  • 34
  • 38
  • If you're adding a new column for time, just use 4:00 AM and change the Time Zone to GMT (EST is GMT-4:00). That would mean the date is 12:00AM EST. I don't think you would need to do anything else fancy. – Joe McBride Mar 30 '11 at 19:44
  • You haven't thought about what to do when the input and output timestamps straddle a month boundary. – John Machin Mar 30 '11 at 20:00
  • @John Machin: I did think about it, though left that as an exercise for widget. – Joe McBride Mar 30 '11 at 20:09
1

You can use pandas.DataFrame.tz_convert() like this:

import pandas as pd
from datetime import datetime

df = pd.read_csv("your_data_file_path.csv", index_col=False, engine='python')
df['Date'] = pd.to_datetime(df['Date'])
df['Date'] = df['Date'].dt.tz_localize('US/Eastern').dt.tz_convert('UTC')
df['Date'] = df['Date'].apply(lambda x: datetime.replace(x, tzinfo=None))

What the last row does is removing the timezone info from the datetime object, so you can operate with the date and time only (don't worry, that doesn't change the timezone again, it just strips it from the timestamp string).

tsveti_iko
  • 6,834
  • 3
  • 47
  • 39
0

I had to create a custom function in Python to convert EST to GMT, here's the code I've written:

#convert est time to gmt. Make sure you assign the current EST values
#to the following variables
        est_year
        est_month
        est_day
        est_hour
        est_min

        gmt_year = est_year
        gmt_month = est_month
        gmt_day = est_day
        gmt_hour = est_hour + 5 #gmt is ahead by 5 hrs
        gmt_min = est_min

        if gmt_hour > 23:
          gmt_hour = gmt_hour - 23
          gmt_day = est_day + 1

        days_in_month = calendar.monthrange(est_year,est_month)[1] #in case the no days becomes 32..

        if gmt_day > days_in_month:
          gmt_day = 1
          gmt_month = gmt_month + 1

        if gmt_month > 12:
          gmt_month = 1
          gmt_year = gmt_year + 1

        gmttime = datetime.datetime(gmt_year, gmt_month, gmt_day, gmt_hour, gmt_min, 0)

I haven't added support for EDT. It is February currently and EST is being followed. Any changes or corrections are welcome!

Bilbo Baggins
  • 3,644
  • 8
  • 40
  • 64