Làm cách nào để xác thực định dạng chuỗi ngày trong python?


143

Tôi có một phương thức python chấp nhận đầu vào ngày dưới dạng chuỗi .

Làm cách nào để thêm xác thực để đảm bảo chuỗi ngày được truyền cho phương thức nằm trong ffg. định dạng:

'YYYY-MM-DD'

nếu không, phương thức sẽ đưa ra một số lỗi


2
Nó có thể là Pythonic hơn (yêu cầu sự tha thứ, không cho phép) không kiểm tra tất cả, và nắm bắt bất kỳ trường hợp ngoại lệ kết quả xảy ra.
Thomas

Câu trả lời:


230
>>> import datetime
>>> def validate(date_text):
    try:
        datetime.datetime.strptime(date_text, '%Y-%m-%d')
    except ValueError:
        raise ValueError("Incorrect data format, should be YYYY-MM-DD")


>>> validate('2003-12-23')
>>> validate('2003-12-32')

Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    validate('2003-12-32')
  File "<pyshell#18>", line 5, in validate
    raise ValueError("Incorrect data format, should be YYYY-MM-DD")
ValueError: Incorrect data format, should be YYYY-MM-DD

8
Có cách nào để làm điều đó mà không cần thử / ngoại trừ không? Python có xu hướng chậm lại đáng kể khi một ngoại lệ được nêu ra và bị bắt.
chiffa

1
@chiffa Bạn có thể khớp với biểu thức định dạng ngày nhưng không được khuyến nghị vì nó kém mạnh mẽ hơn và các ngoại lệ rõ ràng hơn. Bạn có chắc chắn xác nhận ngày là nút cổ chai của bạn?
jamylak

1
Không thực sự, vì vậy cuối cùng tôi sẽ chỉ gói ném - ngoại trừ cấu trúc trong một hàm. Tôi chỉ ngạc nhiên rằng không có hàm xác thực bool-return sẽ kích hoạt ném Exception trong thư viện datetime.
chiffa

@chiffa Có lẽ chúng không bao gồm bool trả về chức năng xác nhận hợp lệ, nó có thể tồn tại trong các thư viện bên ngoài
jamylak

2
Đối với những người muốn đệm không trong ngày, giải pháp này sẽ không hoạt động vì thời gian không nghiêm ngặt về đệm không. Thực hiện một biểu thức chính của bạn hoặc kiểm tra độ dài của chuỗi kết quả sau khi tước khoảng trắng và sau đó sử dụng giải pháp này.
Suparshva

65

Các Pythondateutil thư viện được thiết kế cho việc này (và nhiều hơn nữa). Nó sẽ tự động chuyển đổi nó thành một datetimeđối tượng cho bạn và nâng cao ValueErrornếu nó không thể.

Ví dụ:

>>> from dateutil.parser import parse
>>> parse("2003-09-25")
datetime.datetime(2003, 9, 25, 0, 0)

Điều này sẽ tăng ValueErrornếu ngày không được định dạng chính xác:

>>> parse("2003-09-251")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/jacinda/envs/dod-backend-dev/lib/python2.7/site-packages/dateutil/parser.py", line 720, in parse
    return DEFAULTPARSER.parse(timestr, **kwargs)
  File "/Users/jacinda/envs/dod-backend-dev/lib/python2.7/site-packages/dateutil/parser.py", line 317, in parse
    ret = default.replace(**repl)
ValueError: day is out of range for month

dateutilcũng cực kỳ hữu ích nếu bạn bắt đầu cần phân tích các định dạng khác trong tương lai, vì nó có thể xử lý hầu hết các định dạng đã biết một cách thông minh và cho phép bạn sửa đổi đặc tả của mình: dateutilphân tích ví dụ .

Nó cũng xử lý các múi giờ nếu bạn cần điều đó.

Cập nhật dựa trên nhận xét : parsecũng chấp nhận đối số từ khóa dayfirstkiểm soát xem ngày hoặc tháng dự kiến ​​sẽ đến trước nếu ngày không rõ ràng. Điều này mặc định là Sai. Ví dụ

>>> parse('11/12/2001')
>>> datetime.datetime(2001, 11, 12, 0, 0) # Nov 12
>>> parse('11/12/2001', dayfirst=True)
>>> datetime.datetime(2001, 12, 11, 0, 0) # Dec 11

