Guide

Época Explicada

Introdução

O tempo de época (também chamado de carimbo de data / hora Unix ou tempo POSIX) é um sistema para descrever um ponto no tempo como o número de segundos que se passaram desde uma data e hora de referência específicas. Compreender a época é fundamental para desenvolvedores, administradores de sistema e qualquer pessoa que trabalhe com carimbos de data/hora na computação.

O que é o tempo da época

Definição

O tempo da época representa o tempo como uma contagem contínua de unidades de tempo (geralmente segundos) a partir de um ponto de referência fixo denominado "época":

Epoch Timestamp = Current Time - Epoch Start Time

Example (Unix Epoch):
  Epoch Start: January 1, 1970, 00:00:00 UTC
  Current Time: January 8, 2024, 00:00:00 UTC
  Timestamp: 1704672000 seconds since epoch

Época Unix (horário POSIX)

O sistema de época mais amplamente usado é a época Unix (horário POSIX):

Unix Epoch Reference:
  Start Date: January 1, 1970, 00:00:00 UTC
  Time Units: Seconds (some systems use milliseconds)
  Notation: 32-bit signed integer (common) or 64-bit
  Max Range (32-bit): 1901-12-13 to 2038-01-19
  Current Use: Linux, Unix, macOS, most programming languages

Fato interessante: A época do Unix foi escolhida porque era um número redondo na época em que o Unix estava sendo desenvolvido, simplificando os cálculos e evitando carimbos de data e hora negativos para usos mais práticos.

História da Época Unix

A época Unix foi estabelecida no início dos anos 1970:

  • 1970: data da época Unix escolhida (1º de janeiro de 1970)
  • 1971-1973: Os sistemas Unix iniciais usavam o tipo time_t (32 bits)
  • 1988: O padrão POSIX adotou formalmente o horário Unix
  • Anos 2000: a maioria dos sistemas fez a transição para time_t de 64 bits para evitar o problema do ano 2038
  • 2020: sistemas modernos usam carimbos de data/hora de época de 64 bits

Por que 1970? Foi aproximadamente a época em que o Unix estava sendo desenvolvido e representa um "ponto zero" conveniente antes da existência da maioria dos sistemas de computador, evitando carimbos de data e hora negativos para a história da computação inicial.

Diferentes sistemas de época

Referências comuns de época

1. Unix Epoch (POSIX)
   Start: January 1, 1970, 00:00:00 UTC
   Units: Seconds (or milliseconds)
   Usage: Unix, Linux, macOS, most programming languages

2. Windows FILETIME
   Start: January 1, 1601, 00:00:00 UTC
   Units: 100-nanosecond intervals
   Usage: Windows file systems, NTFS

3. Mac HFS/HFS+ Epoch
   Start: January 1, 1904, 00:00:00 UTC
   Units: Seconds
   Usage: Classic Mac OS (pre-OS X)

4. GPS Epoch
   Start: January 6, 1980, 00:00:00 UTC
   Units: Seconds
   Usage: GPS systems, navigation

5. NTP Timestamp
   Start: January 1, 1900, 00:00:00 UTC
   Units: Seconds (64-bit)
   Usage: Network Time Protocol

6. WebKit/Chrome Epoch
   Start: January 1, 1601, 00:00:00 UTC
   Units: Microseconds
   Usage: Web browsers (Date object)

Importante: Sempre verifique qual sistema de época seu sistema ou API usa antes de converter carimbos de data/hora.

Época JavaScript

JavaScript usa época Unix em milissegundos:

// JavaScript Date uses Unix epoch in milliseconds
const now = Date.now();
console.log(now);  // e.g., 1704672000000 (milliseconds)

// Convert to seconds
const nowSec = Math.floor(Date.now() / 1000);
console.log(nowSec);  // e.g., 1704672000 (seconds)

// Create from Unix epoch seconds
const date = new Date(1704672000 * 1000);
console.log(date.toISOString());  // "2024-01-08T00:00:00.000Z"

Época Python

time.time() do Python usa a época Unix em segundos:

import time
from datetime import datetime

# Get current Unix timestamp (seconds)
now_ts = time.time()
print(now_ts)  # e.g., 1704672000.123

# Create datetime from Unix timestamp
dt = datetime.fromtimestamp(1704672000)
print(dt)  # 2024-01-08 00:00:00

# Get UTC timestamp
now_utc = datetime.now(timezone.utc).timestamp()
print(now_utc)  # e.g., 1704672000

