๐ Time & Timezones in Software Development โ Why They Matter¶
As a software developer or automation specialist, you know this truth:
Time and timezones can make or break your system!
I recently faced this first-hand while building an attendance app.
I began with SQLite (no timezone-aware datetime support) and later migrated to PostgreSQL (timezone-aware).
But thenโฆ โ UTC showed up in my web UI because Python wasn't serializing timezone data correctly.
When querying โtodayโs records,โ date truncation missed some entries due to timezone mismatches.
In todayโs world, we develop locally (e.g., India ๐ฎ๐ณ) but deploy on cloud servers across the globe ๐.
That difference in system time vs. local time can seriously hurt data accuracy and user experience.
1๏ธโฃ What is a Timezone?¶
A timezone is basically an offset from UTC (Coordinated Universal Time โ the modern replacement for GMT).
Think of UTC as the "world clock" โ it never changes with seasons or geography.
Examples:
- ๐ฎ๐ณ India โ UTC+05:30 (IST)
- ๐บ๐ธ New York โ
- UTC-05:00 (EST) in winter
- UTC-04:00 (EDT) in summer
- ๐ฏ๐ต Tokyo โ UTC+09:00 (JST)
2๏ธโฃ Why are Timezones Tricky?¶
-
Offset changes
Some countries adjust time twice a year (Daylight Saving Time). -
Historical changes
Governments sometimes change timezone rules. -
Local naming vs offsets
Asia/Kolkatais different from justUTC+05:30- The named timezone also carries future and past DST rules, not just the offset.
๐ Common DateTime Formats (Windows/Linux)¶
Below are common ways date and time are represented across systems and standards.
| Format Type | Example | Notes |
|---|---|---|
UTC |
2025-08-16 08:30:00 UTC | Global reference time |
IST |
2025-08-16 14:00:00 IST | UTC+05:30 |
ISO 8601 |
2025-08-16T14:00:00+05:30 | Standard for APIs |
ISO 8601 (UTC) |
2025-08-16T08:30:00Z | Z = UTC |
Epoch |
1765925400 | Seconds since 1970 UTC |
RFC 2822 |
Sat, 16 Aug 2025 14:00:00 +0530 | Used in HTTP/Email headers |
Windows Local |
8/16/2025 2:00:00 PM | Regional format dependent |
Linux Local |
Sat Aug 16 14:00:00 IST 2025 | Depends on date command configuration |
๐ง Linux Timezone Basics¶
- System timezone affects displayed local time (not UTC itself).
- Stored in
/etc/localtime(symlink to a file in/usr/share/zoneinfo).
๐ Common Commands¶
| Command | Purpose | Example Output |
|---|---|---|
date |
Show current date & time in local timezone | Sat Aug 16 14:00:00 IST 2025 |
date -u |
Show current UTC time | Sat Aug 16 08:30:00 UTC 2025 |
timedatectl |
View system time, UTC, and timezone info | Local time: ... \n Time zone: Asia/Kolkata |
timedatectl list-timezones |
List available timezones | Asia/Kolkata, America/New_York |
sudo timedatectl set-timezone <Zone> |
Change timezone | sudo timedatectl set-timezone Asia/Kolkata |
hwclock |
Show hardware clock (BIOS/RTC) | 2025-08-16 14:00:10.123456+05:30 |
๐ Timezone Files¶
/etc/localtimeโ current timezone file (binary)/usr/share/zoneinfo/โ all timezone definitions
๐ช Windows Timezone Basics¶
- Windows stores timezone info in the Registry
(HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation). - System timezone affects local time display; UTC remains the reference internally.
๐ Common Commands¶
| Command | Purpose | Example Output |
|---|---|---|
time |
View/set current system time | The current time is: 14:00:00 |
date |
View/set current system date | The current date is: Sat 08/16/2025 |
tzutil /g |
Show current timezone | India Standard Time |
tzutil /l |
List all available timezones | Pacific Standard Time, UTC, ... |
tzutil /s "<Time Zone Name>" |
Set system timezone | tzutil /s "India Standard Time" |
Get-TimeZone (PowerShell) |
Get current timezone | Id: India Standard Time |
Set-TimeZone -Id "<Id>" (PowerShell) |
Set timezone | Set-TimeZone -Id "UTC" |
๐ Notes¶
- Control Panel โ Date & Time โ Change time zone can also be used.
- Windows timezone names differ from Linux (
Asia/Kolkatain Linux is"India Standard Time"in Windows). - Always check for Daylight Saving Time rules in
tzutil /l.
๐ Python DateTime Basics¶
1๏ธโฃ Modules¶
datetimeโ Main date/time handlingzoneinfoโ Timezone support (Python 3.9+)timedeltaโ Time differences and arithmetictime
Getting Current Time¶
from datetime import datetime
from zoneinfo import ZoneInfo
import time
# Local time (system timezone)
now_local = datetime.now()
print(now_local)
# UTC time
now_utc = datetime.utcnow() # naive UTC
now_utc_aware = datetime.now(tz=ZoneInfo("UTC")) # aware UTC
print(now_utc_aware)
## Epoch (Unix Timestamp)
time.time() # float seconds since epoch
int(time.time()) # integer seconds
datetime.now(timezone.utc).timestamp() # from datetime
## Get Current Time in ISO 8601
datetime.now(timezone.utc).isoformat()
## Convert Timezone
dt_utc = datetime.now(timezone.utc)
dt_ist = dt_utc.astimezone(ZoneInfo("Asia/Kolkata"))
## Replace Timezone (without changing the clock)
dt = datetime(2025, 8, 16, 14, 0, 0)
dt_with_tz = dt.replace(tzinfo=ZoneInfo("Asia/Kolkata"))
## Parse from String
# Format must match exactly
datetime.strptime("2025-08-16 14:00:00", "%Y-%m-%d %H:%M:%S")
## Parse from Epoch
datetime.fromtimestamp(1765925400, tz=timezone.utc) # in UTC
datetime.fromtimestamp(1765925400, tz=ZoneInfo("Asia/Kolkata")) # i
## Add Days / Hours / Seconds
now = datetime.now()
now + timedelta(days=1) # Add 1 day
now + timedelta(hours=2) # Add 2 hours
now + timedelta(seconds=30) # Add 30 seconds
## Get Only Date or Time
dt = datetime.now()
dt.date() # Returns date object: 2025-08-16
dt.time() # Returns time object: 14:00:00
๐ SQLModel / SQLAlchemy โ Time & Timezone Awareness¶
1๏ธโฃ Timezone Awareness in SQLAlchemy¶
SQLAlchemy provides DateTime(timezone=True) for timezone-aware datetime columns.
from datetime import datetime, timezone
from sqlmodel import SQLModel, Field
from typing import Annotated
class Event(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), sa_column_kwargs={"timezone": True})
2๏ธโฃ Example with SQLAlchemy Core
from sqlalchemy import Column, DateTime
from sqlalchemy.sql import func
created_at = Column(DateTime(timezone=True), server_default=func.now())
3๏ธโฃ Enforcing UTC in SQLModel using Annotated
from datetime import datetime, timezone
from sqlmodel import SQLModel, Field
from typing import Annotated
def ensure_utc(dt: datetime) -> datetime:
"""Force datetime to be UTC-aware."""
if dt.tzinfo is None:
dt = dt.replace(tzinfo=timezone.utc)
else:
dt = dt.astimezone(timezone.utc)
return dt
UTCDateTime = Annotated[datetime, ensure_utc]
class Log(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
timestamp: UTCDateTime = Field(default_factory=lambda: datetime.now(timezone.utc), sa_column_kwargs={"timezone": True})
๐ผ Pandas DateTime, Epoch, and Timezone Basics¶
1๏ธโฃ Epoch in Pandas¶
- Epoch time = seconds since
1970-01-01 00:00:00 UTC. - Pandas supports:
- Seconds โ
unit='s' - Milliseconds โ
unit='ms' - Microseconds โ
unit='us' - Nanoseconds โ default for
Timestamp
import pandas as pd
# From epoch seconds
pd.to_datetime(1692172800, unit='s', utc=True)
# From epoch milliseconds
pd.to_datetime(1692172800000, unit='ms', utc=True)
# From epoch microseconds
pd.to_datetime(1692172800000000, unit='us', utc=True)
2๏ธโฃ Relation with Python datetime
pandas.Timestamp is a subclass of Pythonโs datetime.datetime but with nanosecond precision. Fully compatible with Python datetime functions.
ts = pd.Timestamp.now(tz="UTC")
isinstance(ts, datetime) # True
3๏ธโฃ NumPy and Pandas DateTime
Under the hood, Pandas often uses NumPyโs datetime64 for efficiency.
NumPy stores datetimes as integer nanoseconds from epoch.
Example:
import numpy as np
np.datetime64('2025-08-16T14:00:00Z')
np.datetime64(1692172800000, 'ms') # from milliseconds
4๏ธโฃ Current Time in Pandas
pd.Timestamp.now() # Local time
pd.Timestamp.utcnow() # Naive UTC
pd.Timestamp.now(tz="UTC") # Aware UTC
5๏ธโฃ Convert Between Timezones
ts = pd.Timestamp.now(tz="UTC")
ts.tz_convert("Asia/Kolkata")
6๏ธโฃ Parse from String / Python datetime
pd.to_datetime("2025-08-16 14:00:00", utc=True)
pd.to_datetime(datetime.now(), utc=True)
8๏ธโฃ Add / Subtract Time
ts + pd.Timedelta(days=1)
ts + pd.Timedelta(hours=2)
ts - pd.Timedelta(seconds=30)
๐ NumPy Date & Time Handling¶
NumPyโs datetime64 is not timezone-aware โ all datetime values are stored in a fixed, absolute scale based on UTC, but without any explicit timezone information attached Benefit โ Because itโs timezone-naive, operations like subtraction, sorting, and broadcasting are faster and more memory-efficient โ but you must handle local time conversion yourself.
-
Datetime Types
numpy.datetime64 โ Represents a specific date/time.
numpy.timedelta64 โ Represents a time difference (duration).
Supports different precisions: year (Y), month (M), day (D), hour (h), minute (m), second (s), millisecond (ms), microsecond (us), nanosecond (ns).
-
Key Functions ```python
Create datetime objects¶
import numpy as np np.datetime64('2025-08-16') np.datetime64('2025-08-16T15:30')
Current date/time¶
np.datetime64('now')
Date range generation¶
np.arange('2025-08-01', '2025-08-05', dtype='datetime64[D]')
Time differences¶
np.datetime64('2025-08-16') - np.datetime64('2025-08-10')
โ numpy.timedelta64(6,'D')¶
Vectorized datetime operations¶
dates = np.array(['2025-08-16', '2025-08-20'], dtype='datetime64') mask = dates > np.datetime64('2025-08-17')
array([False, True])¶
```
-
Benefits
โ Vectorized operations โ Work on entire arrays of dates at once (fast, memory-efficient).
โ Multiple precisions โ From years down to nanoseconds.
โ Simple arithmetic โ Easy difference, addition, and comparison.
โ Interoperability โ Works well with Pandas time series.
โ Lightweight โ Less overhead than Python datetime objects for large datasets.
๐ Real-World Use Cases Where Timezone Awareness Is Crucial¶
- ๐ Scheduling & calendar events across regions
- ๐ Attendance & time-tracking for remote teams
- ๐ Logging & audit trails in global systems
- ๐ฐ Financial transactions for compliance & reconciliation
- ๐ Data synchronization between countries
- ๐ User activity tracking with local timestamps
- โ Automation workflows running in user-local time
- โณ Daylight Saving Time (DST) handling
- ๐ก Cross-system communication with consistent time references
๐ Lessons Learned from My Journey¶
โ Store in UTC โ Always keep a single, reliable reference point
โ Display in local time โ Convert UTC โ userโs timezone for UI
โ In storage โ Prefer native datetime types (with timezone awareness)
โ In APIs & inter-system exchange โ Use ISO 8601 for human-readability or Epoch for compactness โ but be consistent
โ For high-performance pipelines (like Kafka or binary protocols) โ Use Epoch to minimize serialization/deserialization cost
โ Convert before comparing โ Local time โ UTC for filters & sorting
โ Preserve timezone info โ During serialization/deserialization
โ Use reliable libraries โ For conversion & DST handling
โ Test edge cases โ DST shifts, leap years, timezone borders
โ Document assumptions โ For team & stakeholders
โ Stay disciplined โ Especially when developing locally & deploying remotely
โ Stay updated โ Timezones are political & constantly changing (IANA DB ๐ )
๐ก Final Thought:
Handling timezones isnโt a minor detail โ itโs the backbone of reliable global applications.
Ignore it, and you risk confusing users, corrupting data, and introducing subtle bugs.