Como validar um formato de string de data em python?


143

Eu tenho um método python que aceita uma entrada de data como uma seqüência de caracteres .

Como adiciono uma validação para garantir que a sequência de datas passada no método esteja no ffg. formato:

'YYYY-MM-DD'

caso contrário, o método deve gerar algum tipo de erro


2
Pode ser mais pitonico (pedir perdão, não permissão) não checar e capturar as exceções resultantes que ocorram.
Thomas

Respostas:


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
Existe uma maneira de fazer isso sem uma tentativa / exceto? Python tende a abrandar significativamente quando uma exceção é criada e capturada.
Chiffa

1
@chiffa Você pode corresponder a um regex de formato de data, mas não é recomendado porque é menos robusto e as exceções são mais claras. Tem certeza de que a validação da data é seu gargalo?
jamylak

1
Na verdade, não, então, no final, apenas envolverei o throw, exceto o construto em uma função. Estou surpreso que não há nenhuma função de validação de retorno de bool que desencadeie o lançamento de exceção na biblioteca de data e hora.
chiffa 12/09/16

@chiffa Talvez eles não incluem bool retornando validar função de propósito, ele pode existir em bibliotecas externas
jamylak

2
Para aqueles que desejam zero padding em datas, esta solução não funcionará, pois o strptime não é rigoroso quanto ao padding zero. Implemente uma regex própria ou verifique o comprimento da sequência resultante depois de eliminar o espaço em branco e, em seguida, use esta solução.
Suparshva 28/05

65

A biblioteca Pythondateutil foi projetada para isso (e mais). Ele automaticamente converterá isso em um datetimeobjeto para você e aumentará umValueError se não puder.

Como um exemplo:

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

Isso gera a ValueErrorse a data não estiver formatada corretamente:

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

dateutiltambém é extremamente útil se você começar a analisar outros formatos no futuro, pois ele pode lidar com os formatos mais conhecidos de maneira inteligente e permite modificar sua especificação: dateutilexemplos de análise .

Ele também lida com fusos horários, se você precisar.

Atualização baseada em comentários : parsetambém aceita o argumento de palavra-chave dayfirstque controla se o dia ou o mês deve chegar primeiro se a data for ambígua. O padrão é Falso. Por exemplo

>>> 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
pode aceitar demais, por exemplo, parse('13/12/2001')é "13 de dezembro", mas parse('11/12/2001')é "12 de novembro" (o primeiro resultado sugere "11 de dezembro" aqui).
JFS

2
parsena verdade, usa um dayfirstargumento de palavra - chave que permite controlar isso. parse('11/12/2001', dayfirst=True)retornará "11 de dezembro" O padrão do dateutil édayfirst=False
Jacinda

você está perdendo o ponto que datetutil.parser.parse()aceita muitos formatos de hora (você pode encontrar outros exemplos com entrada ambígua). Se você deseja validar que sua entrada está no formato AAAA-MM-DD, a parse()função é a ferramenta errada.
JFS

1
Esse é um ponto completamente válido - se você realmente deseja restringir apenas esse formato específico, isso não faz isso, e a resposta aceita já faz um ótimo trabalho de fazer a coisa certa nesse caso. Acho que quando escrevi a resposta, pensava mais sobre como validar se era uma data válida, em oposição ao formato específico solicitado pelo autor, que quando as pessoas se deparam com essa pergunta é o que costumam fazer procurando por.
213 Jacinda

Existe uma maneira de .parse()retornar a string de formato além do datetimeobjeto?
Citynorman 5/10

35

Eu acho que a função de validação completa deve ficar assim:

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

Executando apenas

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

não é suficiente porque o método strptime não verifica se mês e dia do mês são números decimais preenchidos com zero. Por exemplo

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

será executado sem erros.


3
"Você está tecnicamente correto - o melhor tipo de correção". Eu precisava garantir isso nas minhas cordas.
delrocco

Isso funciona bem nos meus testes, no entanto, a documentação parece incorreta, pois indica: "% d -> dia do mês como um número decimal preenchido com zero -> 01, 02,…, 31" e o mesmo para% m -> Mês como um número decimal preenchido com zero. -> 01, 02,…, 12 docs.python.org/2/library/…
thanos.a

Se você precisa verificar se o mês e o dia são preenchidos com zero, não seria suficiente apenas verificar o comprimento da string e datetime.strptime(date_text, "%Y-%m-%d")?
Kyle Barron

17
from datetime import datetime

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

.. isso gera a ValueErrorse receber um formato incompatível.

..se você estiver lidando muito com datas e horas (no sentido de objetos de data e hora, em oposição a flutuadores de data e hora unix), é uma boa ideia olhar para o módulo pytz e, para storage / db, armazenar tudo no UTC .


2
Você foi mais rápido, eu mesmo teria postado ( ideone.com/vuxDDf ). Voto a favor.
Tadeck

..apenas o viu logo após ser publicado e, atualmente, trabalha com objetos de data e hora.
Mr. B

-7

Esta é a maneira mais fácil:

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

2
Seria melhor ter uma explicação, em vez de apenas código.
Lukas_o 22/03
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.