Época Java

Java usa época Unix em milissegundos (consistente com JavaScript):

import java.time.Instant;

// Get current timestamp (milliseconds)
long nowMs = System.currentTimeMillis();
System.out.println(nowMs);  // e.g., 1704672000000

// Get from Instant (Java 8+)
Instant now = Instant.now();
long ts = now.getEpochSecond();
System.out.println(ts);  // e.g., 1704672000

// Create Instant from Unix timestamp
Instant instant = Instant.ofEpochSecond(1704672000);
System.out.println(instant);  // 2024-01-08T00:00:00Z

Limites e intervalos de carimbo de data/hora

Limites de números inteiros assinados de 32 bits

Os carimbos de data/hora Unix tradicionais usam números inteiros assinados de 32 bits:

32-bit Signed Integer Range:
  Min Value: -2147483648 (seconds)
  Max Value: 2147483647 (seconds)
  Min Date: December 13, 1901, 20:45:52 UTC
  Max Date: January 19, 2038, 03:14:07 UTC
  Current Date: January 8, 2024
  Time to Overflow: ~14 years

Crítico: 19 de janeiro de 2038, 03:14:07 UTC é conhecido como o "problema do ano 2038" - os carimbos de data e hora Unix de 32 bits irão transbordar e se transformar em valores negativos, quebrando muitos sistemas.

Carimbos de data e hora de 64 bits

Os sistemas modernos usam carimbos de data/hora de 64 bits para resolver problemas de overflow:

64-bit Signed Integer Range:
  Min Value: -9223372036854775808 (seconds)
  Max Value: 9223372036854775807 (seconds)
  Min Date: ~293 billion years BCE
  Max Date: ~293 billion years CE
  Practical Limit: Effectively infinite for all practical purposes
  Current Date: January 8, 2024

Prática recomendada: Sempre use carimbos de data/hora de 64 bits em novos sistemas para evitar problemas do ano 2038 e outros problemas de estouro.

Milissegundo vs Segunda Precisão

Sistemas diferentes usam precisão diferente:

Second Precision (Traditional Unix):
  Units: Seconds since epoch
  Range (32-bit): 136 years
  Use: Unix/Linux systems, APIs, databases
  Example: 1704672000

Millisecond Precision (Modern Systems):
  Units: Milliseconds since epoch
  Range (32-bit): ~49 days (not practical)
  Range (64-bit): ~293 million years
  Use: JavaScript, Java, most modern APIs
  Example: 1704672000000

Fórmula de conversão:

> Seconds to Milliseconds: seconds * 1000
> Milliseconds to Seconds: milliseconds / 1000
>

O problema do ano 2038

Qual é o problema do ano 2038?

O problema do ano 2038 é um bug de computação de tempo em que os carimbos de data/hora Unix assinados de 32 bits irão transbordar em 19 de janeiro de 2038, às 03:14:07 UTC.

Overflow Timestamp: 2147483647
Date: January 19, 2038, 03:14:07 UTC

After Overflow (Signed 32-bit wraps to negative):
Next Second: -2147483648
Date: December 13, 1901, 20:45:52 UTC

Impacto crítico: Sistemas que usam carimbos de data/hora de 32 bits falharão ou produzirão datas incorretas após 19/01/2038.

Sistemas afetados

Sistemas potencialmente afetados pelo problema do ano 2038:

  • Sistemas Unix legados ainda usando time_t de 32 bits
  • Sistemas embarcados com memória limitada
  • Sistemas de banco de dados mais antigos
  • Sistemas de arquivos usando carimbos de data/hora de 32 bits
  • Protocolos de rede com campos de hora de 32 bits
  • Algumas APIs ainda usam números inteiros de 32 bits

Soluções

Solution 1: Upgrade to 64-bit
  - Use time64_t or equivalent
  - Increases range to ~293 billion years
  - Required for long-term systems

Solution 2: Offset Timestamps
  - Store timestamps with epoch offset
  - Example: Store "years since 2000" instead of seconds since 1970
  - Requires conversion on read/write

Solution 3: Use Alternative Formats
  - Use ISO 8601 strings (no overflow)
  - Use datetime types with larger range
  - Store year, month, day separately

Prevenção: Ao projetar novos sistemas, sempre use carimbos de data/hora de 64 bits ou objetos de data e hora com intervalos maiores.

Convertendo entre épocas

