Dates and date arithmetic
Problem¶
- How to extract calendar parts?
- How to compare dates?
- How to add days?
- How to compute day differences?
Notions: Dates and date arithmetic
SQL and Pandas syntax¶
- SQLite commonly stores dates as text.
- PostgreSQL has native date and timestamp types.
SELECT
DATE(created_at) AS day,
STRFTIME('%Y-%m', created_at) AS month,
DATE(created_at, '+1 day') AS next_day,
JULIANDAY(end_at) - JULIANDAY(start_at) AS days_diff
FROM t
WHERE DATE(created_at) BETWEEN DATE('2024-01-01') AND DATE('2024-01-31');
-- PostgreSQL
SELECT
created_at::date AS day,
TO_CHAR(created_at, 'YYYY-MM') AS month,
created_at::date + INTERVAL '1 day' AS next_day,
end_at::date - start_at::date AS days_diff
FROM t
WHERE created_at::date BETWEEN DATE '2024-01-01' AND DATE '2024-01-31';
df["created_at"] = pd.to_datetime(df["created_at"])
df["start_at"] = pd.to_datetime(df["start_at"])
df["end_at"] = pd.to_datetime(df["end_at"])
out = df.loc[
df["created_at"].between("2024-01-01", "2024-01-31")
].copy()
out["day"] = out["created_at"].dt.date
out["month"] = out["created_at"].dt.strftime("%Y-%m")
out["next_day"] = out["created_at"] + pd.Timedelta(days=1)
out["days_diff"] = (out["end_at"] - out["start_at"]).dt.days
Example¶
import sqlite3
import pandas as pd
## SQL
con = sqlite3.connect(":memory:")
con.executescript("""
CREATE TABLE events (
id INTEGER,
created_at TEXT,
start_at TEXT,
end_at TEXT
);
INSERT INTO events VALUES
(1, '2024-01-05', '2024-01-05', '2024-01-08'),
(2, '2024-01-20', '2024-01-20', '2024-01-21'),
(3, '2024-02-01', '2024-02-01', '2024-02-04');
""")
sql = """
-- Derive date fields and keep only January 2024 events.
SELECT
id,
DATE(created_at) AS day,
STRFTIME('%Y-%m', created_at) AS month,
DATE(created_at, '+1 day') AS next_day,
CAST(JULIANDAY(end_at) - JULIANDAY(start_at) AS INTEGER) AS days_diff
FROM events
WHERE DATE(created_at) BETWEEN DATE('2024-01-01') AND DATE('2024-01-31')
ORDER BY id;
"""
pd.read_sql_query(sql, con)
# id day month next_day days_diff
# 0 1 2024-01-05 2024-01 2024-01-06 3
# 1 2 2024-01-20 2024-01 2024-01-21 1
## Pandas
events = pd.DataFrame({
"id": [1, 2, 3],
"created_at": ["2024-01-05", "2024-01-20", "2024-02-01"],
"start_at": ["2024-01-05", "2024-01-20", "2024-02-01"],
"end_at": ["2024-01-08", "2024-01-21", "2024-02-04"]
})
events.dtypes
# id int64
# created_at str
# start_at str
# end_at str
# dtype: object
for col in ["created_at", "start_at", "end_at"]:
events[col] = pd.to_datetime(events[col])
# events.dtypes
# id int64
# created_at datetime64[us]
# start_at datetime64[us]
# end_at datetime64[us]
# dtype: object
out = events.loc[
events["created_at"].between("2024-01-01", "2024-01-31")
].copy()
out["day"] = out["created_at"].dt.date
out["month"] = out["created_at"].dt.strftime("%Y-%m")
out["next_day"] = (out["created_at"] + pd.Timedelta(days=1)).dt.date
out["days_diff"] = (out["end_at"] - out["start_at"]).dt.days
out[["id", "day", "month", "next_day", "days_diff"]]
# id day month next_day days_diff
# 0 1 2024-01-05 2024-01 2024-01-06 3
# 1 2 2024-01-20 2024-01 2024-01-21 1
out[["id", "day", "month", "next_day", "days_diff"]].dtypes
# id int64
# day object
# month str
# next_day object
# days_diff int64
# dtype: object
Extra¶
How does sqlite handle/store date and timestamp? What data type they use?
SQLite does not have dedicated DATE or TIMESTAMP storage classes.
- SQLite uses dynamic typing.
- Dates and times are usually stored in one of these formats:
TEXT- ISO-8601 strings like:
'2026-07-04 15:30:00'
- ISO-8601 strings like:
INTEGER- Unix time, seconds since 1970-01-01 UTC:
1751643000
- Unix time, seconds since 1970-01-01 UTC:
REAL- Julian day number:
2460496.14583
- Julian day number:
SQLite storage classes are:
NULLINTEGERREALTEXTBLOB
So for date/timestamp, SQLite typically uses:
TEXTfor readable timestampsINTEGERfor Unix epoch timestampsREALfor Julian dates
You can declare columns as DATE or DATETIME, but SQLite treats them as type affinities, not true date/time types.