Data e Hora em Python – Carregando informações de uma API REST

Vamos fazer uma operação aparentemente simples mas que vai necessitar conhecimentos diversos. Queremos construir um pequeno programa que te dá a data e horário atual em diferentes lugares do mundo, ou seja em diferentes fuso horários. Para isto vamos consultar um serviço gratuito e utilizar um cliente de API REST em Python. Aprenderemos também a criar uma interface de linha de comando em que o usuário pode selecionar de uma lista. E por último vamos aprender a formatar data e hora em Python para poder exibir na tela.

O que é uma API REST?

API (Application Programming Interface), ou seja interface de programação para aplicações. Nós usuários utilizamos interfaces gráficas e utilizamos um mouse e teclado para conversar com sistemas. E os sistemas também precisam de uma maneira de se comunicar, o nome desta interface de comunicação entre sistemas é API.

Já o acrônimo REST vem do termo Representational State Transfer que significa estado de transferência representacional. O REST descreve uma arquitetura de comunicação dentre sistemas WEB. Nesta arquitetura existe sempre um cliente e um servidor e eles são totalmente independentes, ou seja, se o código do cliente for alterado ele não afeta o servidor e vice-versa. Existem várias características que fazem uma API ser REST, mas isto é um assunto para outro post.

Fazendo uma chamada com cliente REST a uma API em Python

Eu encontrei uma API pública que fornece data e hora de vários lugares do mundo. A World Time API se baseia nos fuso horários para te entregar o horário exato. Ela é uma API REST que devolve os dados em JSON. Veja o seguinte exemplo:

http://worldtimeapi.org/api/timezone/America/Sao_Paulo

{
   "abbreviation":"-03",
   "client_ip":"110.175.192.208",
   "datetime":"2020-09-17T07:23:17.946853-03:00",
   "day_of_week":4,
   "day_of_year":261,
   "dst":false,
   "dst_from":null,
   "dst_offset":0,
   "dst_until":null,
   "raw_offset":-10800,
   "timezone":"America/Sao_Paulo",
   "unixtime":1600338197,
   "utc_datetime":"2020-09-17T10:23:17.946853+00:00",
   "utc_offset":"-03:00",
   "week_number":38
}

O campo que nos interessa é o datetime que guarda o horário local no fuso horário que escolhemos. Para fazer a chamada a essa API vamos utilizar um pacote chamado requests. Eu gosto dele por que é muito simples de utilizar. Vamos iniciar fazendo a chamada à api, criando uma função que recebe o nome da timezone:

import requests
import datetimefrom datetime import datetime

def hora(timezone):
  url = 'http://worldtimeapi.org/api/timezone/' + timezone
  resposta = requests.get(url)
  hora = datetime.fromisoformat(resposta.json()['datetime'])
  return hora

Estamos utilizando o método .json() da resposta para transformar o resultado em um objeto JSON e então acessamos a propriedade datetime deste objeto. A função fromisoformat do objeto datetime consegue converter uma string de uma data no formato ISO 8601 em um objeto datetime do python. Podemos testar a função assim:

data = hora('America/Sao_Paulo')
print(data)

Precisamos então descobrir todos fuso horários disponíveis nesta api, vamos construir outra função para buscar esta informação, para isto vamos utilizar uma outra rota da api que devolve a lista completa:

def timezones_disponiveis():
  url = 'http://worldtimeapi.org/api/timezone/'
  resposta = requests.get(url)
  timezones = resposta.json()
  return timezones

print(timezones_disponiveis())
# ['Africa/Abidjan', 'Africa/Accra', 'Africa/Algiers', 'Africa/Bissau', 'Africa/Cairo', 'Africa/Casablanca', ....] 

Colhendo input de usuário em Python

Queremos dar a possibilidade do usuário escolher um fuso horário por isto precisamos apresentar esta lista de uma forma simples para ele selecionar. Mas como fazer isto de uma forma elegante em uma linha de comando? Pesquisei várias opções de bibliotecas para linha de comando em python e encontre uma chamada prompt_toolkit que é muito fácil de utilizar e tem uma interface para selecionar listas.

Vamos começar com uma versão simples, que pede para o usuário digitar o nome do fuso horário que ele dejeja:

fuso_horario = prompt('Fuso Horário:')
print(fuso_horario)

