Time as Intervals: How Decipad's Date System Mimics Human Thinking

Pedro Teixeira

Astronaut plays with time

One of my favorite features in Decipad is our date system. It’s not just another date implementation - it’s a fundamental rethinking of how we represent time in programming languages. We’ve designed it to work the way humans actually think about time: as intervals, not as precise moments.

The Problem with Traditional Date Systems

Most programming languages treat dates as precise moments in time - a specific instant on the timeline. But that’s not how humans naturally think about dates. When you say “2023”, you’re not thinking about January 1st at 00:00:00.000 UTC. You’re thinking about the entire year of 2023 - a span of time that includes all 365 (or 366) days.

Similarly, when you say “March 2024”, you’re not referring to a specific moment. You’re talking about the entire month - all 31 days from March 1st to March 31st. Even “March 15th, 2024” represents the entire day, not a specific second.

Traditional date systems force us to make arbitrary decisions about precision. Should “2023” be represented as January 1st at midnight? What timezone? What about “March” - should that be March 1st at 00:00:00? These decisions don’t reflect how we actually use dates in real-world scenarios.

Enter Granularity: Time as Intervals

In Decipad, we solve this by introducing the concept of granularity. Every date has a granularity that defines what kind of time interval it represents:

  • Year: date(2023) represents the entire year 2023
  • Month: date(2023-03) represents the entire month of March 2023
  • Day: date(2023-03-15) represents the entire day of March 15th, 2023
  • Hour: date(2023-03-15 14) represents the hour from 14:00 to 14:59
  • Minute: date(2023-03-15 14:30) represents the minute from 14:30:00 to 14:30:59
  • Second: date(2023-03-15 14:30:45) represents the second from 14:30:45.000 to 14:30:45.999

This granularity is baked into the type system. When you create a date, Decipad automatically infers the appropriate granularity based on the format you provide:

Year = date(2023)           // granularity: year
Month = date(2023-03)       // granularity: month
Day = date(2023-03-15)      // granularity: day
Time = date(2023-03-15 14:30) // granularity: minute

The Magic of Contains

This interval-based approach enables one of my favorite features: the contains operator. You can ask whether one time interval contains another, which is incredibly intuitive:

Year = date(2023)
Month = date(2023-03)
Day = date(2023-03-15)
Minute = date(2023-03-15 14:30)

Year contains Month    // true - 2023 contains March 2023
Month contains Day     // true - March 2023 contains March 15th
Day contains Minute    // true - March 15th contains 14:30
Minute contains Day    // false - a minute doesn't contain a day

This is exactly how humans think about time! When you say “I’ll finish this project in March”, you’re not committing to a specific day or time - you’re saying it will happen somewhere within that month-long interval.

Date Arithmetic That Makes Sense

The granularity system also makes date arithmetic much more intuitive. When you add or subtract time intervals, the result maintains the appropriate granularity:

Start = date(2021-01-01)  // granularity: day
End = Start + 1 year + 6 months + 5 days
// Result: 2022-07-06 (granularity: day)

Year2020 = date(2020)     // granularity: year
Year2023 = date(2023)     // granularity: year
Difference = Year2023 - Year2020
// Result: 3 years (not 3.0 years - it's a whole number of years)

Notice how the arithmetic respects the granularity. When you subtract two years, you get a whole number of years, not a fractional result. This matches human intuition - we don’t think in terms of “3.0 years” when talking about the difference between 2020 and 2023.

Time Intervals: The Other Half of the Story

Complementing our date system, we also have time intervals - durations that represent spans of time. These are what you get when you subtract two dates:

Start = date(2020-02-23)
End = date(2020-01-12)
Duration = End - Start
// Result: 42 days

// You can convert time intervals to different units
Duration as hours
// Result: 1008 hours

Duration as minutes
// Result: 60480 minutes

Time intervals are first-class citizens in Decipad. They have their own type system and can be converted between different units just like any other quantity. This makes it easy to work with durations in whatever unit makes sense for your use case.

Real-World Examples

Let me show you some practical examples of how this system works in practice:

Financial Planning

// Quarterly planning
Q1 = date(2026Q1)  // first quarter of 2024
Q2 = date(2026Q2)  // second quarter ot 2024
Q3 = date(2026Q3)  // third quarter of 2024
Q4 = date(2026Q4)  // fourth quarter of 2024

// Calculate the duration of each quarter
QuarterDuration = Q2 - Q1  // 3 months

// Check if a specific date falls within a quarter
Q1 contains date(2024-02-15)  // true
Q1 contains date(2024-04-01)  // false

Project Management

ProjectStart = date(2024 - 01 - 15);
ProjectEnd = date(2024 - 06 - 30);
ProjectDuration = ProjectEnd - ProjectStart; // 167 days

