2009-07-09 30 views

Trả lời

93

Bạn có thể sử dụng chức năng phân tích cú pháp từ dateutil:

>>> from dateutil.parser import parse 
>>> d = parse('2009/05/13 19:19:30 -0400') 
>>> d 
datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=tzoffset(None, -14400)) 

Bằng cách này bạn có được một đối tượng datetime sau đó bạn có thể sử dụng.

answered, dateutil2.0 được viết cho Python 3.0 và không hoạt động với Python 2.x. Đối với Python 2.x dateutil1.5 cần phải được sử dụng.

+1

này không hoạt động trong dateutil phiên bản 2.0 trên Python 2.6 –

+11

này hoạt động tốt đối với tôi ('dateutil' 2.1) với Python '2.7.2'; Python 3 là không cần thiết. Lưu ý rằng nếu bạn đang cài đặt từ pip, tên gói là 'python-dateutil'. – BigglesZX

-8

Nếu bạn đang trên Linux, sau đó bạn có thể sử dụng bên ngoài date lệnh để dwim:

import commands, datetime 

def parsedate(text): 
    output=commands.getoutput('date -d "%s" +%%s' % text) 
    try: 
     stamp=eval(output) 
    except: 
     print output 
     raise 
    return datetime.datetime.frometimestamp(stamp) 

Đây là khóa học ít di động hơn dateutil, nhưng hơi linh hoạt hơn, vì date cũng sẽ chấp nhận đầu vào như " Ngày hôm qua "hoặc" năm ngoái ":-)

+3

Tôi không nghĩ rằng nó tốt để gọi một chương trình bên ngoài cho việc này. Và điểm yếu tiếp theo: eval(): Nếu bạn bây giờ một máy chủ web thực hiện mã này, bạn có thể thực hiện mã tùy ý trên máy chủ! – guettli

+5

Tất cả phụ thuộc vào ngữ cảnh: nếu những gì chúng ta đang theo sau chỉ là một kịch bản viết-và-ném-đi, thì những điểm yếu này không liên quan :-) – Gyom

+8

Bỏ phiếu này vì: 1) Nó kêu gọi hệ thống một cái gì đó tầm thường, 2) Nó tiêm chuỗi trực tiếp vào một cuộc gọi vỏ, 3) Nó gọi eval(), và 4) Nó có một ngoại lệ bắt tất cả. Về cơ bản đây là một ví dụ về cách * không * để làm việc. – benjaoming

7

Vấn đề với việc sử dụng dateutil là bạn không thể có cùng chuỗi định dạng cho cả serialization và deserialization, vì dateutil có các tùy chọn định dạng giới hạn (chỉ dayfirstyearfirst).

Trong ứng dụng của tôi, tôi lưu trữ chuỗi định dạng trong tệp .INI và mỗi triển khai có thể có định dạng riêng. Vì vậy, tôi thực sự không thích cách tiếp cận dateutil.

Dưới đây là một phương pháp khác có sử dụng pytz thay vì:

from datetime import datetime, timedelta 

from pytz import timezone, utc 
from pytz.tzinfo import StaticTzInfo 

class OffsetTime(StaticTzInfo): 
    def __init__(self, offset): 
     """A dumb timezone based on offset such as +0530, -0600, etc. 
     """ 
     hours = int(offset[:3]) 
     minutes = int(offset[0] + offset[3:]) 
     self._utcoffset = timedelta(hours=hours, minutes=minutes) 

def load_datetime(value, format): 
    if format.endswith('%z'): 
     format = format[:-2] 
     offset = value[-5:] 
     value = value[:-5] 
     return OffsetTime(offset).localize(datetime.strptime(value, format)) 

    return datetime.strptime(value, format) 

def dump_datetime(value, format): 
    return value.strftime(format) 

value = '2009/05/13 19:19:30 -0400' 
format = '%Y/%m/%d %H:%M:%S %z' 

assert dump_datetime(load_datetime(value, format), format) == value 
assert datetime(2009, 5, 13, 23, 19, 30, tzinfo=utc) \ 
    .astimezone(timezone('US/Eastern')) == load_datetime(value, format) 
32

%z được hỗ trợ trong Python 3.2+:

