{
  "source_file": "0930",
  "source_platform": "Hashnode",
  "author": "Jaival Suthar",
  "title_listed": "Dual Storage for Time: Designing Timezone-Safe Systems at Scale",
  "keywords": "",
  "domain": "大模型算法",
  "content_type": "深度技术解析",
  "is_paid_flag": "否",
  "url": "https://jaivalsuthar.hashnode.dev/dual-storage-for-time-designing-timezone-safe-systems-at-scale",
  "publish_date": "2026-01-15",
  "corpus_stage": "",
  "notes": "",
  "id": "0300dab472b3",
  "collected_at": "2026-10-02T14:12:16",
  "title": "Designing Timezone-Safe Systems Using Dual Time Storage",
  "body_markdown": "Dual Storage for Time: Designing Timezone-Safe Systems at Scale\nPublished\nJanuary 15, 2026\n•\n14\nmin read\n•\nView as Markdown\nJ\nJaival Suthar\nI write technical articles that analyze real world engineering problems through the lens of production systems.\nMy work focuses on architectural tradeoffs, UI layer system design, performance optimization, and reliability patterns derived from shipping and maintaining scalable applications.\nNote:\nThis article was originally published on Medium and is republished here for wider access and long-term reference.\nHow a seemingly simple feature uncovered the true complexity of global time, and why even industry giants struggle to get it right.\nThe Deceptively Simple Requirement\n“Users should be able to schedule events across time zones.”\nFour months ago, I thought this was straightforward. We’re building a platform where users in New York and Mumbai collaborate daily. They need to schedule sessions, and everyone should see the right time. Standard stuff, right?\nWrong. This feature became a masterclass in distributed systems design, edge case handling, and why time is perhaps the hardest problem in software engineering that nobody talks about.\nThe Wake-Up Call: When Filters Break Reality\nWe were building a filtering system for scheduled events. Simple feature: users filter by date range, status, participant. Should have taken a day.\nInstead, we discovered our entire time handling was broken.\nThe symptoms:\nFilter for “January 19” returns events from January 18 and 20\nEvent shows “9:00 PM” in the UI, but 9 PM\nwhere\n? New York? Mumbai? UTC?\nBackend returns\n2026-01-19T22:00:00Z\n, frontend displays it differently for each user\nThe filter wasn’t working because we had no consistent answer to:\n“What does this timestamp represent?”\nThis wasn’t a bug to fix. It was a fundamental architectural gap that would have corrupted data at scale if we shipped without addressing it.\nThe False Start: Why We Couldn’t Ship\nHere’s what made this an urgent architectural decision rather than a “tech debt to fix later”:\nWithout timezone handling:\nEvery event scheduled across timezones would be ambiguous\nUsers editing events would accidentally shift times by hours\nAny data already created would need manual correction\nDST transitions would silently break recurring events\nThe business impact of shipping broken:\nUsers manually converting timezones (failure-prone, frustrating)\nSupport burden for “wrong time” confusion (unsustainable)\nData integrity issues requiring bulk updates (high-risk migration)\nLost credibility with early users (can’t afford as a new feature)\nThe tradeoff I faced:\nDelay shipping by 2 weeks to build timezone handling correctly, or ship fast and inherit months of data cleanup and support tickets.\nI chose the delay. Here’s why that was the right architectural call.\nThe Research Phase: Learning from the Giants\nBefore implementing anything, I studied how companies that have to get this right approach the problem. This wasn’t about copying; it was about understanding the decision space.\nGoogle Calendar’s Approach\nGoogle stores events using\ndual representation\n:\n{\n  \"start\": {\n    \"dateTime\": \"2026-01-19T22:00:00-05:00\",\n    \"timeZone\": \"America/New_York\"\n  }\n}\nWhy both? Because they solve two different problems. An RFC 3339 timestamp with an offset captures the exact moment in history, while the timezone captures the intent: “this should happen at 10 PM New York time, even if DST rules change.”\nThis design decision prevents a subtle but critical bug: if DST rules change retroactively (Brazil did this in 2019), events shift with the intent, not stay fixed to historical offsets.\nKey insight:\nStoring offset alone loses scheduling intent. Storing timezone alone loses the absolute moment. You need both.\nStripe’s Webhook Pattern\nStripe deals with global payments across timezones:\n{\n  \"created\": 1737158400,\n  \"scheduled_for\": 1737244800,\n  \"timezone\": \"America/New_York\"\n}\nAll business logic runs on Unix timestamps (UTC)\n. The timezone is metadata for display only.\nThis works for Stripe because payment deadlines are absolute moments. 11:59 PM UTC is a hard cutoff, regardless of where the user is.\nKey insight:\nWhen the business logic needs absolute time (sorting, comparisons, deadlines), Unix timestamps eliminate ambiguity.\nMicrosoft Outlook’s Hybrid Model\nOutlook does something clever for recurring events:\n{\n  \"start\": {\n    \"dateTime\": \"2026-01-19T22:00:00\",\n    \"timeZone\": \"Eastern Standard Time\"\n  }\n}\nNo offset.\nThe\ndateTime\nis local to the specified timezone, and conversion happens at read time.\nThis prevents the “shifting recurring events” problem where a weekly 9 AM meeting suddenly becomes 10 AM after DST transitions.\nKey insight:\nFor recurring events, preserving local time intent matters more than fixing to an absolute moment.\nThe Pattern: Why All Three Approaches Work\nDespite different implementations, all three share a fundamental principle:\nStore both the moment (when in absolute time) and the context (how humans think about it).\nYou need both because:\nComputers care about moments:\nSorting, duration calculations, “is this event in the past?”\nHumans care about context:\n“I meant 9 AM New York time, not 9 AM UTC”\nThe systems that fail are the ones that try to pick one and derive the other. That’s a lossy conversion.\nThe Architectural Decision: Our Solution\nGiven our use case, scheduling sessions where users need to edit events and understand “when” from their perspective, I designed this contract:\nRequest (Creating an Event)\n{\n  \"scheduledDate\": \"2026-01-19\",\n  \"scheduledTime\": \"22:00\", \n  \"durationMinutes\": 60,\n  \"eventTimezone\": \"America/New_York\"\n}\nThe client provides the\nintended\nlocal time and timezone. This is what the user actually selected: “January 19 at 10 PM Eastern.”\nResponse (Retrieving an Event)\n{\n  \"eventId\": 40,\n  \"startTimeUtc\": \"2026-01-20T03:00:00Z\",\n  \"endTimeUtc\": \"2026-01-20T04:00:00Z\",\n  \"scheduledDateTime\": \"2026-01-19T22:00:00\",\n  \"eventTimezone\": \"America/New_York\",\n  \"durationMinutes\": 60\n}\nThe server returns\nboth representations\n:\nstartTimeUtc\n/\nendTimeUtc\n: The absolute moment (for sorting, filtering, logic)\nscheduledDateTime\n+\neventTimezone\n: The original intent (for editing, display)\nWhy this architecture:\nSingle source of truth for “when”:\nstartTimeUtc\nis unambiguous for all backend operations\nPreserves user intent:\nscheduledDateTime\nin\neventTimezone\nshows what the user actually scheduled\nNo conversion loss:\nEdit → Save → Display round-trips preserve original values\nFilter-friendly:\nQueries on UTC timestamps are straightforward\nAlternative I rejected:\nStoring only UTC and converting to timezone on read.\nWhy I rejected it:\nYou lose the original timezone context. If a user schedules “9 AM New York time” and later edits it, what timezone should the form show? Their current browser timezone? The event’s timezone? Without storing the original, you’re guessing.\nThis causes the exact bug we were trying to prevent: users editing events and accidentally shifting times.\nThe Implementation: What Actually Changed\nWorking with my backend engineer, here’s what we built:\nBackend Storage Strategy\nWe store four critical pieces:\nstart_time_utc\n: The absolute moment (TIMESTAMPTZ in Postgres)\nend_time_utc\n: The absolute end moment\nscheduled_datetime\n: The original local time (TIMESTAMP without timezone)\nevent_timezone\n: IANA timezone identifier (e.g., \"America/New_York\")\nThe\nscheduled_datetime\nhas no timezone attached because it's\nlocal to\nevent_timezone\n. Together, they capture intent.\nWe also store\nduration_minutes\nseparately because DST transitions can make \"1 hour duration\" ambiguous when crossing a DST boundary.\nFrontend Library Choice: Luxon\nI chose Luxon over moment.js or date-fns because:\nFirst-class timezone support via IANA database\nImmutable API prevents accidental mutations\nExplicit about timezone context (forces you to think correctly)\nBetter DST transition handling\nThe critical pattern in our frontend code:\nWhen creating an event:\nconst handleSubmit = async () => {\n  const { date, time, timezone } = formData;\n\n  // Build local datetime in selected timezone\n  const localDT = DateTime.fromISO(\n    `${date}T${time}`, \n    { zone: timezone }\n  );\n\n  // Validate it exists (handles DST gaps)\n  if (!localDT.isValid) {\n    showError(\n      `${time} doesn't exist on ${date} in ${timezone} due to DST`\n    );\n    return;\n  }\n\n  // Send to server (server converts to UTC)\n  await api.createEvent({\n    scheduledDate: date,\n    scheduledTime: time,\n    eventTimezone: timezone,\n    durationMinutes: 60\n  });\n};\nKey decision:\nThe client validates that the time exists in the selected timezone\nbefore\nsending to the server. This catches DST edge cases (like 2:30 AM on March 9, 2026 in New York, which doesn’t exist) at the point of user input, not as a cryptic server error.\nWhen displaying events:\nconst formatEventTime = (\n  event: Event,\n  viewerTimezone: string\n) => {\n  // Parse the UTC timestamp\n  const utcTime = DateTime.fromISO(\n    event.startTimeUtc, \n    { zone: 'utc' }\n  );\n\n  // Convert to viewer's timezone for display\n  const viewerTime = utcTime.setZone(viewerTimezone);\n\n  // Also show original scheduled time for context\n  const eventTime = DateTime.fromISO(\n    event.scheduledDateTime,\n    { zone: event.eventTimezone }\n  );\n\n  return {\n    display: viewerTime.toFormat(\"dd MMM, hh:mm a\"),\n    tooltip: `Scheduled as: ${eventTime.toFormat(\"hh:mm a\")} ${event.eventTimezone}`\n  };\n};\nWe show times in the\nviewer’s\ntimezone by default (for convenience), but include a tooltip showing the original scheduled time (for clarity).\nWhen editing events:\nconst loadEventForEdit = (event: Event) => {\n  // Use scheduledDateTime in eventTimezone\n  // NOT the UTC time!\n  const eventDT = DateTime.fromISO(\n    event.scheduledDateTime,\n    { zone: event.eventTimezone }\n  );\n\n  setFormData({\n    date: eventDT.toJSDate(),\n    hour: eventDT.hour,\n    minute: eventDT.minute,\n    timezone: event.eventTimezone\n  });\n};\nCritical principle:\nEdit forms always show the\nevent’s\ntimezone, not the\nviewer’s\ntimezone.\nWhy this matters:\nIf a Mumbai user edits a “10 PM New York” event, showing it as “8:30 AM next day IST” in the edit form is confusing. They might “fix” it to “8:30 AM today,” which actually shifts the New York time to the previous day. Showing the event’s original timezone prevents this entire class of bugs.\nThe Edge Cases That Define Senior Engineering\nHere’s what separates a working implementation from a robust one:\nEdge Case #1: The Midnight Boundary\nUser input (Mumbai user):\n- Date: January 19\n- Time: 11:00 PM\n- Timezone: America/New_York\nUTC conversion: January 20, 4:00 AM UTC\nThe problem:\nWhat date do you show in a table? If you show “January 19” (original date), it contradicts the UTC timestamp. If you show “January 20” (UTC date), users get confused.\nOur solution:\nShow dates in the\nviewer’s\ntimezone for tables, but preserve the\nevent’s\ntimezone in edit forms. This way:\nNew York users see: “Jan 19, 11:00 PM”\nMumbai users see: “Jan 20, 9:30 AM” (next day, correctly converted)\nEveryone editing sees: “Jan 19, 11:00 PM (America/New_York)” with their local equivalent in a tooltip\nEdge Case #2: DST Transitions Create Non-Existent Times\nOn March 9, 2026, clocks in New York jump from 1:59 AM to 3:00 AM. If someone tries to schedule something for 2:30 AM, Luxon returns\nisValid: false\n.\nOur handling:\nClient-side validation catches this immediately\nShow user-friendly error: “2:30 AM doesn’t exist on March 9 in America/New_York due to Daylight Saving Time”\nSuggest alternative: “Did you mean 3:30 AM?”\nWe also log these occurrences for analysis. If users hit this frequently, we might add UI guardrails during DST transition weekends.\nEdge Case #3: The “Different Day” Warning\nMost insidious UX problem:\nMumbai user schedules:\n- January 19, 11:00 PM in New York\n- This is January 20, 9:30 AM in Mumbai\nIf editing shows \"January 20, 9:30 AM\":\n- User thinks: \"Why is this the next day?\"\n- User \"corrects\" to \"January 19, 9:30 AM\" \n- Now it's January 18, 11:00 PM in New York ❌\nOur solution:\nAlways show times in the\nevent’s\ntimezone when editing, with the viewer’s timezone as reference:\n┌─────────────────────────────────────────┐\n│ Scheduled: 11:00 PM (America/New_York) │\n│ Your timezone: Jan 20, 9:30 AM (IST)   │\n│ ⚠️  Note: Different day in your zone    │\n└─────────────────────────────────────────┘\nThis UI pattern prevents the accidental shift while still giving users context.\nThe Tradeoffs: What This Cost\nDevelopment time:\n2 weeks additional implementation + 1 week testing\nAlternative (ship without timezone handling): 2 days to ship, months of support burden\nCode complexity:\n~400 additional lines of timezone handling logic\nBut prevents an entire class of bugs across the application\nTesting surface:\nDST transitions, midnight boundaries, timezone picker UX\nCreated automated test suite with 40+ edge cases\nProgrammatically validated DST transitions for 2026–2030\nRisk of shipping broken data:\nIf we’d shipped without this, early users would have scheduled events in ambiguous timezones\nFixing retroactively would require contacting users to confirm intent\nHigh risk of corrupting data at scale\nThe decision:\nBetter to delay shipping 2 weeks than inherit months of data cleanup, support tickets, and lost user trust.\nThe Scale Consideration: What Breaks at 10x\nOur current approach works for our scale (hundreds of events per day). Here’s what would need to change at 10x or 100x:\nStorage overhead:\nDual timestamps add ~16 bytes per event\nAt 100K events/day: 1.6MB/day additional storage (negligible)\nAt 10M events/day: 160MB/day (still acceptable on modern databases)\nQuery performance:\nFiltering by\nstart_time_utc\nis indexed and fast\nIf we needed to filter by “all events at 9 AM in any timezone,” we’d need additional indexes on\nscheduled_datetime\nData migration risk:\nIf we’d shipped without timezone handling, then tried to add it later:\nExisting events have no timezone context\nRetroactive conversion requires guessing user intent (impossible to do correctly)\nWould need to contact every user for confirmation\nThis is why handling it correctly upfront was critical: the cost of fixing it later grows exponentially with data volume.\nMeasuring Success: The Outcomes\nBefore implementation:\nFilters returned incorrect results 40% of the time for cross-timezone events\nNo way to know what “9 PM” meant in the UI\nEdit → Save → Display flow would shift times unpredictably\nAfter implementation:\nZero timezone-related bugs in testing (validated programmatically)\n100% accuracy on DST transition edge cases\nEdit → Save → Display round-trips preserve original intent\nUser impact:\nUsers no longer manually convert timezones (eliminated cognitive load)\nCan confidently schedule across New York ↔ Mumbai without confusion\nClear UI showing both event time and “your time” builds trust\nTeam velocity impact:\nPrevented months of support tickets for “wrong time” issues\nAvoided high-risk data migration to fix broken timezone data\nCreated reusable patterns for future timezone-dependent features\nIf we’d shipped without this:\nEstimated 15-20 support tickets/month for timezone confusion\nData corruption requiring manual user outreach for clarification\nLoss of credibility with early adopters (can’t afford for a new feature)\nThe 2-week delay saved us months of support burden and protected data integrity from day one.\nThe Organizational Impact: Beyond This Feature\nThis wasn’t just about fixing one feature. It established patterns the team now reuses:\nInternal documentation created:\n“Timezone Handling Guide” for future features\nTest suite template for DST edge cases\nAPI design checklist for time-dependent endpoints\nDecisions this informed:\nHow we handle recurring events (next feature on roadmap)\nWebhook timestamp formats (adopted UTC + timezone pattern)\nUser settings for default timezone preference\nKnowledge transfer:\nWalked the team through the architecture decision in design review\nShared research on Google/Stripe/Outlook patterns\nNow referenced when designing other time-dependent features\nThe multiplier effect:\nthis decision cost two weeks, but it prevents similar bugs across 5+ future features that touch time. That’s organizational leverage, making the next ten decisions easier, not just solving one problem.\nThe Broader Lesson: Data Model IS Architecture\nThis problem taught me something fundamental about distributed systems:\nMost timezone bugs aren’t coding errors. They’re modeling errors,\nand the code just exposes the flawed model.\nBefore we fixed the model:\n❌ Single timestamp (loses either moment or intent)\n❌ Ambiguous “date” field (which timezone?)\n❌ Client does all conversion (inconsistent across platforms)\nAfter:\n✅ Separate moment (UTC) and context (local + timezone)\n✅ Server is source of truth for conversion\n✅ Client responsible for display preferences only\nThis pattern applies beyond timezones:\nAnywhere you have data that exists in multiple “perspectives” (currencies, units, locales), store both the canonical form and the user’s intent.\nWhat I’d Do Differently\nWith hindsight:\nStart with edge cases:\nI should have built the DST transition test cases\nbefore\nthe happy path. We discovered the “non-existent time” edge case late in testing. Building tests first would have caught it in design.\nMore explicit naming:\nscheduledDateTime\nis better than generic naming because it signals \"this is local time, not UTC.\" But we initially used\neventDate\nwhich was ambiguous. Clear naming prevents misuse.\nTimezone validation service:\nWe ended up with timezone validation logic in both frontend and backend. Should have created a shared validation library from the start to ensure consistency.\nDocument the “why” alongside the “what”:\nOur API docs explain the fields but don’t explain why we chose this pattern over alternatives. Future engineers won’t understand the tradeoffs we considered.\nThe Checklist: Non-Negotiable Requirements\nIf you’re implementing timezone-aware scheduling:\n[ ] Store both UTC timestamp and original local time + timezone\n[ ] Use IANA timezone identifiers (not abbreviations like “EST”)\n[ ] Validate times during DST transitions\n[ ] Test with timezones that cross midnight boundaries\n[ ] Show “different day” warnings in UI when relevant\n[ ] Edit forms display in\nevent’s\ntimezone with viewer context\n[ ] Document which system (client/server) owns conversion\n[ ] Have a rollback plan if timezone logic breaks\nThe one I’d add after this experience:\nBuild automated tests for DST transitions 3–5 years out. Timezone rules change, and your tests should catch that before users do.\nConclusion: Architecture Over Implementation\nWe thought we were building a scheduling feature. We actually built a distributed time coordination system.\nThe difference matters:\nA\nfeature\nis about implementation (write code that works)\nA\nsystem\nis about architecture (design contracts that can’t be misused)\nTimezones exposed this distinction because they’re fundamentally about distributed state:\nMultiple systems (client, API, database) need shared understanding\nMultiple perspectives (event time, viewer time, UTC) exist simultaneously\nMultiple failure modes (DST, midnight boundaries, data migration) lurk at scale\nDon’t optimize for the code you write today. Optimize for the code someone else maintains in 2 years when timezones rules change, DST policies shift, and your assumptions no longer hold.\nThat’s what separates good systems from great ones: not clever code, but thoughtful architecture that degrades gracefully and makes the right thing easy.\nThis article reflects real architectural decisions made during active development. We chose Luxon for timezone handling; production systems should always rely on established libraries rather than custom timezone logic. The principles remain universal.\n#\ntimezones\n#\nsystem-design\n#\nsoftware-architecture\n#\ndistributed-systems\n#\nfrontendarchitecture\n#\nscalable-systems\n#\ndata-modeling\n#\nbackendarchitecture",
  "metadata": {
    "title": "Designing Timezone-Safe Systems Using Dual Time Storage",
    "description": "A deep dive into designing timezone-safe systems using dual time storage. Learn how to preserve user intent while enabling reliable UTC-based logic at scale",
    "keywords": null,
    "author": null,
    "og:title": "Designing Timezone-Safe Systems Using Dual Time Storage",
    "og:description": "A deep dive into designing timezone-safe systems using dual time storage. Learn how to preserve user intent while enabling reliable UTC-based logic at scale",
    "og:url": "https://medium.com/@jaivalsuthar/dual-storage-for-time-designing-timezone-safe-systems-at-scale-e5f76a825169",
    "og:site_name": "Jaival Suthar | Engineering Portfolio",
    "og:image": "https://cdn.hashnode.com/res/hashnode/image/upload/v1769147232099/b80c0d78-458b-4de0-bf04-72fa562e1627.png",
    "og:image:width": "1200",
    "og:image:height": "630",
    "og:type": "article",
    "twitter:card": "summary_large_image",
    "twitter:creator": "https://x.com/Jaival_Suthar",
    "twitter:title": "Designing Timezone-Safe Systems Using Dual Time Storage",
    "twitter:description": "A deep dive into designing timezone-safe systems using dual time storage. Learn how to preserve user intent while enabling reliable UTC-based logic at scale",
    "twitter:image": "https://cdn.hashnode.com/res/hashnode/image/upload/v1769147232099/b80c0d78-458b-4de0-bf04-72fa562e1627.png",
    "article:published_time": "2026-01-15T18:30:00.000Z",
    "article:author": "https://jaivalsuthar.hashnode.dev/@JaivalSuthar"
  },
  "paywall": {
    "listed_paid": false,
    "detected": false,
    "marker": "",
    "public_only": false,
    "policy": "付费/会员内容只保留页面公开可见部分，不绕过付费墙"
  },
  "crawl": {
    "success": true,
    "status_code": 200,
    "error": ""
  },
  "code_blocks": [
    {
      "file": "attachments/0300dab472b3/code/body-000.txt",
      "chars": 101,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-001.txt",
      "chars": 93,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-002.txt",
      "chars": 100,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-003.txt",
      "chars": 129,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-004.txt",
      "chars": 212,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-005.txt",
      "chars": 575,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-006.txt",
      "chars": 606,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-007.txt",
      "chars": 358,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-008.txt",
      "chars": 91,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-009.txt",
      "chars": 40,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-010.txt",
      "chars": 98,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-011.txt",
      "chars": 173,
      "language": "text"
    },
    {
      "file": "attachments/0300dab472b3/code/body-012.txt",
      "chars": 218,
      "language": "text"
    }
  ],
  "images": [
    {
      "status": "ok",
      "url": "https://cdn.hashnode.com/res/hashnode/image/upload/v1769147232099/b80c0d78-458b-4de0-bf04-72fa562e1627.png",
      "bytes": 1265305,
      "reused": true,
      "local_path": "attachments/0300dab472b3/images/000.png",
      "src": "https://cdn.hashnode.com/res/hashnode/image/upload/v1769147232099/b80c0d78-458b-4de0-bf04-72fa562e1627.png",
      "alt": "Dual Storage for Time: Designing Timezone-Safe Systems at Scale",
      "downloaded": true
    }
  ],
  "audio": [],
  "videos": [],
  "links": [
    {
      "href": "https://jaivalsuthar.hashnode.dev/dual-storage-for-time-designing-timezone-safe-systems-at-scale.md",
      "label": "View as Markdown",
      "type": "a"
    },
    {
      "href": "https://hashnode.com/@JaivalSuthar",
      "label": "J",
      "type": "a"
    },
    {
      "href": "https://x.com/Jaival_Suthar",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://www.linkedin.com/in/jaival-suthar-57195b257/",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://jaivalsuthar.hashnode.dev/tag/timezones",
      "label": "# timezones",
      "type": "a"
    },
    {
      "href": "https://jaivalsuthar.hashnode.dev/tag/system-design",
      "label": "# system-design",
      "type": "a"
    },
    {
      "href": "https://jaivalsuthar.hashnode.dev/tag/software-architecture",
      "label": "# software-architecture",
      "type": "a"
    },
    {
      "href": "https://jaivalsuthar.hashnode.dev/tag/distributed-systems",
      "label": "# distributed-systems",
      "type": "a"
    },
    {
      "href": "https://jaivalsuthar.hashnode.dev/tag/frontendarchitecture",
      "label": "# frontendarchitecture",
      "type": "a"
    },
    {
      "href": "https://jaivalsuthar.hashnode.dev/tag/scalable-systems",
      "label": "# scalable-systems",
      "type": "a"
    },
    {
      "href": "https://jaivalsuthar.hashnode.dev/tag/data-modeling",
      "label": "# data-modeling",
      "type": "a"
    },
    {
      "href": "https://jaivalsuthar.hashnode.dev/tag/backendarchitecture",
      "label": "# backendarchitecture",
      "type": "a"
    }
  ],
  "retry_at": "2026-10-03T08:10:51",
  "repair_version": 2,
  "repaired_at": "2026-10-14T10:51:05Z",
  "source_url": "https://jaivalsuthar.hashnode.dev/dual-storage-for-time-designing-timezone-safe-systems-at-scale",
  "papers": [],
  "actual_video_files": [],
  "body_chars": 20026,
  "expected_body_images": 1,
  "discovery_status": "ok",
  "delivery_status": "ok",
  "missing_reason": "",
  "raw_html": "attachments/0300dab472b3/pages/source.html",
  "local_html": "attachments/0300dab472b3/pages/article.html",
  "body_base_path": "attachments/0300dab472b3/pages/",
  "body_markdown_path": "attachments/0300dab472b3/pages/article.md"
}