Saudações! No meu dia-a-dia, eu utilizo tanto o Windows 10 quando o Ubuntu 20.04 em dual boot (mais o segundo que o primeiro).
Entretanto, toda vez que eu entrava no Ubuntu e, mais tarde, no Windows, este se apresentava três horas adiantado (sim, o Windows à frente do tempo pode soar um paradoxo). A solução era, a cada novo boot, ir até as configurações, desligar a hora automática e ligar de novo. Porém somos desenvolvedores e essa era uma ótima oportunidade de se automatizar alguma coisa. Veja agora como criei um script em Python que atualiza automaticamente a hora do Windows sempre que o sistema é inicializado.
Antes de tudo, aos colegas que utilizam Linux religiosamente, também é possível fazer isso, usando outras bibliotecas e outro método. Não vou apresentar aqui porque o Linux (ao menos meu Ubuntu 20.04) é inteligente o suficiente para fazer isso out of the box durante a inicialização…
Isto posto, vamos aos trabalhos.
Um pouco de pesquisa
Diferente do que quem está começando a programar pode pensar, poucos programadores de fato sabem fazer qualquer coisa sem nenhuma consulta à internet. A verdade é que, como programadores, devemos saber descobrir de maneira efetiva a melhor forma de fazer algo, ter intuição e etc. Sendo assim, eu não sabia exatamente como definir a hora do Windows no Python. Eu já sabia que precisaria obter a hora de algum lugar, mas também não tinha decidido de onde.
Para começar a brincadeira, fui à internet procurar algumas bibliotecas que poderiam facilitar meu trabalho de definir a hora do sistema. Encontrei uma lib chamada pywin32 que permite, entre outras coisas, definir a hora do sistema.
A forma como ela faz isso é a seguinte:
# Sim, o import é diferente do nome canônico da biblioteca...
import win32api
# A hora deve ser atribuída em fuso UTC (ou GMT, a hora do pacífico).
# O fuso horário correto é definido nas configurações do sistema operacional.
win32api.SetSystemTime(year, month, weekday, day, hour, minutes, seconds, milliseconds)
Ótimo. Agora eu só precisava obter a hora correta na internet. A ideia inicial foi entrar em algum site oficial e usar web scraping para obter a hora atual. Como eu falei acima sobre intuição, um alerta piscante surgiu imediatamente na minha cabeça dizendo overengineering (engenharia excessiva, tipo construir uma ponte Rio-Niterói para um carrinho de controle remoto: funciona, mas não é uma boa ideia). Provavelmente existia alguma API pra obter isso, me restando apenas uma pesquisa decente e uma linha de código.
Como em qualquer dia normal, caí no StackOverflow e encontrei um serviço que retorna nada mais que a hora atual em formato ISO (esse formato da imagem abaixo). Perfeito! Era exatamente o que eu queria.
Usando um parâmetro get ?f=
também é possível obter a data em outros formatos, mas não vem ao caso.
Com isso tudo em mãos, bastava obter a hora (e já sabemos como), definir no sistema operacional (o que também sabemos como) e fazer isso inicializar com o sistema (isso a gente resolve mais tarde hehe).
Coding time
Abaixo o código comentado de como fiz as duas primeiras coisas.
import os
from datetime import datetime
import urllib3
import win32api
import logging
# Fazemos a requisição aqui
response = urllib3.PoolManager().request('GET', "http://just-the-time.appspot.com")
# Se o status HTTP não for 200 (OK), paramos tudo.
if response.status != 200:
logging.error(f"Server responded with status {response.status}.")
os.exit(1)
# Agora que sabemos que o status code é 200, isso significa que response.data contém o
# corpo do retorno da página. No caso, apenas a data e a hora no formato iso.
# Vamos obtê-las separadas
date, time = response.data.decode('utf-8').strip().split(' ')
# E agora obtemos cada parâmetro, convertemos para inteiro e
# atribuímos a novas variáveis
hour, minutes, seconds = list(map(int, time.split(':')))
year, month, day = list(map(int, date.split('-')))
# Precisamos calcular o dia da semana com o datetime e vamos
# deixar os milissegundos em zero mesmo.
time_tuple = (
year,
month,
datetime(year, month, day).weekday(),
day,
hour,
minutes,
seconds,
0
)
# A grande "hora" (haha)
win32api.SetSystemTime(*time_tuple)
A última linha, se você não está acostumadx com Python, está “desestruturando” a tupla e passando cada elemento como um argumento. Por exemplo, as duas chamadas de funções a seguir são idênticas:
def soma(a: float, b: float) -> float:
return a + b
# As duas chamadas abaixo fazem exatamente a mesma coisa.
soma(a, b)
soma(*(a, b))
Para alterar a hora do sistema, é necessário obter permissões elevadas. Isso significa que você deve executar seu Terminal como administrador (para o
cmd.exe
, tecle Win + R, digitecmd
e tecle Ctrl + Shift + Alt + Enter e dê a permissão).
Criando um executável
Para criar um executável que funcione standalone, sem precisar executar via linha de comando, podemos usar o pyinstaller, biblioteca muito simples de usar. Para criar um executável a partir do arquivo principal main.py
, tudo o que precisamos é fazer o seguinte na linha de comando (permissões elevadas podem ser necessárias):
> cd seu_diretorio\
> pip install pyinstaller
> pyinstaller main.py --onefile --uac-admin
Isso vai instalar o pyinstaller (como num Inception, tipo usar o Explorer pra baixar o Chrome) e criar um único executável (--onefile
) que exige permissões administrativas (--uac-admin
) a partir de main.py
, que é o arquivo de entrada (nesse caso, o único) do nosso programa.
Você pode definir outras opções. Acesse a documentação oficial para ver quais estão disponíveis.
Acesse a pasta dist\
, copie seu executável e mova para algum lugar de seu interesse (ou deixe aí mesmo). Eu coloquei em C:\Program Files\current_hour_setter\current_hour_setter.exe
.
Inicializando tudo com o Windows
Essa é talvez a parte mais demorada. Vamos criar uma tarefa no agendador de tarefas do Windows que executa um prompt de comando com permissões administrativas e, daí, executa nosso executável com as permissões corretas. Em seguida, vamos fazer isso ser executado junto com o sistema.
Executando o programa com permissões administrativas sem o prompt
O que faremos aqui é executar o nosso script com permissão administrativa sem passar pelo popup típico de permissão do Windows (UAC credential prompt).
Esse procedimento foi removido de um fórum (em inglês) que também apresenta um método automático usando um arquivo bat. Eu, no entanto, não recomendo (e não fiz). O método manual segue.
-
Aperte Win + R e digite
taskschd.msc
, confirmando em seguida. -
Clique em Biblioteca do Agendador
-
Clique em Criar Tarefa…
-
Em Nome, coloque um nome para a sua tarefa (e anote). Em Descrição, faça o mesmo. Marque a caixa “Executar com privilégios mais altos” e defina “Configurar para: Windows 10”.
-
Clique na guia Ações e no botão Novo… Na janela que abrir, defina o Programa/Script como
cmd.exe
.
Assim, estamos criando uma tarefa que executa um cmd.exe
com permissões elevadas.
- Vamos também executar nosso script. Adicione, no campo “Adicione argumentos (opcional)”, o seguinte:
/c start "Nome da Tarefa" "C:\Program Files\current_hour_setter\current_hour_setter.exe"
No lugar de “Nome da Tarefa”, coloque o nome da tarefa definido no passo 4. Substitua o caminho para o caminho do seu executável. Clique em OK quantas vezes forem necessário e feche o agendador de tarefas (mantendo o nome da sua tarefa anotado).
Agora temos uma tarefa que abre um prompt de comando elevado e executa o nosso executável com as mesmas permissões.
Executando tudo na inicialização do sistema
- Clique com o botão direito no seu desktop ou em alguma pasta vazia, vá até Novo… e clique Atalho.
- No endereço, coloque o seguinte, substituindo o nome da tarefa pelo correto.
schtasks /run /tn "Nome da Tarefa"
- Salve com um nome adequado.
- Mova esse atalho para a pasta de inicialização do Windows.
- Para fazer isso apenas no usuário atual, mova para:
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup
- Para fazer isso para todos os usuários do sistema, mova para:
%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\StartUp
Deixe seu sistema com a hora incorreta e reinicie. Se tudo deu certo, seu relógio deve ser corrigido alguns segundos após a inicialização.
Conclusão
Esta foi uma tentativa de mostrar como a programação não é algo exatamente complicado (configurar o Windows foi bem mais trabalhoso) e também como pode ser feito para resolver problemas reais na vida.
Se você quer começar a programar, confira meu curso de Algoritmos com Portugol Studio no Youtube.
Comentários
Postar um comentário