diff --git a/README.md b/README.md index 8411c33..1796608 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Detailed explanations: The project foundation is complete. Phase 0 established the multilingual documentation, contribution workflow, collaboration templates, community standards, authorship, licensing, AI governance, automated quality checks, original visual identity, scalable repository structure, and final foundation audit. -The project foundation and seven complete educational sections are available, and [Phase 8: Standard Library](standard-library/README.md) is now in progress with [Chapter 01: `pathlib`](standard-library/01-pathlib/README.md). [Phase 7: Errors, Files, and Modules](errors-files-and-modules/README.md) is complete with five reviewed chapters. [Phase 1: Fundamentals](fundamentals/README.md) provides six reviewed beginner chapters. Phase 6 contains six reviewed learning chapters: +The project foundation and seven complete educational sections are available, and [Phase 8: Standard Library](standard-library/README.md) is now in progress with [Chapter 01: `pathlib`](standard-library/01-pathlib/README.md) and [Chapter 02: `datetime`](standard-library/02-datetime/README.md). [Phase 7: Errors, Files, and Modules](errors-files-and-modules/README.md) is complete with five reviewed chapters. [Phase 1: Fundamentals](fundamentals/README.md) provides six reviewed beginner chapters. Phase 6 contains six reviewed learning chapters: - [Comments in Python](comments-and-documentation/01-comments/README.md) - [Docstrings in Python](comments-and-documentation/02-docstrings/README.md) @@ -85,7 +85,7 @@ The project foundation and seven complete educational sections are available, an - [Comments versus Logging in Python](comments-and-documentation/05-comments-vs-logging/README.md) - [PEP 8 and Readability in Python](comments-and-documentation/06-pep8-and-readability/README.md) -Phases 1, 2, 3, 4, 5, 6, and 7 are complete. Phase 8 is in progress with [Working with Filesystem Paths Using `pathlib`](standard-library/01-pathlib/README.md), which introduces path objects, portable composition, path inspection, filesystem queries, directory traversal, globbing, text helpers, and the boundary between state checks and operation failures. Phase 7 contains five reviewed chapters: exception handling; deliberate raising and custom exceptions; safe file handling with `open()` and `with`; [Working with TXT, CSV, and JSON](errors-files-and-modules/04-txt-csv-and-json/README.md); and [Organizing Code with Imports, Modules, and Packages](errors-files-and-modules/05-imports-modules-and-packages/README.md), which closes the phase with explicit module imports, regular package structure, the main guard, import search context, absolute and relative imports, `python -m`, and dependency design. Phase 5: Functions contains nine reviewed chapters: [Defining and Calling Functions](functions/01-defining-and-calling-functions/README.md), [Parameters and Arguments](functions/02-parameters-and-arguments/README.md), [Return Values](functions/03-return-values/README.md), [Scope](functions/04-scope/README.md), [Type Hints](functions/05-type-hints/README.md), [Default Values](functions/06-default-values/README.md), [`*args` and `**kwargs`](functions/07-args-and-kwargs/README.md), [Functions Working Together](functions/08-functions-working-together/README.md), and [Data Flow Between Functions](functions/09-data-flow-between-functions/README.md). Together they establish function definition and calling, required input flow, returned results, local and global scope, typed interfaces, safe optional inputs, intentionally flexible positional and keyword argument collection, composition through helpers and coordinators, and explicit caller-to-parameter-to-return data flow including rebinding versus mutation. Phase 4 remains complete with eight reviewed Program Flow chapters, ending with [Choosing and Combining Program Flow](program-flow/08-choosing-and-combining-program-flow/README.md). Phase 3 contains six reviewed Collections chapters, ending with [Choosing the Right Collection](collections/06-choosing-the-right-collection/README.md). Phase 2 remains complete with four reviewed chapters, ending with [Numeric Built-ins](strings-and-numbers/04-numeric-builtins/README.md). See the [roadmap](docs/roadmap.en.md) or the [full learning path](docs/learning-path.en.md) for the current curriculum status and direct chapter links. +Phases 1, 2, 3, 4, 5, 6, and 7 are complete. Phase 8 is in progress with [Working with Filesystem Paths Using `pathlib`](standard-library/01-pathlib/README.md) and [Working with Dates and Time Calculations Using `datetime`](standard-library/02-datetime/README.md). Together they introduce path-aware filesystem work plus explicit date/time types, durations, parsing, formatting, timezone awareness, UTC conversion, and deterministic time arithmetic. Phase 7 contains five reviewed chapters: exception handling; deliberate raising and custom exceptions; safe file handling with `open()` and `with`; [Working with TXT, CSV, and JSON](errors-files-and-modules/04-txt-csv-and-json/README.md); and [Organizing Code with Imports, Modules, and Packages](errors-files-and-modules/05-imports-modules-and-packages/README.md), which closes the phase with explicit module imports, regular package structure, the main guard, import search context, absolute and relative imports, `python -m`, and dependency design. Phase 5: Functions contains nine reviewed chapters: [Defining and Calling Functions](functions/01-defining-and-calling-functions/README.md), [Parameters and Arguments](functions/02-parameters-and-arguments/README.md), [Return Values](functions/03-return-values/README.md), [Scope](functions/04-scope/README.md), [Type Hints](functions/05-type-hints/README.md), [Default Values](functions/06-default-values/README.md), [`*args` and `**kwargs`](functions/07-args-and-kwargs/README.md), [Functions Working Together](functions/08-functions-working-together/README.md), and [Data Flow Between Functions](functions/09-data-flow-between-functions/README.md). Together they establish function definition and calling, required input flow, returned results, local and global scope, typed interfaces, safe optional inputs, intentionally flexible positional and keyword argument collection, composition through helpers and coordinators, and explicit caller-to-parameter-to-return data flow including rebinding versus mutation. Phase 4 remains complete with eight reviewed Program Flow chapters, ending with [Choosing and Combining Program Flow](program-flow/08-choosing-and-combining-program-flow/README.md). Phase 3 contains six reviewed Collections chapters, ending with [Choosing the Right Collection](collections/06-choosing-the-right-collection/README.md). Phase 2 remains complete with four reviewed chapters, ending with [Numeric Built-ins](strings-and-numbers/04-numeric-builtins/README.md). See the [roadmap](docs/roadmap.en.md) or the [full learning path](docs/learning-path.en.md) for the current curriculum status and direct chapter links. ## Visual identity diff --git a/docs/learning-path.en.md b/docs/learning-path.en.md index cd9e3c0..f26b68b 100644 --- a/docs/learning-path.en.md +++ b/docs/learning-path.en.md @@ -104,8 +104,9 @@ Phase 7 is complete with five reviewed chapters. Chapters 01–02 establish exce [Open the Standard Library section index](../standard-library/README.md) 1. [Working with Filesystem Paths Using `pathlib`](../standard-library/01-pathlib/README.md) +2. [Working with Dates and Time Calculations Using `datetime`](../standard-library/02-datetime/README.md) -Phase 8 is in progress. Chapter 01 introduces path objects, portable path composition, filesystem inspection, directory traversal, globbing, text helpers, and safe operation boundaries. The next planned chapter is **`datetime` and Time Calculations**. +Phase 8 is in progress. Chapter 01 introduces path objects and filesystem boundaries. Chapter 02 adds dates, times, durations, parsing, formatting, naive versus aware datetimes, fixed UTC offsets, timezone conversion, and deterministic time calculations. The next planned chapter is **`json` Beyond Basic Persistence**. ## Phase 9 · External Libraries ⏳ diff --git a/docs/learning-path.es.md b/docs/learning-path.es.md index 057653d..2bdc7a5 100644 --- a/docs/learning-path.es.md +++ b/docs/learning-path.es.md @@ -104,8 +104,9 @@ La Fase 7 está completada con cinco capítulos revisados. Los Capítulos 01–0 [Abrir el índice de la sección Biblioteca Estándar](../standard-library/README.es.md) 1. [Trabajar con Rutas del Sistema de Archivos Usando `pathlib`](../standard-library/01-pathlib/README.es.md) +2. [Trabajar con Fechas y Cálculos de Tiempo Usando `datetime`](../standard-library/02-datetime/README.es.md) -La Fase 8 está en progreso. El Capítulo 01 introduce objetos de ruta, composición portable, inspección del filesystem, recorrido de directorios, globbing, helpers de texto y límites seguros de operación. El próximo capítulo planificado es **`datetime` y Cálculos de Tiempo**. +La Fase 8 está en progreso. El Capítulo 01 introduce objetos de ruta y límites del filesystem. El Capítulo 02 añade fechas, horas, duraciones, parsing, formato, datetimes naive frente a aware, offsets UTC fijos, conversión de timezone y cálculos de tiempo deterministas. El próximo capítulo planificado es **`json` Más Allá de la Persistencia Básica**. ## Fase 9 · Bibliotecas Externas ⏳ diff --git a/docs/learning-path.pt-BR.md b/docs/learning-path.pt-BR.md index 7b7ecf4..0a1b656 100644 --- a/docs/learning-path.pt-BR.md +++ b/docs/learning-path.pt-BR.md @@ -104,8 +104,9 @@ A Fase 7 está concluída com cinco capítulos revisados. Os Capítulos 01–02 [Abrir o índice da seção Biblioteca Padrão](../standard-library/README.pt-BR.md) 1. [Trabalhando com Caminhos do Sistema de Arquivos Usando `pathlib`](../standard-library/01-pathlib/README.pt-BR.md) +2. [Trabalhando com Datas e Cálculos de Tempo Usando `datetime`](../standard-library/02-datetime/README.pt-BR.md) -A Fase 8 está em andamento. O Capítulo 01 introduz objetos de caminho, composição portável, inspeção do filesystem, percurso de diretórios, globbing, helpers de texto e fronteiras seguras de operação. O próximo capítulo planejado é **`datetime` e Cálculos de Tempo**. +A Fase 8 está em andamento. O Capítulo 01 introduz objetos de caminho e fronteiras do filesystem. O Capítulo 02 acrescenta datas, horários, durações, parsing, formatação, datetimes naive versus aware, offsets UTC fixos, conversão de timezone e cálculos de tempo determinísticos. O próximo capítulo planejado é **`json` Além da Persistência Básica**. ## Fase 9 · Bibliotecas Externas ⏳ diff --git a/docs/localized/README.es.md b/docs/localized/README.es.md index 275d345..d2bf0e1 100644 --- a/docs/localized/README.es.md +++ b/docs/localized/README.es.md @@ -76,7 +76,7 @@ Explicaciones detalladas: La base del proyecto está completada. La Fase 0 estableció la documentación multilingüe, el flujo de contribución, las plantillas de colaboración, los estándares de la comunidad, la autoría, la licencia, la gobernanza de IA, las verificaciones automáticas, la identidad visual original, la estructura escalable y la auditoría final de la base. -La base del proyecto y siete secciones educativas completas están disponibles, y la [Fase 8: Biblioteca Estándar](../../standard-library/README.es.md) está ahora en progreso con el [Capítulo 01: `pathlib`](../../standard-library/01-pathlib/README.es.md). La [Fase 7: Errores, Archivos y Módulos](../../errors-files-and-modules/README.es.md) está completada con cinco capítulos revisados. La [Fase 1: Fundamentos](../../fundamentals/README.es.md) ofrece seis capítulos revisados para principiantes. La Fase 6 reúne seis capítulos de aprendizaje revisados: +La base del proyecto y siete secciones educativas completas están disponibles, y la [Fase 8: Biblioteca Estándar](../../standard-library/README.es.md) está ahora en progreso con el [Capítulo 01: `pathlib`](../../standard-library/01-pathlib/README.es.md) y el [Capítulo 02: `datetime`](../../standard-library/02-datetime/README.es.md). La [Fase 7: Errores, Archivos y Módulos](../../errors-files-and-modules/README.es.md) está completada con cinco capítulos revisados. La [Fase 1: Fundamentos](../../fundamentals/README.es.md) ofrece seis capítulos revisados para principiantes. La Fase 6 reúne seis capítulos de aprendizaje revisados: - [Comentarios en Python](../../comments-and-documentation/01-comments/README.es.md) - [Docstrings en Python](../../comments-and-documentation/02-docstrings/README.es.md) @@ -85,7 +85,7 @@ La base del proyecto y siete secciones educativas completas están disponibles, - [Comentarios frente a Logging en Python](../../comments-and-documentation/05-comments-vs-logging/README.es.md) - [PEP 8 y Legibilidad en Python](../../comments-and-documentation/06-pep8-and-readability/README.es.md) -Las Fases 1, 2, 3, 4, 5, 6 y 7 están completadas. La Fase 8 está en progreso con [Trabajar con Rutas del Sistema de Archivos Usando `pathlib`](../../standard-library/01-pathlib/README.es.md), que introduce objetos de ruta, composición portable, inspección de rutas, consultas al filesystem, recorrido de directorios, globbing, helpers de texto y el límite entre comprobaciones de estado y fallos de operación. La Fase 7 reúne cinco capítulos revisados: manejo de excepciones; lanzamiento y excepciones personalizadas; uso seguro de archivos con `open()` y `with`; [Trabajar con TXT, CSV y JSON](../../errors-files-and-modules/04-txt-csv-and-json/README.es.md); y [Organizar Código con Imports, Módulos y Paquetes](../../errors-files-and-modules/05-imports-modules-and-packages/README.es.md), que cierra la fase con imports explícitos de módulos, estructura de paquete regular, main guard, contexto de búsqueda de imports, imports absolutos y relativos, `python -m` y diseño de dependencias. La Fase 5: Funciones reúne nueve capítulos revisados: [Definir y Llamar Funciones](../../functions/01-defining-and-calling-functions/README.es.md), [Parámetros y Argumentos](../../functions/02-parameters-and-arguments/README.es.md), [Valores de Retorno](../../functions/03-return-values/README.es.md), [Alcance](../../functions/04-scope/README.es.md), [Type Hints](../../functions/05-type-hints/README.es.md), [Valores Predeterminados](../../functions/06-default-values/README.es.md), [`*args` y `**kwargs`](../../functions/07-args-and-kwargs/README.es.md), [Funciones Trabajando Juntas](../../functions/08-functions-working-together/README.es.md) y [Flujo de Datos Entre Funciones](../../functions/09-data-flow-between-functions/README.es.md). Juntos establecen definición y llamada, flujo de entrada obligatorio, resultados retornados, alcance local y global, interfaces tipadas, entradas opcionales seguras, recolección intencionalmente flexible de argumentos posicionales y por palabra clave, composición mediante funciones auxiliares y coordinadoras y flujo explícito desde el llamador hacia parámetros y retornos, incluida la reasignación frente a la mutación. La Fase 4 permanece completada con ocho capítulos revisados de Flujo del Programa, terminando con [Elegir y Combinar el Flujo del Programa](../../program-flow/08-choosing-and-combining-program-flow/README.es.md). La Fase 3 reúne seis capítulos revisados de Colecciones, terminando con [Elegir la Colección Adecuada](../../collections/06-choosing-the-right-collection/README.es.md). La Fase 2 permanece completada con cuatro capítulos revisados, terminando con [Funciones Numéricas Incorporadas](../../strings-and-numbers/04-numeric-builtins/README.es.md). Consulta el [roadmap](../roadmap.es.md) o la [ruta completa de aprendizaje](../learning-path.es.md) para seguir el estado del currículo y acceder directamente a los capítulos. +Las Fases 1, 2, 3, 4, 5, 6 y 7 están completadas. La Fase 8 está en progreso con [Trabajar con Rutas del Sistema de Archivos Usando `pathlib`](../../standard-library/01-pathlib/README.es.md) y [Trabajar con Fechas y Cálculos de Tiempo Usando `datetime`](../../standard-library/02-datetime/README.es.md). Juntos introducen trabajo de filesystem orientado a rutas y tipos explícitos de fecha/hora, duraciones, parsing, formato, conciencia de timezone, conversión UTC y aritmética de tiempo determinista. La Fase 7 reúne cinco capítulos revisados: manejo de excepciones; lanzamiento y excepciones personalizadas; uso seguro de archivos con `open()` y `with`; [Trabajar con TXT, CSV y JSON](../../errors-files-and-modules/04-txt-csv-and-json/README.es.md); y [Organizar Código con Imports, Módulos y Paquetes](../../errors-files-and-modules/05-imports-modules-and-packages/README.es.md), que cierra la fase con imports explícitos de módulos, estructura de paquete regular, main guard, contexto de búsqueda de imports, imports absolutos y relativos, `python -m` y diseño de dependencias. La Fase 5: Funciones reúne nueve capítulos revisados: [Definir y Llamar Funciones](../../functions/01-defining-and-calling-functions/README.es.md), [Parámetros y Argumentos](../../functions/02-parameters-and-arguments/README.es.md), [Valores de Retorno](../../functions/03-return-values/README.es.md), [Alcance](../../functions/04-scope/README.es.md), [Type Hints](../../functions/05-type-hints/README.es.md), [Valores Predeterminados](../../functions/06-default-values/README.es.md), [`*args` y `**kwargs`](../../functions/07-args-and-kwargs/README.es.md), [Funciones Trabajando Juntas](../../functions/08-functions-working-together/README.es.md) y [Flujo de Datos Entre Funciones](../../functions/09-data-flow-between-functions/README.es.md). Juntos establecen definición y llamada, flujo de entrada obligatorio, resultados retornados, alcance local y global, interfaces tipadas, entradas opcionales seguras, recolección intencionalmente flexible de argumentos posicionales y por palabra clave, composición mediante funciones auxiliares y coordinadoras y flujo explícito desde el llamador hacia parámetros y retornos, incluida la reasignación frente a la mutación. La Fase 4 permanece completada con ocho capítulos revisados de Flujo del Programa, terminando con [Elegir y Combinar el Flujo del Programa](../../program-flow/08-choosing-and-combining-program-flow/README.es.md). La Fase 3 reúne seis capítulos revisados de Colecciones, terminando con [Elegir la Colección Adecuada](../../collections/06-choosing-the-right-collection/README.es.md). La Fase 2 permanece completada con cuatro capítulos revisados, terminando con [Funciones Numéricas Incorporadas](../../strings-and-numbers/04-numeric-builtins/README.es.md). Consulta el [roadmap](../roadmap.es.md) o la [ruta completa de aprendizaje](../learning-path.es.md) para seguir el estado del currículo y acceder directamente a los capítulos. ## Identidad visual diff --git a/docs/localized/README.pt-BR.md b/docs/localized/README.pt-BR.md index f1a4f01..fa10284 100644 --- a/docs/localized/README.pt-BR.md +++ b/docs/localized/README.pt-BR.md @@ -76,7 +76,7 @@ Explicações detalhadas: A fundação do projeto está concluída. A Fase 0 estabeleceu a documentação multilíngue, o fluxo de contribuição, os templates de colaboração, os padrões da comunidade, a autoria, a licença, a governança de IA, as validações automáticas, a identidade visual original, a estrutura escalável e a auditoria final da fundação. -A fundação do projeto e sete seções educacionais completas estão disponíveis, e a [Fase 8: Biblioteca Padrão](../../standard-library/README.pt-BR.md) agora está em andamento com o [Capítulo 01: `pathlib`](../../standard-library/01-pathlib/README.pt-BR.md). A [Fase 7: Erros, Arquivos e Módulos](../../errors-files-and-modules/README.pt-BR.md) está concluída com cinco capítulos revisados. A [Fase 1: Fundamentos](../../fundamentals/README.pt-BR.md) oferece seis capítulos revisados para iniciantes. A Fase 6 reúne seis capítulos de aprendizagem revisados: +A fundação do projeto e sete seções educacionais completas estão disponíveis, e a [Fase 8: Biblioteca Padrão](../../standard-library/README.pt-BR.md) agora está em andamento com o [Capítulo 01: `pathlib`](../../standard-library/01-pathlib/README.pt-BR.md) e o [Capítulo 02: `datetime`](../../standard-library/02-datetime/README.pt-BR.md). A [Fase 7: Erros, Arquivos e Módulos](../../errors-files-and-modules/README.pt-BR.md) está concluída com cinco capítulos revisados. A [Fase 1: Fundamentos](../../fundamentals/README.pt-BR.md) oferece seis capítulos revisados para iniciantes. A Fase 6 reúne seis capítulos de aprendizagem revisados: - [Comentários em Python](../../comments-and-documentation/01-comments/README.pt-BR.md) - [Docstrings em Python](../../comments-and-documentation/02-docstrings/README.pt-BR.md) @@ -85,7 +85,7 @@ A fundação do projeto e sete seções educacionais completas estão disponíve - [Comentários versus Logging em Python](../../comments-and-documentation/05-comments-vs-logging/README.pt-BR.md) - [PEP 8 e Legibilidade em Python](../../comments-and-documentation/06-pep8-and-readability/README.pt-BR.md) -As Fases 1, 2, 3, 4, 5, 6 e 7 estão concluídas. A Fase 8 está em andamento com [Trabalhando com Caminhos do Sistema de Arquivos Usando `pathlib`](../../standard-library/01-pathlib/README.pt-BR.md), que introduz objetos de caminho, composição portável, inspeção de caminhos, consultas ao filesystem, percurso de diretórios, globbing, helpers de texto e a fronteira entre verificações de estado e falhas de operação. A Fase 7 reúne cinco capítulos revisados: tratamento de exceções; levantamento e exceções personalizadas; uso seguro de arquivos com `open()` e `with`; [Trabalhando com TXT, CSV e JSON](../../errors-files-and-modules/04-txt-csv-and-json/README.pt-BR.md); e [Organizando Código com Imports, Módulos e Pacotes](../../errors-files-and-modules/05-imports-modules-and-packages/README.pt-BR.md), que encerra a fase com imports explícitos de módulos, estrutura de pacote regular, main guard, contexto de busca de imports, imports absolutos e relativos, `python -m` e design de dependências. A Fase 5: Funções reúne nove capítulos revisados: [Definindo e Chamando Funções](../../functions/01-defining-and-calling-functions/README.pt-BR.md), [Parâmetros e Argumentos](../../functions/02-parameters-and-arguments/README.pt-BR.md), [Valores de Retorno](../../functions/03-return-values/README.pt-BR.md), [Escopo](../../functions/04-scope/README.pt-BR.md), [Type Hints](../../functions/05-type-hints/README.pt-BR.md), [Valores Padrão](../../functions/06-default-values/README.pt-BR.md), [`*args` e `**kwargs`](../../functions/07-args-and-kwargs/README.pt-BR.md), [Funções Trabalhando Juntas](../../functions/08-functions-working-together/README.pt-BR.md) e [Fluxo de Dados Entre Funções](../../functions/09-data-flow-between-functions/README.pt-BR.md). Juntos, eles estabelecem definição e chamada, fluxo de entrada obrigatório, resultados retornados, escopo local e global, interfaces tipadas, entradas opcionais seguras, coleta intencionalmente flexível de argumentos posicionais e nomeados, composição por funções auxiliares e coordenadoras e fluxo explícito do chamador aos parâmetros e retornos, incluindo reatribuição versus mutação. A Fase 4 permanece concluída com oito capítulos revisados de Fluxo do Programa, encerrando com [Escolhendo e Combinando o Fluxo do Programa](../../program-flow/08-choosing-and-combining-program-flow/README.pt-BR.md). A Fase 3 reúne seis capítulos revisados de Coleções, encerrando com [Escolhendo a Coleção Certa](../../collections/06-choosing-the-right-collection/README.pt-BR.md). A Fase 2 permanece concluída com quatro capítulos revisados, encerrando com [Funções Numéricas Embutidas](../../strings-and-numbers/04-numeric-builtins/README.pt-BR.md). Consulte o [roadmap](../roadmap.pt-BR.md) ou a [trilha completa de estudos](../learning-path.pt-BR.md) para acompanhar o status do currículo e acessar os capítulos diretamente. +As Fases 1, 2, 3, 4, 5, 6 e 7 estão concluídas. A Fase 8 está em andamento com [Trabalhando com Caminhos do Sistema de Arquivos Usando `pathlib`](../../standard-library/01-pathlib/README.pt-BR.md) e [Trabalhando com Datas e Cálculos de Tempo Usando `datetime`](../../standard-library/02-datetime/README.pt-BR.md). Juntos, eles introduzem trabalho de filesystem orientado a caminhos e tipos explícitos de data/hora, durações, parsing, formatação, consciência de timezone, conversão UTC e aritmética de tempo determinística. A Fase 7 reúne cinco capítulos revisados: tratamento de exceções; levantamento e exceções personalizadas; uso seguro de arquivos com `open()` e `with`; [Trabalhando com TXT, CSV e JSON](../../errors-files-and-modules/04-txt-csv-and-json/README.pt-BR.md); e [Organizando Código com Imports, Módulos e Pacotes](../../errors-files-and-modules/05-imports-modules-and-packages/README.pt-BR.md), que encerra a fase com imports explícitos de módulos, estrutura de pacote regular, main guard, contexto de busca de imports, imports absolutos e relativos, `python -m` e design de dependências. A Fase 5: Funções reúne nove capítulos revisados: [Definindo e Chamando Funções](../../functions/01-defining-and-calling-functions/README.pt-BR.md), [Parâmetros e Argumentos](../../functions/02-parameters-and-arguments/README.pt-BR.md), [Valores de Retorno](../../functions/03-return-values/README.pt-BR.md), [Escopo](../../functions/04-scope/README.pt-BR.md), [Type Hints](../../functions/05-type-hints/README.pt-BR.md), [Valores Padrão](../../functions/06-default-values/README.pt-BR.md), [`*args` e `**kwargs`](../../functions/07-args-and-kwargs/README.pt-BR.md), [Funções Trabalhando Juntas](../../functions/08-functions-working-together/README.pt-BR.md) e [Fluxo de Dados Entre Funções](../../functions/09-data-flow-between-functions/README.pt-BR.md). Juntos, eles estabelecem definição e chamada, fluxo de entrada obrigatório, resultados retornados, escopo local e global, interfaces tipadas, entradas opcionais seguras, coleta intencionalmente flexível de argumentos posicionais e nomeados, composição por funções auxiliares e coordenadoras e fluxo explícito do chamador aos parâmetros e retornos, incluindo reatribuição versus mutação. A Fase 4 permanece concluída com oito capítulos revisados de Fluxo do Programa, encerrando com [Escolhendo e Combinando o Fluxo do Programa](../../program-flow/08-choosing-and-combining-program-flow/README.pt-BR.md). A Fase 3 reúne seis capítulos revisados de Coleções, encerrando com [Escolhendo a Coleção Certa](../../collections/06-choosing-the-right-collection/README.pt-BR.md). A Fase 2 permanece concluída com quatro capítulos revisados, encerrando com [Funções Numéricas Embutidas](../../strings-and-numbers/04-numeric-builtins/README.pt-BR.md). Consulte o [roadmap](../roadmap.pt-BR.md) ou a [trilha completa de estudos](../learning-path.pt-BR.md) para acompanhar o status do currículo e acessar os capítulos diretamente. ## Identidade visual diff --git a/docs/project-structure.en.md b/docs/project-structure.en.md index eb68f84..6380447 100644 --- a/docs/project-structure.en.md +++ b/docs/project-structure.en.md @@ -388,15 +388,24 @@ python-study-guide/ │ ├── README.md │ ├── README.pt-BR.md │ ├── README.es.md -│ └── 01-pathlib/ +│ ├── 01-pathlib/ +│ │ ├── README.md +│ │ ├── README.pt-BR.md +│ │ ├── README.es.md +│ │ └── examples/ +│ │ ├── discover_python_files.py +│ │ ├── inspect_paths.py +│ │ ├── path_parts.py +│ │ └── text_workspace.py +│ └── 02-datetime/ │ ├── README.md │ ├── README.pt-BR.md │ ├── README.es.md │ └── examples/ -│ ├── discover_python_files.py -│ ├── inspect_paths.py -│ ├── path_parts.py -│ └── text_workspace.py +│ ├── date_arithmetic.py +│ ├── duration_seconds.py +│ ├── parse_and_format.py +│ └── utc_conversion.py ├── strings-and-numbers/ │ ├── README.md │ ├── README.pt-BR.md @@ -458,7 +467,7 @@ python-study-guide/ - `practical-projects/`: future small projects combining several concepts. - `program-flow/`: complete Phase 4 learning path. Chapters 01–08 teach conditions, comparisons, truth-value testing, membership, identity, Boolean logic, conditional branching with `if`, `elif`, and `else`, structural pattern matching, iterable-driven repetition with `for`, numeric progressions with `range()`, position-aware iteration with `enumerate()`, parallel iteration with `zip()` including explicit equal-length validation with `strict=True`, state-driven repetition with `while`, deliberate loop control with `break`, `continue`, and loop `else`, and how to choose and combine program-flow tools according to intent, in English, Brazilian Portuguese, and Spanish with deterministic executable examples. - `scripts/`: dependency-free maintenance tools used locally and by GitHub Actions. -- `standard-library/`: in-progress Phase 8 learning path. Chapter 01 teaches `pathlib` path objects, portable composition, structural inspection, filesystem queries, text helpers, directory traversal, globbing, resolution, and exception-aware operation boundaries in English, Brazilian Portuguese, and Spanish with deterministic executable examples. +- `standard-library/`: in-progress Phase 8 learning path. Chapter 01 teaches `pathlib` path objects and filesystem boundaries. Chapter 02 teaches `datetime` date/time types, durations, parsing, formatting, ISO-oriented helpers, naive versus aware values, UTC and fixed offsets, timezone conversion, timestamps, and deterministic time calculations in English, Brazilian Portuguese, and Spanish with deterministic executable examples. - `strings-and-numbers/`: complete Phase 2 learning path. Its four reviewed chapters cover string creation and indexing, common string methods, integer, floating-point, and Boolean behavior, floating-point precision, and `round()`, `abs()`, `min()`, `max()`, and `sum()` in English, Brazilian Portuguese, and Spanish with safe executable examples. - `tests/`: regression tests for repository quality tools and later educational code. diff --git a/docs/project-structure.es.md b/docs/project-structure.es.md index c37a75d..ad305bd 100644 --- a/docs/project-structure.es.md +++ b/docs/project-structure.es.md @@ -388,15 +388,24 @@ python-study-guide/ │ ├── README.md │ ├── README.pt-BR.md │ ├── README.es.md -│ └── 01-pathlib/ +│ ├── 01-pathlib/ +│ │ ├── README.md +│ │ ├── README.pt-BR.md +│ │ ├── README.es.md +│ │ └── examples/ +│ │ ├── discover_python_files.py +│ │ ├── inspect_paths.py +│ │ ├── path_parts.py +│ │ └── text_workspace.py +│ └── 02-datetime/ │ ├── README.md │ ├── README.pt-BR.md │ ├── README.es.md │ └── examples/ -│ ├── discover_python_files.py -│ ├── inspect_paths.py -│ ├── path_parts.py -│ └── text_workspace.py +│ ├── date_arithmetic.py +│ ├── duration_seconds.py +│ ├── parse_and_format.py +│ └── utc_conversion.py ├── strings-and-numbers/ │ ├── README.md │ ├── README.pt-BR.md @@ -458,7 +467,7 @@ python-study-guide/ - `practical-projects/`: futuros proyectos pequeños que combinarán varios conceptos. - `program-flow/`: ruta completa de la Fase 4. Los Capítulos 01–08 enseñan condiciones, comparaciones, pruebas de valor de verdad, pertenencia, identidad, lógica booleana, ramificación condicional con `if`, `elif` y `else`, coincidencia de patrones estructurales, repetición guiada por iterables con `for`, progresiones numéricas con `range()`, iteración con posición usando `enumerate()`, iteración paralela con `zip()` incluida la validación explícita de longitudes iguales con `strict=True`, repetición guiada por estado con `while`, control deliberado de bucles con `break`, `continue` y `else` de bucle y cómo elegir y combinar herramientas de flujo del programa según la intención, en inglés, portugués de Brasil y español, con ejemplos ejecutables determinísticos. - `scripts/`: herramientas de mantenimiento sin dependencias externas utilizadas localmente y por GitHub Actions. -- `standard-library/`: ruta de la Fase 8 en progreso. El Capítulo 01 enseña objetos de ruta con `pathlib`, composición portable, inspección estructural, consultas al filesystem, helpers de texto, recorrido de directorios, globbing, resolución y límites de operación conscientes de excepciones en inglés, portugués de Brasil y español, con ejemplos ejecutables determinísticos. +- `standard-library/`: ruta de la Fase 8 en progreso. El Capítulo 01 enseña objetos de ruta con `pathlib` y límites del filesystem. El Capítulo 02 enseña tipos de fecha/hora con `datetime`, duraciones, parsing, formato, helpers orientados a ISO, valores naive frente a aware, UTC y offsets fijos, conversión de timezone, timestamps y cálculos de tiempo deterministas en inglés, portugués de Brasil y español, con ejemplos ejecutables determinísticos. - `strings-and-numbers/`: ruta completa de la Fase 2. Sus cuatro capítulos revisados cubren creación e indexación de strings, métodos comunes, comportamiento de enteros, punto flotante y booleanos, precisión de punto flotante y `round()`, `abs()`, `min()`, `max()` y `sum()` en inglés, portugués de Brasil y español, con ejemplos ejecutables seguros. - `tests/`: pruebas de regresión de las herramientas de calidad y, más adelante, del contenido educativo. diff --git a/docs/project-structure.pt-BR.md b/docs/project-structure.pt-BR.md index b6fdc72..00005a9 100644 --- a/docs/project-structure.pt-BR.md +++ b/docs/project-structure.pt-BR.md @@ -388,15 +388,24 @@ python-study-guide/ │ ├── README.md │ ├── README.pt-BR.md │ ├── README.es.md -│ └── 01-pathlib/ +│ ├── 01-pathlib/ +│ │ ├── README.md +│ │ ├── README.pt-BR.md +│ │ ├── README.es.md +│ │ └── examples/ +│ │ ├── discover_python_files.py +│ │ ├── inspect_paths.py +│ │ ├── path_parts.py +│ │ └── text_workspace.py +│ └── 02-datetime/ │ ├── README.md │ ├── README.pt-BR.md │ ├── README.es.md │ └── examples/ -│ ├── discover_python_files.py -│ ├── inspect_paths.py -│ ├── path_parts.py -│ └── text_workspace.py +│ ├── date_arithmetic.py +│ ├── duration_seconds.py +│ ├── parse_and_format.py +│ └── utc_conversion.py ├── strings-and-numbers/ │ ├── README.md │ ├── README.pt-BR.md @@ -458,7 +467,7 @@ python-study-guide/ - `practical-projects/`: futuros projetos pequenos combinando diversos conceitos. - `program-flow/`: trilha completa da Fase 4. Os Capítulos 01–08 ensinam condições, comparações, teste de valor de verdade, pertencimento, identidade, lógica booleana, ramificação condicional com `if`, `elif` e `else`, correspondência de padrões estruturais, repetição guiada por iteráveis com `for`, progressões numéricas com `range()`, iteração com posição usando `enumerate()`, iteração paralela com `zip()` incluindo validação explícita de comprimentos iguais com `strict=True`, repetição guiada por estado com `while`, controle deliberado de loops com `break`, `continue` e `else` de loop e como escolher e combinar ferramentas de fluxo do programa de acordo com a intenção, em inglês, português brasileiro e espanhol, com exemplos executáveis determinísticos. - `scripts/`: ferramentas de manutenção sem dependências externas, utilizadas localmente e pelo GitHub Actions. -- `standard-library/`: trilha da Fase 8 em andamento. O Capítulo 01 ensina objetos de caminho com `pathlib`, composição portável, inspeção estrutural, consultas ao filesystem, helpers de texto, percurso de diretórios, globbing, resolução e fronteiras de operação conscientes de exceções em inglês, português brasileiro e espanhol, com exemplos executáveis determinísticos. +- `standard-library/`: trilha da Fase 8 em andamento. O Capítulo 01 ensina objetos de caminho com `pathlib` e fronteiras do filesystem. O Capítulo 02 ensina tipos de data/hora com `datetime`, durações, parsing, formatação, helpers orientados a ISO, valores naive versus aware, UTC e offsets fixos, conversão de timezone, timestamps e cálculos de tempo determinísticos em inglês, português brasileiro e espanhol, com exemplos executáveis determinísticos. - `strings-and-numbers/`: trilha completa da Fase 2. Seus quatro capítulos revisados cobrem criação e indexação de strings, métodos comuns, comportamento de inteiros, ponto flutuante e booleanos, precisão de ponto flutuante e `round()`, `abs()`, `min()`, `max()` e `sum()` em inglês, português brasileiro e espanhol, com exemplos executáveis seguros. - `tests/`: testes de regressão das ferramentas de qualidade e, futuramente, do conteúdo educacional. diff --git a/docs/roadmap.en.md b/docs/roadmap.en.md index 1828985..685389b 100644 --- a/docs/roadmap.en.md +++ b/docs/roadmap.en.md @@ -141,7 +141,7 @@ Phase 7 is complete. Chapters 01–02 establish exception handling and deliberat See the [section learning path](../standard-library/README.md). - [x] [`pathlib`](../standard-library/01-pathlib/README.md) -- [ ] `datetime` +- [x] [`datetime`](../standard-library/02-datetime/README.md) - [ ] `json` - [ ] `csv` - [ ] `logging` @@ -150,7 +150,7 @@ See the [section learning path](../standard-library/README.md). - [ ] `decimal` - [ ] `os` and `shutil` -Phase 8 is in progress. Chapter 01 establishes `Path`, pure paths, relative and absolute paths, structural inspection, portable composition, text helpers, directory creation and traversal, globbing, resolution, and filesystem exception boundaries. Chapter 02 will continue with `datetime` and time calculations. +Phase 8 is in progress. Chapter 01 establishes `pathlib` path modeling and filesystem boundaries. Chapter 02 adds `date`, `time`, `datetime`, `timedelta`, parsing, formatting, ISO-oriented helpers, naive versus aware datetimes, UTC and fixed offsets, timezone conversion, timestamps, and deterministic time calculations. Chapter 03 will continue with deeper `json` handling. ## Phase 9: External libraries diff --git a/docs/roadmap.es.md b/docs/roadmap.es.md index 4edbdd6..16cfc24 100644 --- a/docs/roadmap.es.md +++ b/docs/roadmap.es.md @@ -141,7 +141,7 @@ La Fase 7 está completada. Los Capítulos 01–02 establecen manejo y señaliza Consulta la [ruta de aprendizaje de la sección](../standard-library/README.es.md). - [x] [`pathlib`](../standard-library/01-pathlib/README.es.md) -- [ ] `datetime` +- [x] [`datetime`](../standard-library/02-datetime/README.es.md) - [ ] `json` - [ ] `csv` - [ ] `logging` @@ -150,7 +150,7 @@ Consulta la [ruta de aprendizaje de la sección](../standard-library/README.es.m - [ ] `decimal` - [ ] `os` y `shutil` -La Fase 8 está en progreso. El Capítulo 01 establece `Path`, rutas puras, rutas relativas y absolutas, inspección estructural, composición portable, helpers de texto, creación y recorrido de directorios, globbing, resolución y límites de excepciones del filesystem. El Capítulo 02 continuará con `datetime` y cálculos de tiempo. +La Fase 8 está en progreso. El Capítulo 01 establece modelado de rutas con `pathlib` y límites del filesystem. El Capítulo 02 añade `date`, `time`, `datetime`, `timedelta`, parsing, formato, helpers orientados a ISO, datetimes naive frente a aware, UTC y offsets fijos, conversión de timezone, timestamps y cálculos de tiempo deterministas. El Capítulo 03 continuará con uso más profundo de `json`. ## Fase 9: Bibliotecas externas diff --git a/docs/roadmap.pt-BR.md b/docs/roadmap.pt-BR.md index 3e01faa..071d250 100644 --- a/docs/roadmap.pt-BR.md +++ b/docs/roadmap.pt-BR.md @@ -141,7 +141,7 @@ A Fase 7 está concluída. Os Capítulos 01–02 estabelecem tratamento e sinali Consulte a [trilha de aprendizagem da seção](../standard-library/README.pt-BR.md). - [x] [`pathlib`](../standard-library/01-pathlib/README.pt-BR.md) -- [ ] `datetime` +- [x] [`datetime`](../standard-library/02-datetime/README.pt-BR.md) - [ ] `json` - [ ] `csv` - [ ] `logging` @@ -150,7 +150,7 @@ Consulte a [trilha de aprendizagem da seção](../standard-library/README.pt-BR. - [ ] `decimal` - [ ] `os` e `shutil` -A Fase 8 está em andamento. O Capítulo 01 estabelece `Path`, caminhos puros, caminhos relativos e absolutos, inspeção estrutural, composição portável, helpers de texto, criação e percurso de diretórios, globbing, resolução e fronteiras de exceções do filesystem. O Capítulo 02 continuará com `datetime` e cálculos de tempo. +A Fase 8 está em andamento. O Capítulo 01 estabelece modelagem de caminhos com `pathlib` e fronteiras do filesystem. O Capítulo 02 acrescenta `date`, `time`, `datetime`, `timedelta`, parsing, formatação, helpers orientados a ISO, datetimes naive versus aware, UTC e offsets fixos, conversão de timezone, timestamps e cálculos de tempo determinísticos. O Capítulo 03 continuará com uso mais profundo de `json`. ## Fase 9: Bibliotecas externas diff --git a/scripts/example_manifest.txt b/scripts/example_manifest.txt index b2c02da..da4eb96 100644 --- a/scripts/example_manifest.txt +++ b/scripts/example_manifest.txt @@ -126,3 +126,7 @@ standard-library/01-pathlib/examples/discover_python_files.py standard-library/01-pathlib/examples/inspect_paths.py standard-library/01-pathlib/examples/path_parts.py standard-library/01-pathlib/examples/text_workspace.py +standard-library/02-datetime/examples/date_arithmetic.py +standard-library/02-datetime/examples/duration_seconds.py +standard-library/02-datetime/examples/parse_and_format.py +standard-library/02-datetime/examples/utc_conversion.py diff --git a/standard-library/01-pathlib/README.es.md b/standard-library/01-pathlib/README.es.md index 846b744..b589f1f 100644 --- a/standard-library/01-pathlib/README.es.md +++ b/standard-library/01-pathlib/README.es.md @@ -758,7 +758,7 @@ Los ejemplos son deterministas y usan solo operaciones estructurales de rutas o ## Próximo capítulo -Continúa con **Capítulo 02: `datetime` y Cálculos de Tiempo**, donde la biblioteca estándar añade objetos explícitos para fechas, horas, duraciones, parsing, formato y aritmética de fechas. +Continúa con **[Capítulo 02: `datetime` y Cálculos de Tiempo](../02-datetime/README.es.md)**, donde la biblioteca estándar añade objetos explícitos para fechas, horas, duraciones, parsing, formato y aritmética de fechas. ## Referencias oficiales diff --git a/standard-library/01-pathlib/README.md b/standard-library/01-pathlib/README.md index 8f60ceb..b65f63a 100644 --- a/standard-library/01-pathlib/README.md +++ b/standard-library/01-pathlib/README.md @@ -762,7 +762,7 @@ These examples are deterministic and use either path-only operations or temporar ## Next chapter -Continue with **Chapter 02: `datetime` and Time Calculations**, where the standard library adds explicit objects for dates, times, durations, parsing, formatting, and date arithmetic. +Continue with **[Chapter 02: `datetime` and Time Calculations](../02-datetime/README.md)**, where the standard library adds explicit objects for dates, times, durations, parsing, formatting, and date arithmetic. ## Official references diff --git a/standard-library/01-pathlib/README.pt-BR.md b/standard-library/01-pathlib/README.pt-BR.md index ef18b7e..c5bf2e8 100644 --- a/standard-library/01-pathlib/README.pt-BR.md +++ b/standard-library/01-pathlib/README.pt-BR.md @@ -758,7 +758,7 @@ Os exemplos são determinísticos e usam apenas operações estruturais de camin ## Próximo capítulo -Continue com **Capítulo 02: `datetime` e Cálculos de Tempo**, onde a biblioteca padrão adiciona objetos explícitos para datas, horários, durações, parsing, formatação e aritmética de datas. +Continue com **[Capítulo 02: `datetime` e Cálculos de Tempo](../02-datetime/README.pt-BR.md)**, onde a biblioteca padrão adiciona objetos explícitos para datas, horários, durações, parsing, formatação e aritmética de datas. ## Referências oficiais diff --git a/standard-library/02-datetime/README.es.md b/standard-library/02-datetime/README.es.md new file mode 100644 index 0000000..fb22fe2 --- /dev/null +++ b/standard-library/02-datetime/README.es.md @@ -0,0 +1,703 @@ +# Trabajar con Fechas y Cálculos de Tiempo Usando `datetime` + +[🇺🇸 English](README.md) · [🇧🇷 Português](README.pt-BR.md) · [🇪🇸 Español](README.es.md) + +El módulo `datetime` de Python proporciona objetos explícitos para fechas, horas, valores combinados de fecha y hora, duraciones, desplazamientos fijos respecto de UTC, parsing, formato, comparación y aritmética. + +Strings como `"2026-08-27"` son útiles para almacenamiento y comunicación, pero no saben automáticamente cuántos días separan dos fechas, si un año es bisiesto o cómo sumar una duración correctamente. El módulo `datetime` da tipos y reglas propios a esos conceptos. + +Para la mayor parte del trabajo principiante e intermedio, los imports centrales son: + +```python +from datetime import date, datetime, time, timedelta, timezone +``` + +## Objetivos de aprendizaje + +Al final de este capítulo deberías poder: + +- distinguir `date`, `time`, `datetime` y `timedelta`; +- construir objetos de fecha y hora explícitamente; +- inspeccionar componentes de año, mes, día, hora, minuto y segundo; +- usar `date.today()` y `datetime.now()` deliberadamente; +- hacer aritmética con `timedelta`; +- entender la diferencia entre `timedelta.seconds` y `timedelta.total_seconds()`; +- hacer parsing con `strptime()` y formato con `strftime()`; +- usar helpers ISO como `fromisoformat()` e `isoformat()`; +- distinguir objetos `datetime` naive y timezone-aware; +- representar UTC y offsets fijos con `timezone`; +- convertir datetimes aware con `astimezone()`; +- entender por qué asignar `tzinfo` no equivale a convertir una hora; +- evitar tratar duraciones fijas como reglas de meses del calendario; +- reconocer cuándo las zonas horarias reales requieren el módulo complementario `zoneinfo`. + +## 1. ¿Por qué usar tipos dedicados para fecha y hora? + +Considera dos strings: + +```python +start = "2026-08-27" +end = "2026-09-03" +``` + +Una persona ve que parecen fechas, pero Python todavía ve strings comunes. + +Con `date`, el significado queda explícito: + +```python +from datetime import date + +start = date(2026, 8, 27) +end = date(2026, 9, 3) + +print(end - start) +``` + +La resta produce un `timedelta`, porque Python ahora sabe que los valores representan fechas de calendario. + +La idea de diseño es: + +```text +texto para representación + != +objetos para comportamiento de fecha/hora +``` + +## 2. Las clases centrales + +Las clases más usadas son: + +| Clase | Representa | +|---|---| +| `date` | fecha de calendario: año, mes y día | +| `time` | hora de reloj sin una fecha | +| `datetime` | fecha y hora juntas | +| `timedelta` | duración entre puntos en el tiempo | +| `timezone` | offset fijo respecto de UTC | + +Resuelven problemas relacionados, pero no son intercambiables. + +## 3. Crear un `date` + +Construye una fecha con año, mes y día: + +```python +from datetime import date + +release_date = date(2026, 8, 27) + +print(release_date.year) +print(release_date.month) +print(release_date.day) +``` + +Valores imposibles fallan inmediatamente: + +```python +from datetime import date + +try: + impossible = date(2026, 2, 30) +except ValueError: + print("Invalid calendar date") +``` + +Esta validación es una ventaja de usar un tipo de fecha en lugar de transportar texto sin validar por el programa. + +## 4. Crear un `time` + +Un `time` representa una hora de reloj: + +```python +from datetime import time + +meeting_time = time(14, 30, 15) + +print(meeting_time.hour) +print(meeting_time.minute) +print(meeting_time.second) +``` + +Un objeto `time` no contiene año, mes ni día. Es útil cuando la hora importa independientemente de la fecha. + +No esperes sumar un `timedelta` directamente a un `time` simple. La aritmética de horas normalmente necesita un `datetime` o reglas de la aplicación sobre qué fecha usar. + +## 5. Crear un `datetime` + +Un `datetime` combina ambos conceptos: + +```python +from datetime import datetime + +moment = datetime(2026, 8, 27, 14, 30, 15) + +print(moment.date()) +print(moment.time()) +print(moment.year) +print(moment.hour) +``` + +Esto es útil para eventos, timestamps, plazos, logs, citas y otros valores donde importan fecha y hora. + +## 6. Fecha y hora actuales + +`date.today()` devuelve la fecha local actual: + +```python +from datetime import date + +today = date.today() +print(today) +``` + +`datetime.now()` devuelve la fecha y hora locales actuales como `datetime` naive por defecto: + +```python +from datetime import datetime + +now = datetime.now() +print(now) +``` + +Para un `datetime` UTC aware, prefiere: + +```python +from datetime import datetime, timezone + +now_utc = datetime.now(timezone.utc) +print(now_utc) +``` + +Evita llamadas al reloj real cuando una prueba o ejemplo determinista pueda usar un valor fijo. + +### Evita `datetime.utcnow()` en código nuevo + +`datetime.utcnow()` devuelve un objeto naive aunque represente UTC y está deprecated en Python moderno. Prefiere `datetime.now(timezone.utc)` para que la relación con UTC quede explícita en el propio objeto. + +## 7. ¿Qué es un `timedelta`? + +Un `timedelta` representa una duración. + +```python +from datetime import timedelta + +review_window = timedelta(days=7, hours=3) +print(review_window) +``` + +Puede sumarse o restarse de fechas y datetimes: + +```python +from datetime import date, timedelta + +start = date(2026, 8, 27) +end = start + timedelta(days=10) + +print(end) +``` + +Restar fechas o datetimes compatibles produce un `timedelta`: + +```python +from datetime import date + +start = date(2026, 8, 27) +end = date(2026, 9, 3) + +difference = end - start +print(difference.days) +``` + +## 8. `timedelta.seconds` no son los segundos totales + +Este es un error clásico. + +```python +from datetime import timedelta + +duration = timedelta(days=1, seconds=90) + +print(duration.days) +print(duration.seconds) +print(duration.total_seconds()) +``` + +`duration.seconds` es solo la parte normalizada de segundos dentro del día. No incluye días completos. + +Usa `total_seconds()` cuando necesites la duración completa expresada en segundos. + +En el ejemplo anterior: + +```text +componente de segundos = 90 +duración total = 86490 segundos +``` + +## 9. Las duraciones no son meses de calendario + +Un `timedelta` modela duraciones fijas en días, segundos y microsegundos. No tiene un concepto incorporado de "un mes de calendario". + +Esto: + +```python +from datetime import date, timedelta + +start = date(2026, 1, 31) +approximate = start + timedelta(days=30) + +print(approximate) +``` + +significa exactamente "sumar 30 días". No significa "moverse al mismo día del mes siguiente". + +Reglas de cierre de mes, feriados, calendarios comerciales y vencimientos son políticas de la aplicación y deben modelarse explícitamente. + +## 10. Comparar fechas y datetimes + +Objetos compatibles del mismo tipo pueden compararse: + +```python +from datetime import date + +deadline = date(2026, 9, 10) +today = date(2026, 9, 3) + +if today <= deadline: + print("Still on time") +``` + +No compares strings formateados solo porque parecen fechas. Algunos formatos ordenan cronológicamente y otros no, y comparar strings no aporta semántica de calendario. + +## 11. Hacer parsing con `strptime()` + +Los datos externos suelen llegar como texto. + +Usa `datetime.strptime()` cuando la entrada siga un formato conocido: + +```python +from datetime import datetime + +text = "27/08/2026 18:45" +moment = datetime.strptime(text, "%d/%m/%Y %H:%M") + +print(moment) +``` + +La string de formato es un contrato entre tu código y la entrada. + +Directivas comunes: + +| Directiva | Significado | +|---|---| +| `%Y` | año de cuatro dígitos | +| `%m` | número de mes | +| `%d` | día del mes | +| `%H` | hora de 00 a 23 | +| `%M` | minuto | +| `%S` | segundo | +| `%f` | microsegundos | +| `%z` | offset UTC | + +Si el texto no coincide con el formato esperado, el parsing genera `ValueError`. + +```python +from datetime import datetime + +try: + moment = datetime.strptime("2026/08/27", "%Y-%m-%d") +except ValueError: + print("Unexpected date format") +``` + +## 12. Formatear con `strftime()` + +`strftime()` hace el camino contrario: objeto a texto. + +```python +from datetime import datetime + +moment = datetime(2026, 8, 27, 18, 45) + +print(moment.strftime("%Y-%m-%d")) +print(moment.strftime("%d/%m/%Y %H:%M")) +``` + +Mantén clara la diferencia: + +```text +strptime: texto -> datetime +strftime: datetime/date/time -> texto +``` + +## 13. Helpers orientados a ISO + +Para representaciones de estilo ISO, los métodos dedicados suelen ser más claros que formatos personalizados. + +```python +from datetime import date, datetime + +calendar_date = date.fromisoformat("2026-08-27") +moment = datetime.fromisoformat("2026-08-27T18:45:00+00:00") + +print(calendar_date.isoformat()) +print(moment.isoformat()) +``` + +`fromisoformat()` e `isoformat()` son convenientes cuando el contrato coincide con las formas compatibles con el parser y formateador orientados a ISO de Python. + +No asumas que toda string descrita informalmente como "ISO 8601" será aceptada por cualquier parser. La forma exacta admitida forma parte del contrato de interfaz. + +## 14. Controlar la precisión de salida ISO + +`datetime.isoformat()` puede controlar la precisión mostrada: + +```python +from datetime import datetime + +moment = datetime(2026, 8, 27, 18, 45, 12, 345678) + +print(moment.isoformat(timespec="minutes")) +print(moment.isoformat(timespec="seconds")) +print(moment.isoformat(timespec="microseconds")) +``` + +Esto es útil cuando un formato externo exige una precisión específica. + +## 15. Datetimes naive y aware + +Un `datetime` puede ser **naive** o **aware**. + +Un datetime naive no contiene suficiente información de zona horaria para ubicarse de forma inequívoca frente a otros instantes del mundo. + +```python +from datetime import datetime + +naive = datetime(2026, 8, 27, 18, 30) +print(naive.tzinfo) +``` + +Un datetime aware posee información de timezone capaz de proporcionar un offset respecto de UTC: + +```python +from datetime import datetime, timezone + +aware = datetime(2026, 8, 27, 18, 30, tzinfo=timezone.utc) +print(aware.tzinfo) +print(aware.utcoffset()) +``` + +La diferencia importa en APIs, logs, sistemas distribuidos y tareas programadas que cruzan zonas horarias. + +## 16. Representar UTC + +Usa `timezone.utc` para UTC: + +```python +from datetime import datetime, timezone + +moment = datetime(2026, 8, 27, 21, 30, tzinfo=timezone.utc) + +print(moment.isoformat()) +``` + +El resultado incluye el offset UTC: + +```text +2026-08-27T21:30:00+00:00 +``` + +## 17. Offsets UTC fijos + +`timezone` puede representar offsets fijos: + +```python +from datetime import datetime, timedelta, timezone + +brt = timezone(timedelta(hours=-3)) +moment = datetime(2026, 8, 27, 18, 30, tzinfo=brt) + +print(moment.isoformat()) +``` + +Un offset fijo como `-03:00` no equivale a una zona geográfica real. Las zonas geográficas pueden cambiar de offset por reglas históricas, horario de verano y cambios legales. + +## 18. Convertir con `astimezone()` + +Para un datetime aware, usa `astimezone()` para representar el mismo instante en otra zona: + +```python +from datetime import datetime, timedelta, timezone + +brt = timezone(timedelta(hours=-3)) +local = datetime(2026, 8, 27, 18, 30, tzinfo=brt) +utc = local.astimezone(timezone.utc) + +print(local.isoformat()) +print(utc.isoformat()) +``` + +La hora de reloj cambia, pero ambos objetos representan el mismo instante. + +## 19. Asignar `tzinfo` no es convertir timezone + +Este código cambia metadatos sin convertir la lectura del reloj: + +```python +from datetime import datetime, timezone + +naive = datetime(2026, 8, 27, 18, 30) +labeled = naive.replace(tzinfo=timezone.utc) + +print(labeled.isoformat()) +``` + +`replace(tzinfo=...)` no pregunta "¿qué hora es 18:30 en otra zona?". Crea un nuevo objeto con campos reemplazados. + +Úsalo solo cuando ya sepas qué timezone representa el valor naive y adjuntar esa información sea la operación deseada. + +Para convertir un datetime ya aware entre zonas, usa `astimezone()`. + +## 20. No mezcles aritmética naive y aware sin una política + +Restar un datetime aware de uno naive no tiene significado sin una relación explícita de timezone. + +```python +from datetime import datetime, timezone + +naive = datetime(2026, 8, 27, 18, 30) +aware = datetime(2026, 8, 27, 18, 30, tzinfo=timezone.utc) + +try: + difference = aware - naive +except TypeError: + print("Cannot mix naive and aware datetimes") +``` + +Elige y documenta una política de timezone en las fronteras del sistema. + +## 21. Zonas geográficas reales y `zoneinfo` + +La biblioteca estándar incluye el módulo complementario `zoneinfo` para reglas IANA como `America/Sao_Paulo` o `Europe/London`. + +Conceptualmente: + +```python +from datetime import datetime +from zoneinfo import ZoneInfo + +moment = datetime(2026, 8, 27, 18, 30, tzinfo=ZoneInfo("America/Sao_Paulo")) +print(moment.isoformat()) +``` + +A diferencia de `timezone(timedelta(...))`, `ZoneInfo` puede modelar reglas históricas y futuras proporcionadas por la base de datos de zonas disponible. + +La disponibilidad de esa base depende del entorno. Algunos sistemas la incluyen directamente; otros pueden necesitar el paquete `tzdata`. Por eso los ejemplos ejecutables de este capítulo usan offsets fijos. + +## 22. Unix timestamps + +Un Unix timestamp representa segundos transcurridos desde la convención de epoch Unix de la plataforma. + +Crea un datetime UTC aware proporcionando timezone: + +```python +from datetime import datetime, timezone + +moment = datetime.fromtimestamp(0, tz=timezone.utc) +print(moment.isoformat()) +``` + +Convierte un datetime aware de vuelta con `.timestamp()`: + +```python +from datetime import datetime, timezone + +moment = datetime(1970, 1, 1, tzinfo=timezone.utc) +print(moment.timestamp()) +``` + +Los timestamps son útiles como valores de intercambio, pero legibilidad, rango soportado, precisión y comportamiento de plataforma siguen importando. No los uses como sustitutos de comprender y definir una política de timezone. + +## 23. Reemplazar campos + +`replace()` devuelve un nuevo objeto con campos seleccionados modificados: + +```python +from datetime import datetime + +original = datetime(2026, 8, 27, 18, 30) +updated = original.replace(hour=9, minute=0) + +print(original) +print(updated) +``` + +No modifica el objeto original. + +Esto es reemplazo de campos, no aritmética de calendario comercial. Cambiar `month=2` en una fecha cuyo día no existe en febrero puede generar `ValueError`. + +## 24. Combinar una fecha y una hora + +`datetime.combine()` es útil cuando valores separados deben convertirse en un solo datetime: + +```python +from datetime import date, datetime, time + +calendar_date = date(2026, 8, 27) +clock_time = time(18, 30) +moment = datetime.combine(calendar_date, clock_time) + +print(moment) +``` + +El resultado es naive salvo que la información de timezone se aporte mediante un diseño explícito. + +## 25. Errores comunes + +### Error 1: guardar todo como strings + +Los strings son apropiados en las fronteras, pero los cálculos normalmente deben usar objetos de fecha/hora. + +### Error 2: tratar `timedelta.seconds` como la duración completa + +Usa `total_seconds()` cuando necesites incluir también los días. + +### Error 3: usar `timedelta(days=30)` como "un mes" + +Eso significa 30 días, no un mes de calendario. + +### Error 4: hacer parsing sin contrato explícito + +Si la entrada tiene un formato definido, codifícalo deliberadamente y maneja `ValueError` cuando pueda ser inválida. + +### Error 5: mezclar datetimes naive y aware + +Define si tu sistema usa hora local, UTC o zonas explícitas en cada frontera. + +### Error 6: usar `replace(tzinfo=...)` como conversión + +Reemplazo de campo y conversión de timezone son operaciones distintas. + +### Error 7: usar un offset fijo como si fuera una zona geográfica + +Las reglas reales pueden cambiar. Usa `zoneinfo` cuando importen las reglas geográficas. + +### Error 8: usar el reloj real en pruebas deterministas + +Inyecta o construye datetimes fijos cuando importe la reproducibilidad. + +## 26. Ejemplo práctico + +Imagina un informe que recibe un timestamp UTC como texto, lo parsea, aplica un offset local fijo para presentación y calcula un plazo de revisión. + +```python +from datetime import datetime, timedelta, timezone + +source = "2026-08-27T21:30:00+00:00" +created_utc = datetime.fromisoformat(source) + +local_zone = timezone(timedelta(hours=-3)) +created_local = created_utc.astimezone(local_zone) +deadline = created_local + timedelta(days=5) + +print(created_local.isoformat()) +print(deadline.isoformat()) +``` + +El flujo queda explícito: + +```text +contrato de texto + ↓ +datetime aware + ↓ +conversión de timezone + ↓ +aritmética de duración + ↓ +salida formateada +``` + +## 27. Ejercicio + +Crea un programa que: + +1. haga parsing de `"2026-10-15 09:30"` usando `strptime()`; +2. trate ese valor como hora de pared con offset fijo `-03:00`; +3. sume 2 días y 4 horas con `timedelta`; +4. convierta el resultado a UTC con `astimezone()`; +5. muestre los valores local y UTC con `isoformat()`; +6. muestre la duración completa en segundos; +7. formatee el resultado UTC como `YYYY-MM-DD HH:MM`. + +Después responde: + +- ¿Qué objetos son naive y cuáles son aware? +- ¿Por qué `replace(tzinfo=...)` es aceptable para adjuntar aquí el offset conocido del origen, pero no para convertir entre zonas? +- ¿Por qué debe usarse `total_seconds()` en vez de `.seconds` para la duración completa? +- ¿Por qué un offset fijo `-03:00` no equivale automáticamente a todas las reglas históricas o futuras de `America/Sao_Paulo`? + +## 28. Lista de revisión + +Antes de avanzar, asegúrate de poder explicar: + +- `date`, `time`, `datetime`, `timedelta` y `timezone`; +- construcción y validación de valores de calendario; +- `date.today()` y `datetime.now()`; +- por qué UTC aware debe usar `datetime.now(timezone.utc)`; +- aritmética de fechas y datetimes; +- `.days`, `.seconds` y `.total_seconds()`; +- por qué las duraciones fijas no son meses de calendario; +- `strptime()` frente a `strftime()`; +- `fromisoformat()` e `isoformat()`; +- datetimes naive frente a aware; +- UTC y offsets fijos; +- `astimezone()` frente a `replace(tzinfo=...)`; +- por qué las reglas de zonas geográficas pertenecen a `zoneinfo`; +- timestamps como valores de intercambio; +- cómo mantener pruebas deterministas. + +## Referencia rápida + +```python +from datetime import date, datetime, time, timedelta, timezone + +calendar_date = date(2026, 8, 27) +clock_time = time(18, 30) +moment = datetime(2026, 8, 27, 18, 30) +duration = timedelta(days=2, hours=4) + +calendar_date + timedelta(days=1) +moment + duration + +datetime.strptime("2026-08-27 18:30", "%Y-%m-%d %H:%M") +moment.strftime("%d/%m/%Y %H:%M") + +date.fromisoformat("2026-08-27") +datetime.fromisoformat("2026-08-27T18:30:00+00:00") +moment.isoformat() + +aware_utc = datetime(2026, 8, 27, 21, 30, tzinfo=timezone.utc) +fixed_offset = timezone(timedelta(hours=-3)) +aware_utc.astimezone(fixed_offset) + +duration.total_seconds() +``` + +## Ejemplos ejecutables + +- [`examples/date_arithmetic.py`](examples/date_arithmetic.py) +- [`examples/parse_and_format.py`](examples/parse_and_format.py) +- [`examples/utc_conversion.py`](examples/utc_conversion.py) +- [`examples/duration_seconds.py`](examples/duration_seconds.py) + +Los ejemplos son deterministas y no dependen del reloj actual ni de una base externa de zonas horarias. + +## Próximo capítulo + +Continúa con **Capítulo 03: `json` Más Allá de la Persistencia Básica**, donde la biblioteca estándar revisita la serialización JSON con control más profundo de encoders, decoders, formato, hooks numéricos y contratos estrictos de interoperabilidad. + +## Referencias oficiales + +- [Python 3.14 `datetime` - tipos básicos de fecha y hora](https://docs.python.org/3.14/library/datetime.html) +- [Python 3.14 códigos de formato de `strftime()` y `strptime()`](https://docs.python.org/3.14/library/datetime.html#strftime-and-strptime-format-codes) +- [Python 3.14 `zoneinfo` - soporte para zonas IANA](https://docs.python.org/3.14/library/zoneinfo.html) diff --git a/standard-library/02-datetime/README.md b/standard-library/02-datetime/README.md new file mode 100644 index 0000000..383df85 --- /dev/null +++ b/standard-library/02-datetime/README.md @@ -0,0 +1,705 @@ +# Working with Dates and Time Calculations Using `datetime` + +[🇺🇸 English](README.md) · [🇧🇷 Português](README.pt-BR.md) · [🇪🇸 Español](README.es.md) + +Python's `datetime` module provides explicit objects for dates, clock times, combined date-and-time values, durations, fixed UTC offsets, parsing, formatting, comparison, and arithmetic. + +Strings such as `"2026-08-27"` are useful for storage and communication, but they do not automatically know how many days separate two dates, whether a year is a leap year, or how to add a duration safely. The `datetime` module gives those concepts dedicated types and rules. + +For most beginner and intermediate work, the central imports are: + +```python +from datetime import date, datetime, time, timedelta, timezone +``` + +## Learning goals + +By the end of this chapter, you should be able to: + +- distinguish `date`, `time`, `datetime`, and `timedelta`; +- construct date and time objects explicitly; +- inspect year, month, day, hour, minute, and second components; +- use `date.today()` and `datetime.now()` deliberately; +- perform date and datetime arithmetic with `timedelta`; +- understand the difference between `timedelta.seconds` and `timedelta.total_seconds()`; +- parse text with `strptime()` and format objects with `strftime()`; +- use ISO-oriented helpers such as `fromisoformat()` and `isoformat()`; +- distinguish naive and timezone-aware `datetime` objects; +- represent UTC and fixed offsets with `timezone`; +- convert aware datetimes with `astimezone()`; +- understand why assigning `tzinfo` is not the same as converting a time; +- avoid treating fixed durations as calendar-month rules; +- recognize when real-world time zones require the companion `zoneinfo` module. + +## 1. Why use dedicated date and time types? + +Consider two strings: + +```python +start = "2026-08-27" +end = "2026-09-03" +``` + +A human can see that they look like dates, but Python still sees ordinary strings. + +With `date`, the meaning is explicit: + +```python +from datetime import date + +start = date(2026, 8, 27) +end = date(2026, 9, 3) + +print(end - start) +``` + +The subtraction produces a `timedelta`, because Python now knows that the values represent calendar dates. + +The main design idea is: + +```text +text for representation + != +objects for date/time behavior +``` + +## 2. The central classes + +The most commonly used classes are: + +| Class | Represents | +|---|---| +| `date` | a calendar date: year, month, day | +| `time` | a clock time without a calendar date | +| `datetime` | a date and clock time together | +| `timedelta` | a duration between points in time | +| `timezone` | a fixed offset from UTC | + +These classes solve related problems, but they are not interchangeable. + +## 3. Creating a `date` + +Construct a date with year, month, and day: + +```python +from datetime import date + +release_date = date(2026, 8, 27) + +print(release_date.year) +print(release_date.month) +print(release_date.day) +``` + +Invalid calendar values fail immediately: + +```python +from datetime import date + +try: + impossible = date(2026, 2, 30) +except ValueError: + print("Invalid calendar date") +``` + +That validation is one advantage of using a date type instead of carrying unchecked text through the program. + +## 4. Creating a `time` + +A `time` represents a clock time: + +```python +from datetime import time + +meeting_time = time(14, 30, 15) + +print(meeting_time.hour) +print(meeting_time.minute) +print(meeting_time.second) +``` + +A `time` object does not include a year, month, or day. It is useful when the clock-time concept matters independently from a date. + +Do not expect to add a `timedelta` directly to a plain `time` object. Time arithmetic normally needs a `datetime` or application-specific logic about what date should be used. + +## 5. Creating a `datetime` + +A `datetime` combines both concepts: + +```python +from datetime import datetime + +moment = datetime(2026, 8, 27, 14, 30, 15) + +print(moment.date()) +print(moment.time()) +print(moment.year) +print(moment.hour) +``` + +This is useful for events, timestamps, deadlines, logs, appointments, and other values where both date and clock time matter. + +## 6. Current date and current time + +`date.today()` returns the current local date: + +```python +from datetime import date + +today = date.today() +print(today) +``` + +`datetime.now()` returns the current local date and time as a naive `datetime` by default: + +```python +from datetime import datetime + +now = datetime.now() +print(now) +``` + +For an aware UTC datetime, prefer: + +```python +from datetime import datetime, timezone + +now_utc = datetime.now(timezone.utc) +print(now_utc) +``` + +Do not use current-time calls when a deterministic test or example can use a fixed value instead. Real clocks make outputs change from run to run. + +### Avoid `datetime.utcnow()` in new code + +`datetime.utcnow()` returns a naive object even though the value is intended to represent UTC, and it is deprecated in modern Python. Prefer `datetime.now(timezone.utc)` so the UTC relationship is explicit in the object. + +## 7. What is a `timedelta`? + +A `timedelta` represents a duration. + +```python +from datetime import timedelta + +review_window = timedelta(days=7, hours=3) +print(review_window) +``` + +It can be added to or subtracted from dates and datetimes: + +```python +from datetime import date, timedelta + +start = date(2026, 8, 27) +end = start + timedelta(days=10) + +print(end) +``` + +Subtracting compatible dates or datetimes produces a `timedelta`: + +```python +from datetime import date + +start = date(2026, 8, 27) +end = date(2026, 9, 3) + +difference = end - start +print(difference.days) +``` + +## 8. `timedelta.seconds` is not total seconds + +This is a classic trap. + +```python +from datetime import timedelta + +duration = timedelta(days=1, seconds=90) + +print(duration.days) +print(duration.seconds) +print(duration.total_seconds()) +``` + +`duration.seconds` is only the normalized seconds portion inside the day. It does not include whole days. + +Use `total_seconds()` when you need the complete duration expressed in seconds. + +For the example above: + +```text +seconds component = 90 +total duration = 86490 seconds +``` + +## 9. Durations are not calendar months + +A `timedelta` models fixed durations in days, seconds, and microseconds. It does not have a built-in concept of "one calendar month". + +This: + +```python +from datetime import date, timedelta + +start = date(2026, 1, 31) +approximate = start + timedelta(days=30) + +print(approximate) +``` + +means exactly "add 30 days". It does not mean "move to the same day in the next month". + +Calendar-month rules vary because months have different lengths. Business calendars, month-end logic, holidays, and settlement rules are application concepts that need explicit policies. + +## 10. Comparing dates and datetimes + +Objects of the same compatible kind can be compared: + +```python +from datetime import date + +deadline = date(2026, 9, 10) +today = date(2026, 9, 3) + +if today <= deadline: + print("Still on time") +``` + +Do not compare formatted strings merely because they look date-like. Some string formats sort chronologically, some do not, and string comparison does not provide date semantics. + +## 11. Parsing text with `strptime()` + +External data often arrives as text. + +Use `datetime.strptime()` when the input follows a known format: + +```python +from datetime import datetime + +text = "27/08/2026 18:45" +moment = datetime.strptime(text, "%d/%m/%Y %H:%M") + +print(moment) +``` + +The format string is a contract between your code and the input. + +Common directives include: + +| Directive | Meaning | +|---|---| +| `%Y` | four-digit year | +| `%m` | month number | +| `%d` | day of month | +| `%H` | hour from 00 to 23 | +| `%M` | minute | +| `%S` | second | +| `%f` | microseconds | +| `%z` | UTC offset | + +If the text does not match the expected format, parsing raises `ValueError`. + +```python +from datetime import datetime + +try: + moment = datetime.strptime("2026/08/27", "%Y-%m-%d") +except ValueError: + print("Unexpected date format") +``` + +## 12. Formatting with `strftime()` + +`strftime()` goes in the other direction: object to text. + +```python +from datetime import datetime + +moment = datetime(2026, 8, 27, 18, 45) + +print(moment.strftime("%Y-%m-%d")) +print(moment.strftime("%d/%m/%Y %H:%M")) +``` + +Formatting is useful for presentation and external contracts. + +Keep the distinction clear: + +```text +strptime: text -> datetime +strftime: datetime/date/time -> text +``` + +## 13. ISO-oriented helpers + +For ISO-style representations, dedicated methods are often clearer than custom format strings. + +```python +from datetime import date, datetime + +calendar_date = date.fromisoformat("2026-08-27") +moment = datetime.fromisoformat("2026-08-27T18:45:00+00:00") + +print(calendar_date.isoformat()) +print(moment.isoformat()) +``` + +`fromisoformat()` and `isoformat()` are convenient when your contract matches forms supported by Python's ISO-oriented parser and formatter. + +Do not assume that every string loosely described as "ISO 8601" is accepted by every parser. Treat the exact accepted form as part of the interface contract. + +## 14. Controlling ISO output precision + +`datetime.isoformat()` can control the displayed time precision: + +```python +from datetime import datetime + +moment = datetime(2026, 8, 27, 18, 45, 12, 345678) + +print(moment.isoformat(timespec="minutes")) +print(moment.isoformat(timespec="seconds")) +print(moment.isoformat(timespec="microseconds")) +``` + +This is useful when an external format requires a particular precision. + +## 15. Naive and aware datetimes + +A `datetime` can be **naive** or **aware**. + +A naive datetime does not contain enough timezone information to unambiguously position itself relative to other moments in the world. + +```python +from datetime import datetime + +naive = datetime(2026, 8, 27, 18, 30) +print(naive.tzinfo) +``` + +An aware datetime has timezone information that can provide an offset from UTC: + +```python +from datetime import datetime, timezone + +aware = datetime(2026, 8, 27, 18, 30, tzinfo=timezone.utc) +print(aware.tzinfo) +print(aware.utcoffset()) +``` + +This distinction matters in APIs, logs, distributed systems, scheduled jobs, and any system that crosses timezone boundaries. + +## 16. Representing UTC + +Use `timezone.utc` for UTC: + +```python +from datetime import datetime, timezone + +moment = datetime(2026, 8, 27, 21, 30, tzinfo=timezone.utc) + +print(moment.isoformat()) +``` + +The result includes the UTC offset: + +```text +2026-08-27T21:30:00+00:00 +``` + +## 17. Fixed UTC offsets + +`timezone` can represent fixed offsets: + +```python +from datetime import datetime, timedelta, timezone + +brt = timezone(timedelta(hours=-3)) +moment = datetime(2026, 8, 27, 18, 30, tzinfo=brt) + +print(moment.isoformat()) +``` + +A fixed offset such as `-03:00` is not the same thing as a real geographic timezone. Geographic zones can change offset because of historical rules, daylight-saving transitions, and political changes. + +## 18. Converting with `astimezone()` + +For an aware datetime, use `astimezone()` to represent the same instant in another timezone: + +```python +from datetime import datetime, timedelta, timezone + +brt = timezone(timedelta(hours=-3)) +local = datetime(2026, 8, 27, 18, 30, tzinfo=brt) +utc = local.astimezone(timezone.utc) + +print(local.isoformat()) +print(utc.isoformat()) +``` + +The wall-clock value changes, but both objects represent the same instant. + +## 19. Assigning `tzinfo` is not timezone conversion + +This code changes metadata without converting the clock reading: + +```python +from datetime import datetime, timezone + +naive = datetime(2026, 8, 27, 18, 30) +labeled = naive.replace(tzinfo=timezone.utc) + +print(labeled.isoformat()) +``` + +`replace(tzinfo=...)` does not ask, "what time is 18:30 in another zone?" It constructs a new object with fields replaced. + +Use it only when you already know what timezone the naive wall-clock value is supposed to represent and attaching that timezone is the intended operation. + +For converting an already-aware datetime from one timezone to another, use `astimezone()`. + +## 20. Do not mix naive and aware arithmetic casually + +Subtracting an aware datetime from a naive datetime is not a meaningful operation without an explicit timezone relationship. + +```python +from datetime import datetime, timezone + +naive = datetime(2026, 8, 27, 18, 30) +aware = datetime(2026, 8, 27, 18, 30, tzinfo=timezone.utc) + +try: + difference = aware - naive +except TypeError: + print("Cannot mix naive and aware datetimes") +``` + +Choose and document a timezone policy at system boundaries instead of silently mixing models. + +## 21. Real geographic time zones and `zoneinfo` + +The standard library includes the companion `zoneinfo` module for IANA time-zone rules such as `America/Sao_Paulo` or `Europe/London`. + +Conceptually: + +```python +from datetime import datetime +from zoneinfo import ZoneInfo + +moment = datetime(2026, 8, 27, 18, 30, tzinfo=ZoneInfo("America/Sao_Paulo")) +print(moment.isoformat()) +``` + +Unlike `timezone(timedelta(...))`, `ZoneInfo` can model historical and future offset rules supplied by the available timezone database. + +Timezone database availability is environment-dependent. Some systems provide it directly; others may need the `tzdata` package. For that reason, the executable examples in this chapter use fixed offsets rather than assuming a specific IANA database is installed. + +## 22. Unix timestamps + +A Unix timestamp represents elapsed seconds from the platform's Unix epoch convention. + +Create an aware UTC datetime from a timestamp by supplying a timezone: + +```python +from datetime import datetime, timezone + +moment = datetime.fromtimestamp(0, tz=timezone.utc) +print(moment.isoformat()) +``` + +Convert an aware datetime back to a timestamp with `.timestamp()`: + +```python +from datetime import datetime, timezone + +moment = datetime(1970, 1, 1, tzinfo=timezone.utc) +print(moment.timestamp()) +``` + +Timestamps are useful interchange values, but readability, supported ranges, precision, and platform behavior still matter. Do not use them as a replacement for understanding timezone policy. + +## 23. Replacing fields + +`replace()` returns a new object with selected fields changed: + +```python +from datetime import datetime + +original = datetime(2026, 8, 27, 18, 30) +updated = original.replace(hour=9, minute=0) + +print(original) +print(updated) +``` + +It does not mutate the original object. + +This is field replacement, not business-calendar arithmetic. Changing `month=2` on a date whose day is invalid in February can raise `ValueError`. + +## 24. Combining a date and a time + +`datetime.combine()` is useful when separate values need to become one datetime: + +```python +from datetime import date, datetime, time + +calendar_date = date(2026, 8, 27) +clock_time = time(18, 30) +moment = datetime.combine(calendar_date, clock_time) + +print(moment) +``` + +The resulting object is naive unless timezone information is supplied through the time or an explicit timezone-aware design. + +## 25. Common mistakes + +### Mistake 1: storing everything as strings + +Strings are appropriate at boundaries, but calculations should usually use date/time objects. + +### Mistake 2: treating `timedelta.seconds` as the whole duration + +Use `total_seconds()` when you need all days converted into seconds too. + +### Mistake 3: using `timedelta(days=30)` as "one month" + +That is 30 days, not calendar-month arithmetic. + +### Mistake 4: parsing without an explicit contract + +If incoming text has a defined format, encode that format deliberately and handle `ValueError` when input can be invalid. + +### Mistake 5: mixing naive and aware datetimes + +Define whether your system works in local time, UTC, or explicit zones at each boundary. + +### Mistake 6: using `replace(tzinfo=...)` as a conversion + +Field replacement and timezone conversion are different operations. + +### Mistake 7: using a fixed offset as if it were a geographic timezone + +Real time zones may have rule changes. Use `zoneinfo` when geographic rules matter. + +### Mistake 8: using the real clock in deterministic tests + +Inject or construct fixed datetimes when reproducibility matters. + +## 26. Practical example + +Imagine a report that receives a UTC timestamp as text, parses it, applies a fixed local offset for presentation, and calculates a review deadline. + +```python +from datetime import datetime, timedelta, timezone + +source = "2026-08-27T21:30:00+00:00" +created_utc = datetime.fromisoformat(source) + +local_zone = timezone(timedelta(hours=-3)) +created_local = created_utc.astimezone(local_zone) +deadline = created_local + timedelta(days=5) + +print(created_local.isoformat()) +print(deadline.isoformat()) +``` + +The flow is explicit: + +```text +text contract + ↓ +aware datetime + ↓ +timezone conversion + ↓ +duration arithmetic + ↓ +formatted output +``` + +## 27. Exercise + +Create a program that: + +1. parses `"2026-10-15 09:30"` using `strptime()`; +2. treats that value as a wall-clock time with a fixed offset of `-03:00`; +3. adds 2 days and 4 hours with `timedelta`; +4. converts the result to UTC with `astimezone()`; +5. prints both the local and UTC values with `isoformat()`; +6. prints the complete duration in seconds; +7. formats the UTC result as `YYYY-MM-DD HH:MM`. + +Then answer: + +- Which objects are naive and which are aware? +- Why is `replace(tzinfo=...)` acceptable for attaching the known source offset here but not for converting between zones? +- Why should `total_seconds()` be used instead of `.seconds` for the complete duration? +- Why is a fixed `-03:00` offset not automatically equivalent to every historical or future rule for `America/Sao_Paulo`? + +## 28. Review checklist + +Before moving on, make sure you can explain: + +- `date`, `time`, `datetime`, `timedelta`, and `timezone`; +- construction and validation of calendar values; +- `date.today()` and `datetime.now()`; +- why aware UTC should use `datetime.now(timezone.utc)`; +- date and datetime arithmetic; +- `.days`, `.seconds`, and `.total_seconds()`; +- why fixed durations are not calendar months; +- `strptime()` versus `strftime()`; +- `fromisoformat()` and `isoformat()`; +- naive versus aware datetimes; +- UTC and fixed offsets; +- `astimezone()` versus `replace(tzinfo=...)`; +- why real geographic timezone rules belong to `zoneinfo`; +- timestamps and their role as interchange values; +- how to keep tests deterministic. + +## Quick reference + +```python +from datetime import date, datetime, time, timedelta, timezone + +calendar_date = date(2026, 8, 27) +clock_time = time(18, 30) +moment = datetime(2026, 8, 27, 18, 30) +duration = timedelta(days=2, hours=4) + +calendar_date + timedelta(days=1) +moment + duration + +datetime.strptime("2026-08-27 18:30", "%Y-%m-%d %H:%M") +moment.strftime("%d/%m/%Y %H:%M") + +date.fromisoformat("2026-08-27") +datetime.fromisoformat("2026-08-27T18:30:00+00:00") +moment.isoformat() + +aware_utc = datetime(2026, 8, 27, 21, 30, tzinfo=timezone.utc) +fixed_offset = timezone(timedelta(hours=-3)) +aware_utc.astimezone(fixed_offset) + +duration.total_seconds() +``` + +## Executable examples + +- [`examples/date_arithmetic.py`](examples/date_arithmetic.py) +- [`examples/parse_and_format.py`](examples/parse_and_format.py) +- [`examples/utc_conversion.py`](examples/utc_conversion.py) +- [`examples/duration_seconds.py`](examples/duration_seconds.py) + +The examples are deterministic and do not depend on the current clock or an external timezone database. + +## Next chapter + +Continue with **Chapter 03: `json` Beyond Basic Persistence**, where the standard library revisits JSON serialization with deeper control over encoders, decoders, formatting, numeric hooks, and strict interoperability contracts. + +## Official references + +- [Python 3.14 `datetime` - Basic date and time types](https://docs.python.org/3.14/library/datetime.html) +- [Python 3.14 `strftime()` and `strptime()` format codes](https://docs.python.org/3.14/library/datetime.html#strftime-and-strptime-format-codes) +- [Python 3.14 `zoneinfo` - IANA time zone support](https://docs.python.org/3.14/library/zoneinfo.html) diff --git a/standard-library/02-datetime/README.pt-BR.md b/standard-library/02-datetime/README.pt-BR.md new file mode 100644 index 0000000..6beb09c --- /dev/null +++ b/standard-library/02-datetime/README.pt-BR.md @@ -0,0 +1,703 @@ +# Trabalhando com Datas e Cálculos de Tempo Usando `datetime` + +[🇺🇸 English](README.md) · [🇧🇷 Português](README.pt-BR.md) · [🇪🇸 Español](README.es.md) + +O módulo `datetime` do Python fornece objetos explícitos para datas, horários, valores combinados de data e hora, durações, deslocamentos fixos de UTC, parsing, formatação, comparação e aritmética. + +Strings como `"2026-08-27"` são úteis para armazenamento e comunicação, mas não sabem automaticamente quantos dias separam duas datas, se um ano é bissexto ou como somar uma duração corretamente. O módulo `datetime` dá tipos e regras próprios a esses conceitos. + +Para a maior parte do trabalho iniciante e intermediário, os imports centrais são: + +```python +from datetime import date, datetime, time, timedelta, timezone +``` + +## Objetivos de aprendizagem + +Ao final deste capítulo, você deverá conseguir: + +- distinguir `date`, `time`, `datetime` e `timedelta`; +- construir objetos de data e hora explicitamente; +- inspecionar componentes de ano, mês, dia, hora, minuto e segundo; +- usar `date.today()` e `datetime.now()` de forma consciente; +- fazer aritmética com `timedelta`; +- entender a diferença entre `timedelta.seconds` e `timedelta.total_seconds()`; +- fazer parsing com `strptime()` e formatação com `strftime()`; +- usar helpers ISO como `fromisoformat()` e `isoformat()`; +- distinguir objetos `datetime` naive e timezone-aware; +- representar UTC e offsets fixos com `timezone`; +- converter datetimes aware com `astimezone()`; +- entender por que atribuir `tzinfo` não é o mesmo que converter um horário; +- evitar tratar durações fixas como regras de meses do calendário; +- reconhecer quando fusos reais exigem o módulo complementar `zoneinfo`. + +## 1. Por que usar tipos próprios para data e hora? + +Considere duas strings: + +```python +start = "2026-08-27" +end = "2026-09-03" +``` + +Uma pessoa percebe que parecem datas, mas o Python ainda vê strings comuns. + +Com `date`, o significado fica explícito: + +```python +from datetime import date + +start = date(2026, 8, 27) +end = date(2026, 9, 3) + +print(end - start) +``` + +A subtração produz um `timedelta`, pois o Python agora sabe que os valores representam datas de calendário. + +A ideia de design é: + +```text +texto para representação + != +objetos para comportamento de data/hora +``` + +## 2. As classes centrais + +As classes mais usadas são: + +| Classe | Representa | +|---|---| +| `date` | data de calendário: ano, mês e dia | +| `time` | horário sem uma data de calendário | +| `datetime` | data e horário juntos | +| `timedelta` | duração entre pontos no tempo | +| `timezone` | offset fixo em relação ao UTC | + +Elas resolvem problemas relacionados, mas não são intercambiáveis. + +## 3. Criando um `date` + +Construa uma data com ano, mês e dia: + +```python +from datetime import date + +release_date = date(2026, 8, 27) + +print(release_date.year) +print(release_date.month) +print(release_date.day) +``` + +Valores impossíveis falham imediatamente: + +```python +from datetime import date + +try: + impossible = date(2026, 2, 30) +except ValueError: + print("Invalid calendar date") +``` + +Essa validação é uma vantagem de usar um tipo de data em vez de transportar texto não validado pelo programa. + +## 4. Criando um `time` + +Um `time` representa um horário: + +```python +from datetime import time + +meeting_time = time(14, 30, 15) + +print(meeting_time.hour) +print(meeting_time.minute) +print(meeting_time.second) +``` + +Um objeto `time` não contém ano, mês ou dia. Ele é útil quando o horário importa independentemente da data. + +Não espere somar um `timedelta` diretamente a um `time` simples. A aritmética de horário normalmente precisa de um `datetime` ou de regras da aplicação sobre qual data deve ser usada. + +## 5. Criando um `datetime` + +Um `datetime` combina os dois conceitos: + +```python +from datetime import datetime + +moment = datetime(2026, 8, 27, 14, 30, 15) + +print(moment.date()) +print(moment.time()) +print(moment.year) +print(moment.hour) +``` + +Isso é útil para eventos, timestamps, prazos, logs, compromissos e outros valores em que data e horário importam. + +## 6. Data e horário atuais + +`date.today()` retorna a data local atual: + +```python +from datetime import date + +today = date.today() +print(today) +``` + +`datetime.now()` retorna a data e hora locais atuais como `datetime` naive por padrão: + +```python +from datetime import datetime + +now = datetime.now() +print(now) +``` + +Para um `datetime` UTC aware, prefira: + +```python +from datetime import datetime, timezone + +now_utc = datetime.now(timezone.utc) +print(now_utc) +``` + +Evite chamadas ao relógio real quando um teste ou exemplo determinístico puder usar um valor fixo. + +### Evite `datetime.utcnow()` em código novo + +`datetime.utcnow()` retorna um objeto naive mesmo representando UTC e está deprecated no Python moderno. Prefira `datetime.now(timezone.utc)` para que a relação com UTC fique explícita no próprio objeto. + +## 7. O que é um `timedelta`? + +Um `timedelta` representa uma duração. + +```python +from datetime import timedelta + +review_window = timedelta(days=7, hours=3) +print(review_window) +``` + +Ele pode ser somado ou subtraído de datas e datetimes: + +```python +from datetime import date, timedelta + +start = date(2026, 8, 27) +end = start + timedelta(days=10) + +print(end) +``` + +Subtrair datas ou datetimes compatíveis produz um `timedelta`: + +```python +from datetime import date + +start = date(2026, 8, 27) +end = date(2026, 9, 3) + +difference = end - start +print(difference.days) +``` + +## 8. `timedelta.seconds` não são os segundos totais + +Este é um erro clássico. + +```python +from datetime import timedelta + +duration = timedelta(days=1, seconds=90) + +print(duration.days) +print(duration.seconds) +print(duration.total_seconds()) +``` + +`duration.seconds` é apenas a parte normalizada de segundos dentro do dia. Ela não inclui dias inteiros. + +Use `total_seconds()` quando precisar da duração completa expressa em segundos. + +No exemplo acima: + +```text +componente de segundos = 90 +duração total = 86490 segundos +``` + +## 9. Durações não são meses do calendário + +Um `timedelta` modela durações fixas em dias, segundos e microssegundos. Ele não possui o conceito embutido de "um mês de calendário". + +Isto: + +```python +from datetime import date, timedelta + +start = date(2026, 1, 31) +approximate = start + timedelta(days=30) + +print(approximate) +``` + +significa exatamente "somar 30 dias". Não significa "ir para o mesmo dia do mês seguinte". + +Regras de fechamento de mês, feriados, calendários comerciais e vencimentos são políticas da aplicação e precisam ser modeladas explicitamente. + +## 10. Comparando datas e datetimes + +Objetos compatíveis do mesmo tipo podem ser comparados: + +```python +from datetime import date + +deadline = date(2026, 9, 10) +today = date(2026, 9, 3) + +if today <= deadline: + print("Still on time") +``` + +Não compare strings formatadas só porque parecem datas. Alguns formatos ordenam cronologicamente, outros não, e comparação de strings não fornece semântica de calendário. + +## 11. Fazendo parsing com `strptime()` + +Dados externos frequentemente chegam como texto. + +Use `datetime.strptime()` quando a entrada seguir um formato conhecido: + +```python +from datetime import datetime + +text = "27/08/2026 18:45" +moment = datetime.strptime(text, "%d/%m/%Y %H:%M") + +print(moment) +``` + +A string de formato é um contrato entre seu código e a entrada. + +Diretivas comuns: + +| Diretiva | Significado | +|---|---| +| `%Y` | ano com quatro dígitos | +| `%m` | número do mês | +| `%d` | dia do mês | +| `%H` | hora de 00 a 23 | +| `%M` | minuto | +| `%S` | segundo | +| `%f` | microssegundos | +| `%z` | offset UTC | + +Se o texto não corresponder ao formato esperado, o parsing gera `ValueError`. + +```python +from datetime import datetime + +try: + moment = datetime.strptime("2026/08/27", "%Y-%m-%d") +except ValueError: + print("Unexpected date format") +``` + +## 12. Formatando com `strftime()` + +`strftime()` faz o caminho inverso: objeto para texto. + +```python +from datetime import datetime + +moment = datetime(2026, 8, 27, 18, 45) + +print(moment.strftime("%Y-%m-%d")) +print(moment.strftime("%d/%m/%Y %H:%M")) +``` + +Mantenha a distinção clara: + +```text +strptime: texto -> datetime +strftime: datetime/date/time -> texto +``` + +## 13. Helpers orientados a ISO + +Para representações em estilo ISO, métodos dedicados costumam ser mais claros que formatos customizados. + +```python +from datetime import date, datetime + +calendar_date = date.fromisoformat("2026-08-27") +moment = datetime.fromisoformat("2026-08-27T18:45:00+00:00") + +print(calendar_date.isoformat()) +print(moment.isoformat()) +``` + +`fromisoformat()` e `isoformat()` são convenientes quando o contrato corresponde às formas suportadas pelo parser e formatador orientados a ISO do Python. + +Não assuma que toda string chamada informalmente de "ISO 8601" será aceita por qualquer parser. O formato exato aceito faz parte do contrato da interface. + +## 14. Controlando a precisão da saída ISO + +`datetime.isoformat()` pode controlar a precisão exibida: + +```python +from datetime import datetime + +moment = datetime(2026, 8, 27, 18, 45, 12, 345678) + +print(moment.isoformat(timespec="minutes")) +print(moment.isoformat(timespec="seconds")) +print(moment.isoformat(timespec="microseconds")) +``` + +Isso é útil quando um formato externo exige precisão específica. + +## 15. Datetimes naive e aware + +Um `datetime` pode ser **naive** ou **aware**. + +Um datetime naive não contém informações suficientes de timezone para se posicionar de forma inequívoca em relação a outros instantes no mundo. + +```python +from datetime import datetime + +naive = datetime(2026, 8, 27, 18, 30) +print(naive.tzinfo) +``` + +Um datetime aware possui informação de timezone capaz de fornecer offset em relação ao UTC: + +```python +from datetime import datetime, timezone + +aware = datetime(2026, 8, 27, 18, 30, tzinfo=timezone.utc) +print(aware.tzinfo) +print(aware.utcoffset()) +``` + +Essa diferença é importante em APIs, logs, sistemas distribuídos e agendamentos que atravessam fusos. + +## 16. Representando UTC + +Use `timezone.utc` para UTC: + +```python +from datetime import datetime, timezone + +moment = datetime(2026, 8, 27, 21, 30, tzinfo=timezone.utc) + +print(moment.isoformat()) +``` + +O resultado inclui o offset UTC: + +```text +2026-08-27T21:30:00+00:00 +``` + +## 17. Offsets UTC fixos + +`timezone` pode representar offsets fixos: + +```python +from datetime import datetime, timedelta, timezone + +brt = timezone(timedelta(hours=-3)) +moment = datetime(2026, 8, 27, 18, 30, tzinfo=brt) + +print(moment.isoformat()) +``` + +Um offset fixo como `-03:00` não é o mesmo que um fuso geográfico real. Fusos geográficos podem mudar de offset por regras históricas, horário de verão e mudanças legais. + +## 18. Convertendo com `astimezone()` + +Para um datetime aware, use `astimezone()` para representar o mesmo instante em outro timezone: + +```python +from datetime import datetime, timedelta, timezone + +brt = timezone(timedelta(hours=-3)) +local = datetime(2026, 8, 27, 18, 30, tzinfo=brt) +utc = local.astimezone(timezone.utc) + +print(local.isoformat()) +print(utc.isoformat()) +``` + +O horário exibido muda, mas os dois objetos representam o mesmo instante. + +## 19. Atribuir `tzinfo` não é converter timezone + +Este código altera metadados sem converter o valor do relógio: + +```python +from datetime import datetime, timezone + +naive = datetime(2026, 8, 27, 18, 30) +labeled = naive.replace(tzinfo=timezone.utc) + +print(labeled.isoformat()) +``` + +`replace(tzinfo=...)` não pergunta "que horas são 18:30 em outro fuso?". Ele cria um novo objeto com campos substituídos. + +Use isso apenas quando você já souber qual timezone aquele horário naive deveria representar e anexar essa informação for a operação pretendida. + +Para converter um datetime já aware entre fusos, use `astimezone()`. + +## 20. Não misture aritmética naive e aware casualmente + +Subtrair um datetime aware de um naive não possui significado sem uma relação explícita de timezone. + +```python +from datetime import datetime, timezone + +naive = datetime(2026, 8, 27, 18, 30) +aware = datetime(2026, 8, 27, 18, 30, tzinfo=timezone.utc) + +try: + difference = aware - naive +except TypeError: + print("Cannot mix naive and aware datetimes") +``` + +Escolha e documente uma política de timezone nas fronteiras do sistema. + +## 21. Fusos geográficos reais e `zoneinfo` + +A biblioteca padrão inclui o módulo complementar `zoneinfo` para regras IANA como `America/Sao_Paulo` ou `Europe/London`. + +Conceitualmente: + +```python +from datetime import datetime +from zoneinfo import ZoneInfo + +moment = datetime(2026, 8, 27, 18, 30, tzinfo=ZoneInfo("America/Sao_Paulo")) +print(moment.isoformat()) +``` + +Diferentemente de `timezone(timedelta(...))`, `ZoneInfo` pode modelar regras históricas e futuras fornecidas pelo banco de dados de timezones disponível. + +A disponibilidade desse banco depende do ambiente. Alguns sistemas o fornecem diretamente; outros podem precisar do pacote `tzdata`. Por isso, os exemplos executáveis deste capítulo usam offsets fixos. + +## 22. Unix timestamps + +Um Unix timestamp representa segundos decorridos a partir da convenção de epoch Unix da plataforma. + +Crie um datetime UTC aware fornecendo timezone: + +```python +from datetime import datetime, timezone + +moment = datetime.fromtimestamp(0, tz=timezone.utc) +print(moment.isoformat()) +``` + +Converta um datetime aware de volta com `.timestamp()`: + +```python +from datetime import datetime, timezone + +moment = datetime(1970, 1, 1, tzinfo=timezone.utc) +print(moment.timestamp()) +``` + +Timestamps são úteis como valores de intercâmbio, mas legibilidade, faixa suportada, precisão e comportamento de plataforma ainda importam. Não os use como substitutos para compreender e definir uma política de timezone. + +## 23. Substituindo campos + +`replace()` retorna um novo objeto com campos selecionados alterados: + +```python +from datetime import datetime + +original = datetime(2026, 8, 27, 18, 30) +updated = original.replace(hour=9, minute=0) + +print(original) +print(updated) +``` + +Ele não modifica o objeto original. + +Isso é substituição de campos, não aritmética de calendário comercial. Alterar `month=2` em uma data cujo dia não existe em fevereiro pode gerar `ValueError`. + +## 24. Combinando data e horário + +`datetime.combine()` é útil quando valores separados precisam se tornar um único datetime: + +```python +from datetime import date, datetime, time + +calendar_date = date(2026, 8, 27) +clock_time = time(18, 30) +moment = datetime.combine(calendar_date, clock_time) + +print(moment) +``` + +O resultado é naive, a menos que informação de timezone seja fornecida por um design explícito. + +## 25. Erros comuns + +### Erro 1: armazenar tudo como string + +Strings são apropriadas nas fronteiras, mas cálculos devem normalmente usar objetos de data/hora. + +### Erro 2: tratar `timedelta.seconds` como duração inteira + +Use `total_seconds()` quando precisar incluir os dias. + +### Erro 3: usar `timedelta(days=30)` como "um mês" + +Isso significa 30 dias, não um mês de calendário. + +### Erro 4: fazer parsing sem contrato explícito + +Se a entrada tem formato definido, codifique esse formato deliberadamente e trate `ValueError` quando a entrada puder ser inválida. + +### Erro 5: misturar datetimes naive e aware + +Defina se o sistema usa horário local, UTC ou fusos explícitos em cada fronteira. + +### Erro 6: usar `replace(tzinfo=...)` como conversão + +Substituição de campo e conversão de timezone são operações diferentes. + +### Erro 7: usar offset fixo como se fosse fuso geográfico + +Regras reais podem mudar. Use `zoneinfo` quando regras geográficas importarem. + +### Erro 8: usar o relógio real em testes determinísticos + +Injete ou construa datetimes fixos quando a reprodutibilidade for importante. + +## 26. Exemplo prático + +Imagine um relatório que recebe um timestamp UTC em texto, faz parsing, aplica um offset local fixo para apresentação e calcula um prazo de revisão. + +```python +from datetime import datetime, timedelta, timezone + +source = "2026-08-27T21:30:00+00:00" +created_utc = datetime.fromisoformat(source) + +local_zone = timezone(timedelta(hours=-3)) +created_local = created_utc.astimezone(local_zone) +deadline = created_local + timedelta(days=5) + +print(created_local.isoformat()) +print(deadline.isoformat()) +``` + +O fluxo fica explícito: + +```text +contrato de texto + ↓ +datetime aware + ↓ +conversão de timezone + ↓ +aritmética de duração + ↓ +saída formatada +``` + +## 27. Exercício + +Crie um programa que: + +1. faça parsing de `"2026-10-15 09:30"` usando `strptime()`; +2. trate esse valor como horário de parede com offset fixo `-03:00`; +3. some 2 dias e 4 horas com `timedelta`; +4. converta o resultado para UTC com `astimezone()`; +5. imprima os valores local e UTC com `isoformat()`; +6. imprima a duração completa em segundos; +7. formate o resultado UTC como `YYYY-MM-DD HH:MM`. + +Depois responda: + +- Quais objetos são naive e quais são aware? +- Por que `replace(tzinfo=...)` é aceitável para anexar o offset conhecido da origem aqui, mas não para converter entre fusos? +- Por que `total_seconds()` deve ser usado em vez de `.seconds` para a duração completa? +- Por que um offset fixo `-03:00` não equivale automaticamente a todas as regras históricas ou futuras de `America/Sao_Paulo`? + +## 28. Checklist de revisão + +Antes de avançar, confirme que você consegue explicar: + +- `date`, `time`, `datetime`, `timedelta` e `timezone`; +- construção e validação de valores de calendário; +- `date.today()` e `datetime.now()`; +- por que UTC aware deve usar `datetime.now(timezone.utc)`; +- aritmética de datas e datetimes; +- `.days`, `.seconds` e `.total_seconds()`; +- por que durações fixas não são meses de calendário; +- `strptime()` versus `strftime()`; +- `fromisoformat()` e `isoformat()`; +- datetimes naive versus aware; +- UTC e offsets fixos; +- `astimezone()` versus `replace(tzinfo=...)`; +- por que regras de fusos geográficos pertencem ao `zoneinfo`; +- timestamps como valores de intercâmbio; +- como manter testes determinísticos. + +## Referência rápida + +```python +from datetime import date, datetime, time, timedelta, timezone + +calendar_date = date(2026, 8, 27) +clock_time = time(18, 30) +moment = datetime(2026, 8, 27, 18, 30) +duration = timedelta(days=2, hours=4) + +calendar_date + timedelta(days=1) +moment + duration + +datetime.strptime("2026-08-27 18:30", "%Y-%m-%d %H:%M") +moment.strftime("%d/%m/%Y %H:%M") + +date.fromisoformat("2026-08-27") +datetime.fromisoformat("2026-08-27T18:30:00+00:00") +moment.isoformat() + +aware_utc = datetime(2026, 8, 27, 21, 30, tzinfo=timezone.utc) +fixed_offset = timezone(timedelta(hours=-3)) +aware_utc.astimezone(fixed_offset) + +duration.total_seconds() +``` + +## Exemplos executáveis + +- [`examples/date_arithmetic.py`](examples/date_arithmetic.py) +- [`examples/parse_and_format.py`](examples/parse_and_format.py) +- [`examples/utc_conversion.py`](examples/utc_conversion.py) +- [`examples/duration_seconds.py`](examples/duration_seconds.py) + +Os exemplos são determinísticos e não dependem do relógio atual nem de um banco externo de timezones. + +## Próximo capítulo + +Continue com **Capítulo 03: `json` Além da Persistência Básica**, onde a biblioteca padrão revisita serialização JSON com controle mais profundo de encoders, decoders, formatação, hooks numéricos e contratos rigorosos de interoperabilidade. + +## Referências oficiais + +- [Python 3.14 `datetime` - tipos básicos de data e hora](https://docs.python.org/3.14/library/datetime.html) +- [Python 3.14 códigos de formato de `strftime()` e `strptime()`](https://docs.python.org/3.14/library/datetime.html#strftime-and-strptime-format-codes) +- [Python 3.14 `zoneinfo` - suporte a fusos IANA](https://docs.python.org/3.14/library/zoneinfo.html) diff --git a/standard-library/02-datetime/examples/date_arithmetic.py b/standard-library/02-datetime/examples/date_arithmetic.py new file mode 100644 index 0000000..2746816 --- /dev/null +++ b/standard-library/02-datetime/examples/date_arithmetic.py @@ -0,0 +1,8 @@ +from datetime import date, timedelta + +start = date(2026, 8, 27) +deadline = start + timedelta(days=10) + +print(start.isoformat()) +print(deadline.isoformat()) +print((deadline - start).days) diff --git a/standard-library/02-datetime/examples/duration_seconds.py b/standard-library/02-datetime/examples/duration_seconds.py new file mode 100644 index 0000000..57e3980 --- /dev/null +++ b/standard-library/02-datetime/examples/duration_seconds.py @@ -0,0 +1,6 @@ +from datetime import timedelta + +duration = timedelta(days=1, seconds=90) + +print(duration.seconds) +print(duration.total_seconds()) diff --git a/standard-library/02-datetime/examples/parse_and_format.py b/standard-library/02-datetime/examples/parse_and_format.py new file mode 100644 index 0000000..967817c --- /dev/null +++ b/standard-library/02-datetime/examples/parse_and_format.py @@ -0,0 +1,7 @@ +from datetime import datetime + +text = "2026-08-27 19:45" +moment = datetime.strptime(text, "%Y-%m-%d %H:%M") + +print(moment.isoformat(timespec="minutes")) +print(moment.strftime("%d/%m/%Y %H:%M")) diff --git a/standard-library/02-datetime/examples/utc_conversion.py b/standard-library/02-datetime/examples/utc_conversion.py new file mode 100644 index 0000000..2d683ba --- /dev/null +++ b/standard-library/02-datetime/examples/utc_conversion.py @@ -0,0 +1,8 @@ +from datetime import datetime, timedelta, timezone + +brt = timezone(timedelta(hours=-3)) +local = datetime(2026, 8, 27, 18, 30, tzinfo=brt) +utc = local.astimezone(timezone.utc) + +print(local.isoformat()) +print(utc.isoformat()) diff --git a/standard-library/README.es.md b/standard-library/README.es.md index cf8cec1..ee1d221 100644 --- a/standard-library/README.es.md +++ b/standard-library/README.es.md @@ -15,7 +15,7 @@ La Fase 8 parte del modelo de imports aprendido en la Fase 7 y estudia un conjun | Capítulo | Foco principal | Nivel | Estado | |---|---|---|---| | [01. `pathlib`](01-pathlib/README.es.md) | Representar, componer, inspeccionar, crear, leer y descubrir rutas del sistema de archivos con objetos específicos para rutas | Intermedio | Disponible | -| 02. `datetime` | Trabajar con fechas, horas, duraciones, parsing, formato y aritmética | Intermedio | Planificado | +| [02. `datetime`](02-datetime/README.es.md) | Trabajar con fechas, horas, duraciones, parsing, formato, conciencia de timezone y aritmética | Intermedio | Disponible | | 03. `json` | Usar el módulo `json` más allá de la persistencia básica, incluidas opciones de serialización y contratos más estrictos | Intermedio | Planificado | | 04. `csv` | Trabajar con dialectos CSV, quoting, readers, writers y límites de texto tabular | Intermedio | Planificado | | 05. `logging` | Configurar loggers, handlers, formatters, niveles y logging de aplicación frente a biblioteca | Intermedio | Planificado | @@ -76,7 +76,7 @@ Al final de la Fase 8 deberías poder: ## Estado de la fase -La Fase 8 está en progreso. El Capítulo 01 introduce [`pathlib`](01-pathlib/README.es.md) como el primer módulo estudiado de forma enfocada. +La Fase 8 está en progreso. El Capítulo 01 introduce [`pathlib`](01-pathlib/README.es.md), y el Capítulo 02 añade [`datetime`](02-datetime/README.es.md) para fechas, horas, duraciones, parsing, formato, valores conscientes de timezone y cálculos de tiempo. El próximo capítulo planificado es `json` más allá de la persistencia básica. Los capítulos posteriores revisitarán `json`, `csv` y `logging` a un nivel más profundo de biblioteca. Sus apariciones anteriores enseñaron formatos de archivo o conceptos más amplios de diseño; en esta fase estudiamos los módulos, sus APIs y sus trade-offs. @@ -87,15 +87,24 @@ standard-library/ ├── README.md ├── README.pt-BR.md ├── README.es.md -└── 01-pathlib/ +├── 01-pathlib/ +│ ├── README.md +│ ├── README.pt-BR.md +│ ├── README.es.md +│ └── examples/ +│ ├── discover_python_files.py +│ ├── inspect_paths.py +│ ├── path_parts.py +│ └── text_workspace.py +└── 02-datetime/ ├── README.md ├── README.pt-BR.md ├── README.es.md └── examples/ - ├── discover_python_files.py - ├── inspect_paths.py - ├── path_parts.py - └── text_workspace.py + ├── date_arithmetic.py + ├── duration_seconds.py + ├── parse_and_format.py + └── utc_conversion.py ``` Se añadirán nuevos directorios de capítulos a medida que avance la fase. diff --git a/standard-library/README.md b/standard-library/README.md index 03fec63..f71845c 100644 --- a/standard-library/README.md +++ b/standard-library/README.md @@ -15,7 +15,7 @@ Phase 8 builds on the import model from Phase 7 and studies a focused set of mod | Chapter | Main focus | Level | Status | |---|---|---|---| | [01. `pathlib`](01-pathlib/README.md) | Represent, compose, inspect, create, read, and discover filesystem paths with path-aware objects | Intermediate | Available | -| 02. `datetime` | Work with dates, times, durations, parsing, formatting, and arithmetic | Intermediate | Planned | +| [02. `datetime`](02-datetime/README.md) | Work with dates, times, durations, parsing, formatting, timezone awareness, and arithmetic | Intermediate | Available | | 03. `json` | Use the `json` module beyond basic file persistence, including serialization options and stricter contracts | Intermediate | Planned | | 04. `csv` | Work with CSV dialects, quoting, readers, writers, and tabular text boundaries | Intermediate | Planned | | 05. `logging` | Configure loggers, handlers, formatters, levels, and application versus library logging | Intermediate | Planned | @@ -76,7 +76,7 @@ By the end of Phase 8, you should be able to: ## Phase status -Phase 8 is in progress. Chapter 01 introduces [`pathlib`](01-pathlib/README.md) as the first focused standard-library module. +Phase 8 is in progress. Chapter 01 introduces [`pathlib`](01-pathlib/README.md), and Chapter 02 adds [`datetime`](02-datetime/README.md) for dates, times, durations, parsing, formatting, timezone-aware values, and time calculations. The next planned chapter is `json` beyond basic persistence. Later chapters will revisit `json`, `csv`, and `logging` at a deeper library level. Their earlier appearances taught file formats or broader design concepts; this phase studies the modules themselves, their APIs, and their trade-offs. @@ -87,15 +87,24 @@ standard-library/ ├── README.md ├── README.pt-BR.md ├── README.es.md -└── 01-pathlib/ +├── 01-pathlib/ +│ ├── README.md +│ ├── README.pt-BR.md +│ ├── README.es.md +│ └── examples/ +│ ├── discover_python_files.py +│ ├── inspect_paths.py +│ ├── path_parts.py +│ └── text_workspace.py +└── 02-datetime/ ├── README.md ├── README.pt-BR.md ├── README.es.md └── examples/ - ├── discover_python_files.py - ├── inspect_paths.py - ├── path_parts.py - └── text_workspace.py + ├── date_arithmetic.py + ├── duration_seconds.py + ├── parse_and_format.py + └── utc_conversion.py ``` New chapter directories will be added as the phase progresses. diff --git a/standard-library/README.pt-BR.md b/standard-library/README.pt-BR.md index 76fa0a1..320caad 100644 --- a/standard-library/README.pt-BR.md +++ b/standard-library/README.pt-BR.md @@ -15,7 +15,7 @@ A Fase 8 parte do modelo de imports aprendido na Fase 7 e estuda um conjunto foc | Capítulo | Foco principal | Nível | Status | |---|---|---|---| | [01. `pathlib`](01-pathlib/README.pt-BR.md) | Representar, compor, inspecionar, criar, ler e descobrir caminhos do sistema de arquivos com objetos próprios para caminhos | Intermediário | Disponível | -| 02. `datetime` | Trabalhar com datas, horários, durações, parsing, formatação e aritmética | Intermediário | Planejado | +| [02. `datetime`](02-datetime/README.pt-BR.md) | Trabalhar com datas, horários, durações, parsing, formatação, consciência de timezone e aritmética | Intermediário | Disponível | | 03. `json` | Usar o módulo `json` além da persistência básica, incluindo opções de serialização e contratos mais estritos | Intermediário | Planejado | | 04. `csv` | Trabalhar com dialetos CSV, quoting, readers, writers e fronteiras de texto tabular | Intermediário | Planejado | | 05. `logging` | Configurar loggers, handlers, formatters, níveis e logging de aplicação versus biblioteca | Intermediário | Planejado | @@ -76,7 +76,7 @@ Ao final da Fase 8, você deverá conseguir: ## Status da fase -A Fase 8 está em andamento. O Capítulo 01 introduz [`pathlib`](01-pathlib/README.pt-BR.md) como o primeiro módulo estudado de forma focada. +A Fase 8 está em andamento. O Capítulo 01 introduz [`pathlib`](01-pathlib/README.pt-BR.md), e o Capítulo 02 acrescenta [`datetime`](02-datetime/README.pt-BR.md) para datas, horários, durações, parsing, formatação, valores conscientes de timezone e cálculos de tempo. O próximo capítulo planejado é `json` além da persistência básica. Capítulos posteriores revisitarão `json`, `csv` e `logging` em um nível mais profundo de biblioteca. As aparições anteriores ensinaram formatos de arquivo ou conceitos maiores de design; nesta fase estudamos os módulos, suas APIs e seus trade-offs. @@ -87,15 +87,24 @@ standard-library/ ├── README.md ├── README.pt-BR.md ├── README.es.md -└── 01-pathlib/ +├── 01-pathlib/ +│ ├── README.md +│ ├── README.pt-BR.md +│ ├── README.es.md +│ └── examples/ +│ ├── discover_python_files.py +│ ├── inspect_paths.py +│ ├── path_parts.py +│ └── text_workspace.py +└── 02-datetime/ ├── README.md ├── README.pt-BR.md ├── README.es.md └── examples/ - ├── discover_python_files.py - ├── inspect_paths.py - ├── path_parts.py - └── text_workspace.py + ├── date_arithmetic.py + ├── duration_seconds.py + ├── parse_and_format.py + └── utc_conversion.py ``` Novos diretórios de capítulos serão adicionados conforme a fase avançar.