Unix para Windows FILETIME

function unixToWindowsFiletime(unixTimestamp) {
  // Unix to FILETIME: 100-nanosecond intervals since 1601-01-01
  const WINDOWS_EPOCH = 0x019DB1DED53E8000; // FILETIME of Unix epoch
  const NANOSECONDS_PER_MILLISECOND = 10000;

  const filetime = (unixTimestamp * 1000 + 11644473600000) * NANOSECONDS_PER_MILLISECOND;

  // For large numbers, use BigInt
  return BigInt(unixTimestamp) * 10000n + 116444736000000000n;
}

// Example
const filetime = unixToWindowsFiletime(1704672000);
console.log(filetime);  // 1336477752000000000

Windows FILETIME para Unix

function windowsFiletimeToUnix(filetime) {
  const NANOSECONDS_PER_MILLISECOND = 10000;

  // FILETIME to Unix: subtract Windows epoch
  const unixMs = (filetime - 116444736000000000) / 10000n;

  return Number(unixMs / 1000n);
}

// Example
const filetime = 133647752000000000n;
const unixTs = windowsFiletimeToUnix(filetime);
console.log(unixTs);  // 1704672000

Unix para hora GPS

import datetime

def unix_to_gps(unix_timestamp):
    """Convert Unix timestamp to GPS timestamp"""
    # GPS epoch: January 6, 1980
    # Unix epoch: January 1, 1970
    # Difference: 315964800 seconds
    GPS_EPOCH_OFFSET = 315964800

    return unix_timestamp - GPS_EPOCH_OFFSET

def gps_to_unix(gps_timestamp):
    """Convert GPS timestamp to Unix timestamp"""
    GPS_EPOCH_OFFSET = 315964800
    return gps_timestamp + GPS_EPOCH_OFFSET

# Example
unix_ts = 1704672000
gps_ts = unix_to_gps(unix_ts)
print(f"GPS Timestamp: {gps_ts}")  # 5355687200

Horário HFS de Unix para Mac

import datetime

def unix_to_mac_hfs(unix_timestamp):
    """Convert Unix timestamp to Mac HFS timestamp"""
    # Mac HFS epoch: January 1, 1904
    # Unix epoch: January 1, 1970
    # Difference: -2082844800 seconds (Mac is earlier)
    MAC_EPOCH_OFFSET = -2082844800

    return unix_timestamp - MAC_EPOCH_OFFSET

def mac_hfs_to_unix(mac_timestamp):
    """Convert Mac HFS timestamp to Unix timestamp"""
    MAC_EPOCH_OFFSET = -2082844800
    return mac_timestamp + MAC_EPOCH_OFFSET

# Example
unix_ts = 1704672000
mac_ts = unix_to_mac_hfs(unix_ts)
print(f"Mac HFS Timestamp: {mac_ts}")  # 3787516800

Aplicações Práticas

Calculando Duração

import time

def calculate_duration(start_ts, end_ts):
    """Calculate duration between two Unix timestamps"""
    duration_seconds = end_ts - start_ts

    hours = duration_seconds // 3600
    minutes = (duration_seconds % 3600) // 60
    seconds = duration_seconds % 60

    return f"{hours}h {minutes}m {seconds}s"

# Example
start = 1704587200  # 2024-01-07 00:00:00
end = 1704673600    # 2024-01-08 00:00:00
print(calculate_duration(start, end))  # "24h 0m 0s"

Cálculo do tempo futuro/passado

function timeUntil(targetTimestamp) {
  const now = Date.now() / 1000;
  const diff = targetTimestamp - now;

  if (diff <= 0) {
    return { type: 'past', text: 'Already passed' };
  }

  const days = Math.floor(diff / 86400);
  const hours = Math.floor((diff % 86400) / 3600);
  const minutes = Math.floor((diff % 3600) / 60);

  return {
    type: 'future',
    text: `${days} days, ${hours} hours, ${minutes} minutes`
  };
}

// Calculate time until end of 2037
const target = 2155999999; // December 31, 2037
console.log(timeUntil(target));
// "511 days, 2 hours, 33 minutes"

Validação de intervalo de datas

import time