// Check if today is within the project timeline
Today = date(2024 - 03 - 20);
ProjectStart <= Today <= ProjectEnd; // true

// Calculate remaining time
RemainingDays = ProjectEnd - Today; // 102 days

Data Analysis

// Monthly sales data
SalesData = {
  Month = [date(2024-01), date(2024-02), date(2024-03)],
  Revenue = [100000, 120000, 110000]
}

// Calculate month-over-month growth
Growth = (SalesData.Revenue[1] - SalesData.Revenue[0]) / SalesData.Revenue[0]
// Result: 20% growth from January to February

// Find the month with highest revenue
MaxRevenue = max(SalesData.Revenue)  // 120000
MaxMonth = filter(SalesData, SalesData.Revenue == MaxRevenue).Month  // February 2024

The Technical Implementation

Under the hood, our date system is built on several key abstractions:

Granularity Types

We define granularity as a union type that captures all possible time intervals:

export type DateGranularity =
  | "millisecond"
  | "second"
  | "minute"
  | "hour"
  | "day"
  | "month"
  | "quarter"
  | "year";

Date Parsing with Granularity Inference

Our date parser automatically infers the appropriate granularity based on the input format:

it.each([
  ["2020", { kind: "date", date: "year" }, "2020-01-01T00:00Z"],
  ["2020-10", { kind: "date", date: "month" }, "2020-10-01T00:00Z"],
  ["2020-10-13", { kind: "date", date: "day" }, "2020-10-13T00:00Z"],
  ["2020-10-13 10:30", { kind: "date", date: "minute" }, "2020-10-13T10:30Z"],
])("%s is a good %s", (format, type, result) => {
  const d = parseDate(format, type.date as DateGranularity);
  expect(d).toBeDefined();
  expect(d?.date).toEqual(BigInt(new Date(result).getTime()));
});

Arithmetic Operations

Date arithmetic respects granularity throughout the computation:

// When subtracting dates, we maintain the granularity of the result
expect(await runCode(`date(2020) - date(2010)`)).toMatchObject({
  type: {
    type: "number",
    unit: U("year", { known: true }),
  },
  value: N(10),
});

// Adding time quantities to dates preserves the date's granularity
expect(await runCode(`1 year + date(2020)`)).toMatchObject({
  type: {
    date: "year",
  },
  value: 1609459200000n,
});

The Contains Operator

The contains operator is implemented by checking if one interval completely encompasses another:

// A higher granularity (larger interval) can contain a lower granularity (smaller interval)
Day = date(2022-06-30)
Minute = date(2022-06-30 11:59)

Day contains Minute  // true - the day contains that specific minute

Why This Matters

This approach to dates solves several fundamental problems:

1. Intuitive Semantics

The system behaves exactly as humans expect. When you say “March 2024”, you mean the entire month, not a specific moment. Our system reflects this natural thinking.

2. Type Safety

The granularity is part of the type system, which means the compiler can catch errors like trying to add a year to a minute-level date when that doesn’t make sense.

3. Flexible Arithmetic

Date arithmetic works naturally with different granularities. You can add months to years, days to months, etc., and the system handles the conversions appropriately.

4. Efficient Storage

Since dates represent intervals rather than precise moments, we can store them more efficiently. A year-level date doesn’t need to store timezone information or precise time components.

Looking Forward

This date system is just one example of how we’re rethinking fundamental programming concepts in Decipad. By aligning our abstractions with how humans naturally think about problems, we can create systems that are both more powerful and more intuitive.

The granularity concept could extend to other domains as well. We could imagine similar interval-based systems for:

  • Geographic regions: Countries containing states containing cities
  • Organizational hierarchies: Companies containing departments containing teams
  • Data structures: Tables containing columns containing cells

The key insight is that humans think in terms of containment and hierarchy, not just precise equality. By building systems that reflect this natural thinking, we can create tools that feel more natural and intuitive to use.

In the end, this is what makes Decipad special - we’re not just building another programming language or spreadsheet tool. We’re building a system that thinks the way humans do, starting with something as fundamental as how we represent time.


Pedro Teixeira is the CTO of Decipad, where he leads the technical vision for making data analysis accessible to everyone. When he’s not designing intuitive date systems, you can find him exploring the intersection of programming languages and human cognition.

Building with AI agents? Helpmaton gives you workspaces, agent memory, budget controls, and webhooks—without the lock-in. It’s source-available so you can self-host when you need to. Quick integrations for Gmail, Notion, Slack, Discord, and others.

Try Helpmaton

RELATED ARTICLES

Hi, I'm Pedro Teixeira, a software engineer passionate about AI, web development, and building tools that make developers' lives easier.