你对日期的理解是错误的——而且你的代码在欺骗你。
You're Wrong About Dates – and Your Code Is Lying to You

原始链接: https://metaduck.com/youre-wrong-about-dates/

大多数日期库错误地将日期表示为时间上的精确时刻——特定的纳秒——而不是人类自然感知的方式(一整天、一个月或一年)。这种“虚假精度”会在代码中引入错误和复杂性。Decipad 提供了一种新的方法:将日期视为具有固有粒度的*区间*。 与其说是精确的时刻,不如说 `date(2023)` 代表整一年,`date(2023-03)` 代表整个三月,依此类推。这使得日期比较(“这个月是否包含那天?”)和计算(一年包含一个月 = true)变得直观。 至关重要的是,两个日期之间的*差异*也被视为一类区间,简化了诸如计算项目持续时间或财务季度之类的任务——以人类友好的单位(如“天”或“月”)返回结果,而无需手动转换。这种基于区间的系统消除了时区难题,降低了代码复杂性,并与我们自然思考时间的方式保持一致,从而提供了一种更强大、更易于理解的解决方案。

相关文章

原文

Every date library you’ve ever used is lying to you.

They all pretend that a date is a precise moment — a frozen point on a timeline.

  • 2023? Must mean January 1st at 00:00:00.000 UTC.
  • March 2024? Clearly March 1st, 00:00 UTC.
  • March 15th, 2024? Sure, March 15th at the stroke of midnight.

But that’s not how humans think. When you say “2023”, you mean the whole year. “March 2024”? The entire month. Even “March 15th” means the full day, not some arbitrary nanosecond.

We’ve been forced into fake precision that doesn’t match reality. And it’s not harmless — it leads to broken logic, messy hacks, and subtle bugs that only show up in production.


The Rebellion: Time as Intervals

In Decipad, a date isn’t a pinpoint — it’s an interval with a built-in granularity.

  • date(2023) = January 1st to December 31st.
  • date(2023-03) = March 1st to March 31st.
  • date(2023-03-15) = midnight to 23:59:59 that day.

Your code instantly understands that a year contains a month, a month contains a day, and an hour contains 60 minutes.

Year = date(2023)
Month = date(2023-03)
Day = date(2023-03-15)

Year contains Month   // true
Month contains Day    // true
Day contains Month    // false

This isn’t just “nicer syntax” — it’s a fundamental shift in how your software thinks.


The Other Half: Time Intervals

If dates are intervals, then the difference between two dates is also an interval. We treat that as a first-class value too.

Start = date(2020-02-23)
End = date(2020-04-05)

Duration = End - Start  // 42 days
Duration as hours       // 1008 hours
Duration as minutes     // 60,480 minutes

This is insanely useful:

  • Project management: ProjectEnd - Today gives you remaining days, instantly.
  • Finance: Q2 - Q1 returns 3 months without you hardcoding days-per-month.
  • Events: A week-long conference? That’s literally a 7 days object — not a magic number in milliseconds.

Why This Changes Everything

Once you start thinking about time as nested intervals, so many things become intuitive:

  • No more picking random timestamps for “March 2024.”
  • Date math that returns human-friendly units instead of weird floats.
  • Containment checks that match real-world logic (“does this quarter include Feb 15th?”).
  • Duration objects that are as natural to work with as integers.

The old way is a leaky abstraction. The new way just matches how your brain already works.


Example: Brutally Simple Project Tracking

Kickoff = date(2024 - 09 - 01);
Deadline = date(2024 - 12 - 15);
Today = date(2024 - 10 - 20);

Kickoff <= Today <= Deadline; // true
Deadline - Today; // 56 days left

No conversions. No timezone headaches. No milliseconds. Just time the way you talk about it.


The truth: your current date system isn’t just awkward — it’s wrong. We fixed it. And if that feels unsettling… maybe it’s time your code grew up.

ScenarioOld Way (Moment-Obsessed)Interval Way (Granularity-Aware)
Represent “2023”new Date('2023-01-01T00:00:00.000Z') — silently assumes January 1st at midnight in UTC.date(2023) — represents entire year Jan 1 to Dec 31.
Represent “March 2024”new Date('2024-03-01T00:00:00.000Z') — arbitrary starting moment, loses context.date(2024-03) — represents whole month March 1 to March 31.
Check if March contains March 15thManually compare timestamps: start <= date && date <= end.date(2024-03) contains date(2024-03-15)true.
Project days remaining(deadline.getTime() - today.getTime()) / (1000*60*60*24) — pray no DST jumps ruin it.date(2024-12-15) - date(2024-10-20)56 days.
Quarter lengthWrite custom month math or hardcode “3 months” — break in leap years.date(2024Q2) - date(2024Q1)3 months.
Subtract yearsnew Date('2023-01-01') - new Date('2020-01-01') → milliseconds you then divide.date(2023) - date(2020)3 years.
Store “day-level” dataStore full timestamp but ignore time part — waste space and invite bugs.Store only what’s needed: granularity: day.
Human meaningNeeds docs to explain what’s implied.Is exactly what it says on the tin.

Key point: The “Old Way” treats everything like an instant and forces you to fake the rest. The “Interval Way” makes human meaning part of the type system.

Full details (and way more examples): 👉 Time as Intervals – Decipad’s Rethink of Dates

联系我们 contact @ memedata.com