>>> from datetime import datetime 
>>> datetime.strptime('2009/05/13 19:19:30 -0400', '%Y/%m/%d %H:%M:%S %z') 
datetime.datetime(2009, 5, 13, 19, 19, 30, 
        tzinfo=datetime.timezone(datetime.timedelta(-1, 72000))) 

Trong các phiên bản trước đó:

from datetime import datetime 

date_str = '2009/05/13 19:19:30 -0400' 
naive_date_str, _, offset_str = date_str.rpartition(' ') 
naive_dt = datetime.strptime(naive_date_str, '%Y/%m/%d %H:%M:%S') 
offset = int(offset_str[-4:-2])*60 + int(offset_str[-2:]) 
if offset_str[0] == "-": 
    offset = -offset 
dt = naive_dt.replace(tzinfo=FixedOffset(offset)) 
print(repr(dt)) 
# -> datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=FixedOffset(-240)) 
print(dt) 
# -> 2009-05-13 19:19:30-04:00 

nơi FixedOffset là một lớp học dựa trên số the code example from the docs:

from datetime import timedelta, tzinfo 

class FixedOffset(tzinfo): 
    """Fixed offset in minutes: `time = utc_time + utc_offset`.""" 
    def __init__(self, offset): 
     self.__offset = timedelta(minutes=offset) 
     hours, minutes = divmod(offset, 60) 
     #NOTE: the last part is to remind about deprecated POSIX GMT+h timezones 
     # that have the opposite sign in the name; 
     # the corresponding numeric value is not used e.g., no minutes 
     self.__name = '<%+03d%02d>%+d' % (hours, minutes, -hours) 
    def utcoffset(self, dt=None): 
     return self.__offset 
    def tzname(self, dt=None): 
     return self.__name 
    def dst(self, dt=None): 
     return timedelta(0) 
    def __repr__(self): 
     return 'FixedOffset(%d)' % (self.utcoffset().total_seconds()/60) 
+0

Điều này gây ra một 'ValueError: 'z' là một chỉ thị xấu trong định dạng '% Y-% m-% d% M:% H:% S.% f% z'' trong trường hợp của tôi (Python 2.7). – Sheljohn

+0

@Sheljohn nó không phải là nghĩa vụ phải làm việc trên Python 2,7 Nhìn ở đầu rất của câu trả lời. – jfs

+0

lạ, bằng cách này, rằng đây là KHÔNG AT TẤT CẢ được đề cập trên Python * 2.7 * tài liệu: https://docs.python.org/2.7/library/datetime.html?highlight=datetime#strftime-strptime-behavior – 62mkv

12

Đây là một sửa chữa cho vấn đề "%z" cho Python 2.7 và trước đó

Thay vì sử dụng:

datetime.strptime(t,'%Y-%m-%dT%H:%M %z') 

Sử dụng timedelta để chiếm lại múi giờ cũng như thế này:

from datetime import datetime,timedelta 
def dt_parse(t): 
    ret = datetime.strptime(t[0:16],'%Y-%m-%dT%H:%M') 
    if t[18]=='+': 
     ret-=timedelta(hours=int(t[19:22]),minutes=int(t[23:])) 
    elif t[18]=='-': 
     ret+=timedelta(hours=int(t[19:22]),minutes=int(t[23:])) 
    return ret 

Lưu ý rằng các ngày sẽ được chuyển đổi thành GMT, whi ch sẽ cho phép thực hiện số học ngày mà không đáng lo ngại về múi giờ.

+0

I như thế này, mặc dù bạn cần thay đổi 'seconds =' thành 'minutes ='. – Dave

+0

nhờ @Dave, sửa nó –

+1

chuyển đổi thành GMT ... nếu đó là những gì bạn thực sự muốn ... –

0

Một lớp lót cho Pythons cũ ngoài kia.Bạn có thể nhân một timedelta bằng 1/-1 tùy thuộc vào +/- dấu hiệu, như trong:

datetime.strptime(s[:19], '%Y-%m-%dT%H:%M:%S') + timedelta(hours=int(s[20:22]), minutes=int(s[23:])) * (-1 if s[19] == '+' else 1) 
Các vấn đề liên quan