ฉันจะตรวจสอบรูปแบบสตริงวันที่ในไพ ธ อนได้อย่างไร


143

ฉันมีวิธีหลามซึ่งยอมรับการป้อนข้อมูลวันที่เป็นสตริง

ฉันจะเพิ่มการตรวจสอบความถูกต้องได้อย่างไรเพื่อให้แน่ใจว่าสตริงวันที่จะถูกส่งผ่านไปยังเมธอดนั้นอยู่ใน ffg รูปแบบ:

'YYYY-MM-DD'

หากไม่เป็นเช่นนั้นเมธอดควรเพิ่มข้อผิดพลาดบางประเภท


2
มันอาจจะเป็น Pythonic มากกว่านี้ (ขอให้ยกโทษ, ไม่ได้รับอนุญาต) ไม่ควรตรวจสอบเลยและตรวจพบข้อยกเว้นที่เกิดขึ้น
โทมัส

คำตอบ:


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
มีวิธีการทำเช่นนั้นโดยไม่ลอง / ยกเว้น? Python มีแนวโน้มที่จะชะลอตัวลงอย่างมากเมื่อมีการยกและจับข้อยกเว้น
chiffa

1
@chiffa คุณสามารถจับคู่ regex รูปแบบวันที่ได้ แต่ไม่แนะนำเนื่องจากมีประสิทธิภาพน้อยกว่าและมีข้อยกเว้นที่ชัดเจนกว่า คุณแน่ใจหรือไม่ว่าการตรวจสอบวันที่เป็นคอขวดของคุณ
jamylak

1
ไม่จริงๆดังนั้นในท้ายที่สุดฉันจะห่อแบบยกเว้นการสร้างในฟังก์ชัน ฉันแค่แปลกใจที่ไม่มีฟังก์ชั่นการตรวจสอบความน่าเชื่อถือที่จะส่งการยกเว้นในห้องสมุด datetime
chiffa

@chiffa บางทีพวกเขาอาจไม่ได้รวมฟังก์ชั่นการตรวจสอบความถูกต้องของบูลกลับมามันอาจมีอยู่ในห้องสมุดภายนอก
jamylak

2
สำหรับผู้ที่ต้องการเติมเต็มศูนย์ในวันที่วิธีการแก้ปัญหานี้จะไม่ทำงานเพราะ strptime นั้นไม่เข้มงวดกับการเติมเต็มศูนย์ ใช้ regex ของคุณเองหรือตรวจสอบความยาวของสตริงผลลัพธ์หลังจากลอก whitespace แล้วใช้ประโยชน์จากโซลูชันนี้
Suparshva

65

หลามdateutilห้องสมุดถูกออกแบบมาสำหรับการนี้ (และอื่น ๆ ) มันจะแปลงเป็นdatetimeวัตถุให้คุณโดยอัตโนมัติและเพิ่ม a ValueErrorหากไม่สามารถทำได้

ตัวอย่างเช่น:

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

สิ่งนี้จะเพิ่มValueErrorถ้าหากรูปแบบวันที่ไม่ถูกต้อง:

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

dateutilนอกจากนี้ยังเป็นประโยชน์อย่างยิ่งถ้าคุณเริ่มต้นจำเป็นต้องแยกรูปแบบอื่น ๆ ในอนาคตที่จะสามารถจัดการกับรูปแบบที่เป็นที่รู้จักกันมากที่สุดอย่างชาญฉลาดและช่วยให้คุณสามารถปรับเปลี่ยนข้อกำหนดของคุณ: ตัวอย่างการแยก dateutil

นอกจากนี้ยังจัดการเขตเวลาหากคุณต้องการ

อัปเดตตามความคิดเห็น : parseยอมรับอาร์กิวเมนต์ของคำหลักdayfirstซึ่งควบคุมว่าคาดว่าวันหรือเดือนนั้นจะมาก่อนหรือไม่หากวันที่ไม่ชัดเจน ค่าเริ่มต้นนี้เป็นเท็จ เช่น

>>> 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
มันอาจยอมรับมากเกินไปเช่นparse('13/12/2001')"13 ธันวาคม" แต่parse('11/12/2001')"12 พฤศจิกายน" (ผลลัพธ์แรกจะแนะนำ "11 ธันวาคม" ที่นี่)
jfs