Muito bem, isto permitirá que o usuário digite o nome do fuso horário mas como ele poderá se o nome é válido ou quais são as opções de fuso horários disponíveis? O prompt_toolkit tem uma funcionalidade que serve exatamente para isto. Você passa uma lista de valores possíveis e ele se encarregar de fazer a funcionalidade de auto completar o que o usuário está digitando. Para isto é preciso utilizar uma classe chamada WordCompleter. Ela tem algumas opções:


disponiveis = timezones_disponiveis()
opcoes_timezone = WordCompleter(disponiveis, ignore_case=True, match_middle=True)

A lista das opções disponíveis é o primeiro parâmetro, utilizamos a lista que obtemos da API no passo anterior. O parâmetro ignore_case indica que devemos tratar maiúsculas e minúsculas como iguais, então se o usuário digitar “sao paulo” ou “Sao Paulo”, será interpretado igual. O parametro match_middle serve para indicar que estamos buscando a palavra digitada pelo usuário no meio da palavra também. Então se o usuário digitar “paulo” ou “paul” todas as palavras da lista que contiverem o termpo “paul” em qualquer posição da palavra, será retornado.

Depois de criar o objeto do WordCompleter devemos passá-lo ao prompt:

fuso_horario = prompt('Fuso Horário:', completer=opcoes_timezone)
print(fuso_horario)

Veja o resultado quando o usuário digita “ni”:

Seleção de fuso horário em cliente python

Validando o input do usuário em Python

Você vai notar uma coisa desta implementação, se o usuário digitar “enter” ele terá selecionado apenas a palavra “ni” e não existe este fuso horário. Precisamos garantir que o usuário irá escolher uma opção da lista. E para isto o prompt_toolkit tem mais uma funcionalidade: um validador. Precisamos criar uma classe que faz a validação do input do usuário. para isto podemos herdar a classe Validator do proompt_toolkit e implementar o método validate:

from prompt_toolkit.validation import Validator, ValidationError

class TimezoneValidador(Validator):
    def validate(self, document):
        timezone = document.text

        if timezone not in timezones_disponiveis():
            raise ValidationError(message='Timezone não encontrada:' + timezone)

O que este validador faz é garantir que o texto que está sendo digitado pelo usuário está presente na lista de fuso horários disponíveis. Se não estiver ele lança um erro de validação com o ValidationError incluindo a mensagem de erro que o usuário vai receber. Agora podemos incorporar o validador no nosso prompt:

fuso_horario = prompt('Fuso Horário:', completer=opcoes_timezone, validator=TimezoneValidador(), validate_while_typing=False)
print(fuso_horario)

O parâmetro validator recebe o validador que acabemos de criar e o parâmetro validate_while_typing informa que a validação só deve ser executada com o usuário seleciona uma das opções ou aperta “enter”. Veja como aparece a mensagem de erro quando o usuário digita uma opção incorreta:

Mensagem de erro ao validar input do usuário

Formatar Data em Python

O que nos resta fazer agora é imprimir a data e horário no fuso horário escolhido pelo usuário. Portanto precisamos apenas passar o fuso horário escolhido para a função hora que fizemos:

fuso_horario = prompt('Fuso Horário:', completer=opcoes_timezone, validator=TimezoneValidador(), validate_while_typing=False)
resultado = hora(fuso_horario)
print(resultado)
Formato padrão de data em Python
Formato padrão de data em Python

Note que o formato padrão de data não é muito amigável, precisamos melhorar isto. Para tal vamos utilizar uma função do Python para formatar datas em strings. Para isto vamos utilizar o método strftime do objeto datetime. Ele possui alguns operadores para indicar como queremos formatar a data:

Operadores da função strftime para formatar data e hora

OperadorSignificado
%ddia – número de 01 a 31
%-ddia – numero de 1 a 31 (sem o zero na frente)
%mmês – número de 01 a 12
%-mmês – número de 1 a 12 (sem o zero na frente)
%yano – número que representa o ano
%Hhora – no formato 24h
%Ihora – no formato 12h
%Mminuto – numero de 1 a 59 representando os minutos
%Ssegundos – numero de 01 a 59
%-Ssegundos – numero de 1 a 59 (sem o zero na frente)

Código fonte: https://repl.it/@julianajuliano/FusoHorario