- users.time_zone (0034). An account without one takes the browser's zone on its first page (POST /account/time-zone/adopt, never over a choice made by hand); the session follows the account on every request. - /account: who you are and the zone every page writes its times in, reached from your name in the sidebar. - formatting.when: 'Today 06:58', 'Yesterday 23:41', 'Tue 6 Oct 14:12', '6 Oct 2025 14:12', 24-hour, in the reader's zone; |ago's hover is the exact local moment instead of UTC; tz_label() for column headers. - Audit log: When (EDT) with exact times, one detail fact a line, on classes. - tzdata in the image, and the airgapped smoke checks a zone resolves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
23 lines
612 B
Python
23 lines
612 B
Python
"""The zone each user reads times in (milestone 490)
|
|
|
|
Revision ID: 0034_user_time_zone
|
|
Revises: 0033_retire_uptime_widget
|
|
Create Date: 2026-10-08
|
|
"""
|
|
from typing import Sequence, Union
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
revision: str = "0034_user_time_zone"
|
|
down_revision: Union[str, None] = "0033_retire_uptime_widget"
|
|
branch_labels: Union[str, Sequence[str], None] = None
|
|
depends_on: Union[str, Sequence[str], None] = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.add_column("users", sa.Column("time_zone", sa.String(64), nullable=True))
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_column("users", "time_zone")
|