2
parseใช้dayfirstอาร์กิวเมนต์ของคำหลักที่ช่วยให้คุณสามารถควบคุมสิ่งนี้ได้จริง parse('11/12/2001', dayfirst=True)จะกลับมา "11 ธันวาคม" ค่าเริ่มต้นของ dateutil คือdayfirst=False
Jacinda

คุณพลาดจุดที่datetutil.parser.parse()ยอมรับรูปแบบเวลามากเกินไป (คุณสามารถหาตัวอย่างอื่นที่มีการป้อนข้อมูลที่ไม่ชัดเจน) หากคุณต้องการตรวจสอบว่าอินพุตของคุณอยู่ในรูปแบบ YYYY-MM-DD parse()ฟังก์ชันนั้นเป็นเครื่องมือที่ผิด
jfs

1
นั่นเป็นจุดที่ถูกต้องสมบูรณ์ - หากคุณต้องการ จำกัด รูปแบบเฉพาะที่ไม่ได้ทำเช่นนั้นและคำตอบที่ยอมรับแล้วก็เป็นงานที่ยอดเยี่ยมในการทำสิ่งที่ถูกต้องในกรณีนั้น ฉันคิดว่าเมื่อฉันเขียนคำตอบฉันคิดมากขึ้นตามแนวของการชี้ให้เห็นว่าจะตรวจสอบว่าเป็นวันที่ที่ถูกต้องหรือไม่ซึ่งตรงข้ามกับรูปแบบเฉพาะที่ผู้เขียนร้องขอซึ่งเมื่อผู้คนพบคำถามนี้ กำลังมองหา.
Jacinda

มีวิธีที่จะได้รับ.parse()กลับสตริงรูปแบบนอกเหนือจากdatetimeวัตถุหรือไม่
citynorman

35

ฉันคิดว่าฟังก์ชันการตรวจสอบความถูกต้องสมบูรณ์ควรมีลักษณะดังนี้:

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

ดำเนินการเพียง

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

ไม่เพียงพอเนื่องจากวิธี strptime ไม่ได้ตรวจสอบว่าเดือนและวันที่ของเดือนเป็นเลขทศนิยมที่ไม่มีการเติมเต็ม ตัวอย่างเช่น

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

จะถูกดำเนินการโดยไม่มีข้อผิดพลาด


3
"คุณถูกต้องทางเทคนิค - เป็นประเภทที่ถูกต้องที่สุด" ฉันต้องการให้แน่ใจในสิ่งนี้ในสายของฉัน
delrocco

สิ่งนี้ใช้ได้ดีกับการทดสอบของฉัน แต่ฉันเอกสารดูเหมือนว่าไม่ถูกต้องเนื่องจาก: "% d -> วันของเดือนเป็นเลขทศนิยมแบบไม่มีเบาะรอง -> 01, 02, …, 31" และเหมือนกันสำหรับ% m -> เดือนเป็นเลขทศนิยมแบบไม่มีเบาะรอง -> 01, 02, …, 12 docs.python.org/2/library/
thanos.a

หากคุณจำเป็นต้องตรวจสอบว่าเดือนและวันนั้นไม่มีสิ่งใดจะช่วยให้คุณตรวจสอบความยาวของสตริงได้datetime.strptime(date_text, "%Y-%m-%d")หรือไม่?
Kyle Barron

17
from datetime import datetime

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

.. นี่จะเพิ่มValueErrorถ้ามันได้รับรูปแบบที่เข้ากันไม่ได้

.. หากคุณกำลังจัดการกับวันที่และเวลามาก (ในแง่ของวัตถุ datetime เมื่อเทียบกับ unix timestamp floats) คุณควรตรวจสอบโมดูล pytz และเก็บ / db เก็บทุกอย่างใน UTC .


2
คุณเร็วฉันจะโพสต์ด้วยตัวเอง ( ideone.com/vuxDDf ) upvote
Tadeck

.. เพียงแค่เห็นมันหลังจากโพสต์และได้ทำงานกับวัตถุวันที่และเวลาในวันนี้
นาย B

-7

นี่เป็นวิธีที่ง่ายที่สุด:

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

2
มันจะเป็นการดีกว่าถ้ามีคำอธิบายแทนที่จะใช้รหัสเท่านั้น
lukas_o
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.