def is_valid_unix_timestamp(ts, allow_future=True):
    """Validate Unix timestamp is within reasonable range"""
    # Minimum: January 1, 1970
    MIN_TIMESTAMP = 0

    # Maximum: January 19, 2038 (32-bit limit)
    MAX_TIMESTAMP = 2147483647

    if ts < MIN_TIMESTAMP:
        return False, "Timestamp is before Unix epoch"

    if not allow_future and ts > time.time():
        return False, "Timestamp is in the future"

    if ts > MAX_TIMESTAMP:
        return False, "Timestamp exceeds 32-bit limit"

    return True, "Valid"

# Example
print(is_valid_unix_timestamp(1704672000))  # (True, "Valid")
print(is_valid_unix_timestamp(-1000))  # (False, "Timestamp is before Unix epoch")
print(is_valid_unix_timestamp(3000000000))  # (False, "Timestamp exceeds 32-bit limit")

Conversão em lote

function convertUnixTimestamps(timestamps) {
  return timestamps.map(ts => {
    const date = new Date(ts * 1000);
    return {
      timestamp: ts,
      isoString: date.toISOString(),
      utcString: date.toUTCString(),
      localString: date.toLocaleString()
    };
  });
}

// Example batch conversion
const timestamps = [1704587200, 1704673600, 1704760000];
const results = convertUnixTimestamps(timestamps);
console.log(results);
/*
[
  {
    timestamp: 1704587200,
    isoString: "2024-01-07T00:00:00.000Z",
    utcString: "Sun, 07 Jan 2024 00:00:00 GMT",
    localString: "1/7/2024, 12:00:00 AM"
  },
  ...
]
*/

Melhores práticas

Diretrizes para seleção de carimbo de data/hora

When choosing timestamp precision:
  ✅ Use seconds for Unix/Linux compatibility
  ✅ Use milliseconds for JavaScript/Java/Web compatibility
  ✅ Use 64-bit integers for future-proof systems
  ✅ Use ISO 8601 strings for cross-system compatibility
  ✅ Document epoch system in API specifications
  ❌ Don't mix precision levels in same API
  ❌ Don't use 32-bit timestamps for long-term systems
  ❌ Don't assume all systems use Unix epoch

Recomendações de armazenamento

Database storage:
  ✅ Store as TIMESTAMP or DATETIME (64-bit)
  ✅ Store timezone information separately
  ✅ Use UTC for all storage
  ✅ Validate timestamp ranges on input
  ❌ Don't store as VARCHAR or STRING
  ❌ Don't store local times without timezone metadata
  ❌ Don't use 32-bit integers for new systems

Projeto de API

REST API design:
  ✅ Use ISO 8601 in JSON responses (e.g., "2024-01-08T00:00:00Z")
  ✅ Include timezone information (Z or offset)
  ✅ Document timestamp precision (seconds or milliseconds)
  ✅ Support both input formats for flexibility
  ✅ Return descriptive errors for invalid timestamps
  ❌ Don't use locale-specific formats in APIs
  ❌ Don't assume client timezone
  ❌ Don't silently correct invalid timestamps

Estratégias de teste

import datetime

def test_epoch_conversions():
    """Test epoch conversion edge cases"""
    test_cases = [
        ("Unix epoch start", 0, datetime.datetime(1970, 1, 1)),
        ("Current time", 1704672000, datetime.datetime(2024, 1, 8)),
        ("Year 2038 limit", 2147483647, datetime.datetime(2038, 1, 19, 3, 14, 7)),
        ("Negative timestamp", -86400, datetime.datetime(1969, 12, 31, 0, 0, 0)),
    ]

    for name, timestamp, expected in test_cases:
        result = datetime.datetime.fromtimestamp(timestamp, tz=datetime.timezone.utc)
        assert result == expected, f"Failed: {name}"

    print("All epoch conversion tests passed!")

test_epoch_conversions()

Ferramentas relacionadas

Recursos Adicionais

Para a maioria das aplicações, a época Unix (1º de janeiro de 1970) é o padrão de fato. No entanto, sempre verifique o sistema de época ao integrar sistemas externos, APIs ou dados legados, pois sistemas diferentes podem usar datas de referência diferentes.

Referência rápida

Common Epoch Timestamps:
  0: January 1, 1970, 00:00:00 UTC (Unix epoch start)
  946684800: January 1, 2000, 00:00:00 UTC
  1577836800: January 1, 2020, 00:00:00 UTC
  1704067200: January 1, 2024, 00:00:00 UTC
  2147483647: January 19, 2038, 03:14:07 UTC (32-bit max)
  253402300799: December 31, 9999, 23:59:59 UTC (Common limit)