Transforme registros de trabalho em uma tabela e gráfico de resumo mensal
Valide as datas e horas de trabalho em um CSV e depois salve as contagens mensais de registros e o total de horas como um CSV e um gráfico de barras.
Conteúdo verificado 2026.09.19Inclui arquivos de exemplo
Ver o sumário
A tradução foi feita com IA. Confira o código, as unidades e os valores junto com o original. A revisão por falantes nativos de cada idioma ainda não foi concluída. English
Para quem éProfissionais de escritório que querem lidar com resumos mensais recorrentes de trabalho usando código Python simples
Preparação
Tenha Python 3.12 e um terminal prontos. Verifique a versão com python --version.
Extraia todo o ZIP baixado e abra um terminal na pasta que contém example.py.
Comece com os dados de prática incluídos e depois compare os resultados com os arquivos originais.
Este exemplo usa work_log.csv e Matplotlib. O CSV deve usar encoding UTF-8 ou UTF-8 BOM.
01Comece definindo o que uma linha significa
Trate cada linha como um registro de trabalho e some hours ao mês que contém sua date. record_count é o número de linhas, não o número de pessoas nem de dias trabalhados. hours usa horas decimais. 1.50 significa 1 hora e 30 minutos, não 1 hora e 50 minutos.
Os dados incluídos contêm 9 registros fictícios de trabalho de janeiro a março de 2026. Este é um exercício de somar números existentes por mês, não uma ferramenta para medir tempo de trabalho nem avaliar desempenho.
02Verifique as colunas e valores de entrada
Coluna
Formato
Regra de validação
record_id
Texto como R001
Deve ser único dentro do arquivo
date
2026-01-06
YYYY-MM-DD; uma data que realmente exista
task
자료 정리
Não deve estar vazio
hours
2.50
Um número finito igual ou maior que 0, com até duas casas decimais
Não adicione title rows, total rows nem números contendo vírgulas. Se o script encontrar um duplicate ID, ele para para evitar dupla contagem. Records com IDs diferentes são contados separadamente mesmo que suas task descriptions sejam iguais.
03Prepare os arquivos e execute o exemplo
Extraia o ZIP e verifique se o input file listado em README.txt está na mesma pasta que example.py. Não execute o exemplo de dentro do ZIP archive.
Execute os commands abaixo, uma linha por vez, na pasta que contém example.py. No Windows, se python não estiver disponível mas py estiver, substitua python em cada command por py -3.12.
Depois que a completion message aparecer, abra a nova pasta outputs. Se outputs já existir, renomeie-a primeiro para preservar os resultados anteriores e depois execute o exemplo novamente.
A instalação requer conexão com a internet. BASE no código define os paths de input e output em relação a example.py, e não à terminal folder atual.
04Código completo e método de agregação
O código valida datas com date.fromisoformat e cria month keys no formato YYYY-MM. Ele soma hours com Decimal e os grava na tabela com duas casas decimais. Os values são convertidos para ordinary floating-point numbers apenas para plotting. Agg mode salva um PNG em vez de abrir uma chart window.
example.py
"""Summarize fictional work-log records by calendar month."""
import csv
import math
from collections import defaultdict
from datetime import date
from decimal import Decimal, InvalidOperation
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
BASE = Path(__file__).resolve().parent
HEADERS = ["record_id", "date", "task", "hours"]
def main():
destination = BASE / "outputs"
if destination.exists():
raise ValueError("outputs already exists; rename it before running again.")
totals = defaultdict(lambda: {"records": 0, "hours": Decimal("0")})
seen = set()
with (BASE / "work_log.csv").open(encoding="utf-8-sig", newline="") as file:
reader = csv.DictReader(file)
if reader.fieldnames != HEADERS:
raise ValueError(f"Expected headers: {HEADERS}")
for line, row in enumerate(reader, start=2):
if None in row or any(value is None or not value.strip() for value in row.values()):
raise ValueError(f"Row {line}: missing or extra field.")
if row["record_id"] in seen:
raise ValueError(f"Row {line}: duplicate record_id.")
seen.add(row["record_id"])
parsed_date = date.fromisoformat(row["date"])
if parsed_date.isoformat() != row["date"]:
raise ValueError(f"Row {line}: use YYYY-MM-DD dates.")
try:
hours = Decimal(row["hours"])
except InvalidOperation as error:
raise ValueError(f"Row {line}: hours must be a number.") from error
if not hours.is_finite() or hours < 0 or hours.as_tuple().exponent < -2:
raise ValueError(f"Row {line}: hours must be finite, nonnegative, with at most 2 decimals.")
month = parsed_date.strftime("%Y-%m")
totals[month]["records"] += 1
totals[month]["hours"] += hours
if not totals:
raise ValueError("No work records were found.")
months = sorted(totals)
figure, axis = plt.subplots(figsize=(8, 4.6), layout="constrained")
values = [float(totals[month]["hours"]) for month in months]
if not all(math.isfinite(value) and math.isfinite(value * 1.2) for value in values):
plt.close(figure)
raise ValueError("Monthly total is too large to plot as a finite number.")
bars = axis.bar(months, values, color="#2B6578", width=0.55)
axis.bar_label(bars, labels=[f"{value:.2f}" for value in values], padding=4)
axis.set(title="Monthly work hours | Fictional data", xlabel="Calendar month", ylabel="Hours")
axis.set_ylim(0, max(values) * 1.2 if max(values) > 0 else 1)
axis.spines[["top", "right"]].set_visible(False)
axis.set_axisbelow(True)
axis.grid(axis="y", alpha=0.2)
destination.mkdir(exist_ok=False)
with (destination / "monthly_summary.csv").open("x", encoding="utf-8-sig", newline="") as file:
writer = csv.writer(file)
writer.writerow(["month", "record_count", "total_hours"])
for month in months:
writer.writerow([month, totals[month]["records"], f"{totals[month]['hours']:.2f}"])
figure.savefig(destination / "monthly_hours.png", dpi=160)
plt.close(figure)
total_hours = sum((values["hours"] for values in totals.values()), Decimal("0"))
print(f"Records: {len(seen)}; months: {len(months)}; hours: {total_hours:.2f}")
print("Created outputs/monthly_summary.csv and outputs/monthly_hours.png.")
if __name__ == "__main__":
try:
main()
except (OSError, ValueError, csv.Error) as error:
raise SystemExit(f"Stopped: {error}") from error
05Leia a tabela de resumo e o gráfico
O script cria outputs/monthly_summary.csv e outputs/monthly_hours.png. O chart mostra apenas os months presentes no input, ordenados por year e month. Os axis labels em inglês permitem executar o exemplo sem instalar uma Korean font separada.
month
record_count
total_hours
2026-01
3
6.50
2026-02
3
7.50
2026-03
3
9.50
Total geral para verificação
9
23.50
Monthly hours chart for fictional work records. January: 6.5 hours; February: 7.5 hours; March: 9.5 hours.
06Verifique os totais e os limites entre meses
No summary CSV, verifique se janeiro totaliza 2.50 + 1.00 + 3.00 = 6.50 hours.
Verifique se a soma dos valores mensais de record_count corresponde aos 9 input records.
Verifique se total_hours soma 23.50 e compare o valor de cada mês com o número em sua chart bar.
Copie a practice folder, altere a date do último record para 2026-04-01 e execute novamente. Verifique se as hours são divididas em 5.50 para março e 4.00 para abril.
07Quando uma data ou número faz o script parar
Problema
Como corrigir
duplicate record_id
Verifique se o mesmo record foi inserido duas vezes.
day is out of range / Invalid isoformat
Verifique datas impossíveis como 2026-02-30 ou um date format incorreto.
hours must be a number
Digite apenas um número como 2.5 para hours. Remova unit labels e thousands separators.
hours must be finite…
Verifique valores negativos, NaN, Infinity ou mais de duas casas decimais.
Korean text appears garbled
Salve novamente o CSV original em UTF-8.
outputs already exists
Mantenha os resultados anteriores e depois renomeie a result folder.
08Conheça os limites antes de usar os resultados em um relatório
Records que contêm apenas dates são agrupados por calendar month. Start and end times, night shifts, time zones e tasks que atravessam a meia-noite não são tratados.
Months sem input não são adicionados como linhas com 0 hours. Missing records devem ser diferenciados de 0 hours reais.
Apenas duplicate IDs são bloqueados. Verifique nos dados originais se a mesma task foi inserida duas vezes com IDs diferentes.
O summary CSV e o PNG refletem os dados no momento da execução. Depois de editar o CSV, execute o script novamente para obter novos resultados.
Registro de execução e verificação
Windows 11 (10.0.26200), CPython 3.12.14 (64-bit). openpyxl 3.1.5, Matplotlib 3.10.8. As bibliotecas usadas por cada exemplo estão fixadas em requirements.txt.
Foram confirmadas 3 linhas mensais, 23.50 hours e 9 records
Foram verificados a criação do PNG e os resultados após alterar um record através de um month boundary
Foram verificadas datas inválidas, duplicate IDs, negative/NaN hours e header errors
Foram confirmados os hashes originais inalterados e a preservação dos resultados existentes
Limites da verificação
A correspondência com as aggregation rules de sistemas reais de HR ou attendance está fora do escopo da verificação.
O código de exemplo, os nomes de arquivos e as chaves de entrada são mantidos como no original. Consulte também os comandos e os procedimentos de conferência do texto traduzido.
Material de prática original · Guarde os arquivos originais separadamente antes de executar.
Fontes de referência
As explicações e os exemplos são de elaboração própria. Os comportamentos e conceitos relacionados podem ser consultados nas fontes oficiais abaixo.
Encontre linhas com correspondência exata nas quatro colunas e reúna-as em um novo arquivo do Excel junto com seus números de linha originais. Revise cada grupo de duplicatas, incluindo a primeira ocorrência.
Antes de transformar uma tabela em texto, alinhe o objeto, o período, o denominador e a unidade. Use uma tabela sintética de resultados mensais para verificar um valor que mudou de 80 % para 82 % e uma conversão de unidades, e depois monte uma lista de verificação reutilizável.
Combine planilhas que usam as mesmas colunas em uma única tabela do Excel, registrando de qual planilha cada linha veio. Uma pequena pasta de trabalho sintética permite verificar manualmente a ordem das linhas, as contagens e os totais.
Combine vários PDFs em um único arquivo, extraia um intervalo inclusivo de páginas para um segundo arquivo e verifique a contagem e a ordem das páginas resultantes. Um conjunto sintético de páginas em branco com dimensões deliberadamente diferentes torna o resultado verificável manualmente.