1
nó có thể chấp nhận quá nhiều, ví dụ: parse('13/12/2001')"13/12" nhưng parse('11/12/2001')là "12/11" (kết quả đầu tiên sẽ gợi ý "11/12" tại đây).
jfs

2
parsethực sự có một dayfirstđối số từ khóa cho phép bạn kiểm soát điều này. parse('11/12/2001', dayfirst=True)sẽ trở lại "ngày 11 tháng 12" Mặc định của dateutil làdayfirst=False
Jacinda 2/11/2015

bạn đang thiếu điểm datetutil.parser.parse()chấp nhận quá nhiều định dạng thời gian (bạn có thể tìm thấy các ví dụ khác với đầu vào mơ hồ). Nếu bạn muốn xác thực rằng đầu vào của bạn ở định dạng YYYY-MM-DD thì parse()chức năng là công cụ sai.
jfs

1
Đó là một điểm hoàn toàn hợp lệ - nếu bạn thực sự muốn giới hạn ở định dạng cụ thể đó thì điều này không làm được điều đó, và câu trả lời được chấp nhận đã làm rất tốt việc thực hiện đúng trong trường hợp đó. Tôi nghĩ khi tôi viết câu trả lời, tôi đã suy nghĩ nhiều hơn trong các dòng chỉ ra làm thế nào để xác thực xem đó có phải là một ngày hợp lệ trái với định dạng cụ thể mà tác giả yêu cầu hay không, khi mọi người bắt gặp câu hỏi này là những gì họ thường gặp tìm kiếm.
Jacinda 5/11/2015

Có cách nào để có được .parse()trả về chuỗi định dạng ngoài datetimeđối tượng không?
citynorman

35

Tôi nghĩ rằng chức năng xác nhận đầy đủ sẽ trông như thế này:

from datetime import datetime

def validate(date_text):
    try:
        if date_text != datetime.strptime(date_text, "%Y-%m-%d").strftime('%Y-%m-%d'):
            raise ValueError
        return True
    except ValueError:
        return False

Chỉ thực hiện

datetime.strptime(date_text, "%Y-%m-%d") 

là không đủ vì phương pháp strptime không kiểm tra xem tháng và ngày trong tháng có phải là số thập phân có đệm không. Ví dụ

datetime.strptime("2016-5-3", '%Y-%m-%d')

sẽ được thực hiện mà không có lỗi.


3
"Bạn đúng về mặt kỹ thuật - loại đúng nhất." Tôi cần phải đảm bảo điều này trong chuỗi của tôi.
delrocco

Điều này hoạt động tốt đối với các thử nghiệm của tôi, tuy nhiên tài liệu của tôi có vẻ không chính xác vì nó tuyên bố: "% d -> Ngày trong tháng dưới dạng số thập phân không có đệm -> 01, 02, Lỗi, 31" và tương tự cho% m -> Tháng dưới dạng số thập phân có đệm. -> 01, 02, ..., 12 docs.python.org/2/library/...
thanos.a

Nếu bạn cần kiểm tra xem tháng và ngày có được đệm không, thì có phải chỉ cần kiểm tra độ dài của chuỗi datetime.strptime(date_text, "%Y-%m-%d")không?
Kyle Barron

17
from datetime import datetime

datetime.strptime(date_string, "%Y-%m-%d")

.. điều này làm tăng ValueErrornếu nó nhận được một định dạng không tương thích.

.. nếu bạn đang xử lý ngày và giờ rất nhiều (theo nghĩa của các đối tượng datetime, trái ngược với dấu phẩy dấu thời gian unix), bạn nên xem xét mô-đun pytz và để lưu trữ / db, lưu trữ mọi thứ trong UTC .


2
Bạn đã nhanh hơn, tôi sẽ tự đăng nó ( ideone.com/vuxDDf ). Upvote.
Tadeck

..chỉ thấy nó ngay sau khi nó được đăng, và tình cờ đã làm việc với các đối tượng datetime ngày hôm nay.
Ông B

-7

Đây là cách dễ dàng nhất:

date = datetime.now()
date = date.strftime('%Y-%m-%d_%H-%M-%S.jpg')

2
Nó sẽ tốt hơn để có một lời giải thích, thay vì chỉ mã.
lukas_o
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.