What You’ll Learn in This Module
Dates appear in nearly every Cast narration — renewal dates, contract start dates, last login dates, QBR dates, benchmark periods. In this module, you’ll learn how to format dates for display, work with the current date, and perform date arithmetic to calculate time differences like “days until renewal” or “months since onboarding.”
How Dates Work in Liquid
Dates in Liquid are not a separate data type — they’re strings that the date filter knows how to interpret. When you apply the date filter, Liquid parses the string into a date, then reformats it according to the pattern you specify.
Excel analogy: This is like using
=TEXT(A1, "MMMM DD, YYYY")to change how a date cell is displayed. The underlying date value doesn’t change — you’re just choosing a different way to show it.
Why it matters in Cast
Date fields from CRMs typically arrive in formats like "2026-01-15" or "2026-01-15T09:00:00Z". These are accurate but not customer-friendly. The date filter lets you transform them into natural, readable formats like “January 15, 2026” for display in narrations and on slides.
The date Filter — Formatting Dates for Display
Liquid syntax
{{ some_date | date: "FORMAT_STRING" }}
The format string uses special codes that start with % to represent different parts of a date:
| Code | Meaning | Example |
|---|---|---|
%B | Full month name | January |
%b | Abbreviated month name | Jan |
%m | Month number (01–12) | 01 |
%d | Day of month (01–31) | 15 |
%e | Day of month (1–31, no leading zero) | 5 |
%Y | 4-digit year | 2026 |
%y | 2-digit year | 26 |
%A | Full weekday name | Thursday |
%a | Abbreviated weekday name | Thu |
%H | Hour in 24-hour format (00–23) | 14 |
%I | Hour in 12-hour format (01–12) | 02 |
%M | Minutes (00–59) | 30 |
%S | Seconds (00–59) | 00 |
%p | AM/PM | PM |
%s | Unix timestamp (seconds since 1970-01-01) | 1737000000 |
%w | Day of week (0=Sunday, 6=Saturday) | 4 |
Any text in the format string that is not a % code is included literally — so commas, spaces, slashes, and words like “of” pass through unchanged.
Common format patterns
{{ renewal_date | date: "%B %d, %Y" }} → January 15, 2026
{{ renewal_date | date: "%b %d, %Y" }} → Jan 15, 2026
{{ renewal_date | date: "%m/%d/%Y" }} → 01/15/2026
{{ renewal_date | date: "%Y-%m-%d" }} → 2026-01-15
{{ renewal_date | date: "%B %Y" }} → January 2026
{{ renewal_date | date: "%A, %B %d" }} → Thursday, January 15
{{ renewal_date | date: "%b %e, %Y" }} → Jan 5, 2026 (no leading zero on day)
Real Cast example
{%- assign renewal = renewal_date | default: "" -%}
{% if renewal != "" %}
Your contract renews on {{ renewal | date: "%B %d, %Y" }}.
{% else %}
We don't have a renewal date on file.
{% endif %}
If renewal_date is "2026-09-15": Output: Your contract renews on September 15, 2026.
Common mistakes
❌ Mixing up %m (month number) and %M (minutes):
{{ renewal_date | date: "%B %d, %Y at %m:%S" }}
%m gives you the month number (like 09), not the minutes. Use %M for minutes.
âś… Use %M for minutes, %m for month:
{{ renewal_date | date: "%B %d, %Y at %H:%M" }} → September 15, 2026 at 14:30
❌ Forgetting quotes around the format string:
{{ renewal_date | date: %B %d, %Y }}
âś… Always quote the format string:
{{ renewal_date | date: "%B %d, %Y" }}
❌ Applying date to an empty or nil field without a guard:
{{ renewal_date | date: "%B %d, %Y" }}
If renewal_date is nil, this may produce unexpected output or error in strict mode.
âś… Guard with a blank check or default:
{%- assign renewal = renewal_date | default: "" -%}
{% unless renewal == "" %}
Renews on {{ renewal | date: "%B %d, %Y" }}.
{% endunless %}
Working with the Current Date — "now" and "today"
Liquid recognizes two special input values for the date filter:
"now"— the current date and time"today"— the current date (equivalent to"now"in most implementations)
{{ "now" | date: "%B %d, %Y" }} → March 23, 2026
{{ "today" | date: "%Y-%m-%d" }} → 2026-03-23
{{ "now" | date: "%A" }} → Monday
Real Cast example — benchmark date reference
{%- assign benchmarkMMYYYY = "now" | date: "%B %Y" -%}
Here are your metrics for the {{ benchmarkMMYYYY }} benchmark.
Output: Here are your metrics for the March 2026 benchmark.
Real Cast example — dynamic copyright or timestamp
Data as of {{ "now" | date: "%B %d, %Y" }}.
Output: Data as of March 23, 2026.
Unix Timestamps — The Key to Date Math
What is it?
A Unix timestamp is the number of seconds that have elapsed since January 1, 1970. It’s a single number (like 1711152000) that represents a specific moment in time. Unix timestamps are how Liquid performs date arithmetic — because once dates are numbers, you can subtract them, add to them, and divide the result to get days, hours, or months.
Excel analogy: Excel stores dates as numbers internally (days since January 1, 1900). When you subtract two dates, you get a number of days. Unix timestamps work the same way, but in seconds instead of days.
Why it matters in Cast
Liquid doesn’t have built-in “date difference” or “days between” functions. To calculate time differences — days until renewal, months since contract start, duration of a support ticket — you convert both dates to Unix timestamps, subtract, and then convert the difference in seconds to the unit you need.
Liquid syntax
Convert any date to a Unix timestamp:
{{ "2026-01-15" | date: "%s" }} → 1736899200 (or similar)
{{ "now" | date: "%s" }} → current Unix timestamp
Convert seconds to useful units:
| Seconds | Equals |
|---|---|
| 60 | 1 minute |
| 3,600 | 1 hour |
| 86,400 | 1 day |
| 604,800 | 1 week |
| 2,592,000 | ~1 month (30 days) |
| 31,536,000 | ~1 year (365 days) |
Date Math — Calculating Days Until Renewal
Here’s the most common date arithmetic pattern in Cast:
{%- assign renewal_ts = renewal_date | date: "%s" | plus: 0 -%}
{%- assign now_ts = "now" | date: "%s" | plus: 0 -%}
{%- assign diff_seconds = renewal_ts | minus: now_ts -%}
{%- assign days_until = diff_seconds | divided_by: 86400 -%}
{% if days_until > 0 %}
Your renewal is in {{ days_until }} days.
{% elsif days_until == 0 %}
Your renewal is today!
{% else %}
Your renewal was {{ days_until | abs }} days ago.
{% endif %}
Let’s trace through this step by step:
renewal_date | date: "%s"— converts the renewal date to a Unix timestamp (a number in seconds)"now" | date: "%s"— gets the current moment as a Unix timestamprenewal_ts | minus: now_ts— subtracts to get the difference in secondsdiff_seconds | divided_by: 86400— divides by 86,400 (seconds per day) to get days
If renewal_date is "2026-06-15" and today is March 23, 2026:
- The difference is about 84 days
- Output:
Your renewal is in 84 days.
If the renewal date is in the past:
days_untilis negative- We use
| absto make it positive for the “X days ago” message
⚠️ Important note on | plus: 0
The date: "%s" filter returns a string (e.g., "1736899200"). You must convert it to a number with | plus: 0 before doing arithmetic. Without this step, minus would operate on strings.
Date Math — Calculating Months and Years
For longer time spans, divide by the appropriate number of seconds:
{%- assign start_ts = contract_start_date | date: "%s" | plus: 0 -%}
{%- assign now_ts = "now" | date: "%s" | plus: 0 -%}
{%- assign diff = now_ts | minus: start_ts -%}
{%- assign days = diff | divided_by: 86400 -%}
{%- assign months = days | divided_by: 30 -%}
{%- assign years = days | divided_by: 365 -%}
{% if years >= 1 %}
You've been a customer for over {{ years }} year{% if years > 1 %}s{% endif %}.
{% elsif months >= 1 %}
You've been a customer for {{ months }} month{% if months > 1 %}s{% endif %}.
{% else %}
You've been a customer for {{ days }} day{% if days != 1 %}s{% endif %}.
{% endif %}
đź’ˇ These are approximate calculations (30 days per month, 365 days per year). For a more precise and polished version, see the CustomerSince snippet in Module 17.
Invalid Date Handling
Not all CRM date fields contain valid dates. A field might be empty, contain garbage text, or have a default value that looks like a date but isn’t meaningful.
The date: "%s" filter on an invalid input may produce the value -2208988800 (which represents the date December 30, 1899 — a common default for blank dates in some systems). The CustomerSince snippet checks for this:
{%- assign dateStart = contract_start_date | date: '%s' -%}
{% if dateStart != '-2208988800' and dateStart != '' and dateStart != null %}
{%- # Date is valid — proceed with calculations -%}
{% else %}
{%- assign timeFrame = 'Invalid Date Value' -%}
{% endif %}
đź’ˇ Best practice: Always validate date fields before performing date math. Check for blank, nil, and the -2208988800 sentinel value.
Complete Date Format Reference
For easy reference, here are all the formats you’re likely to use in Cast narrations:
| Format String | Output | When to Use |
|---|---|---|
"%B %d, %Y" | January 15, 2026 | Formal narration text |
"%b %d, %Y" | Jan 15, 2026 | Shorter version for slides |
"%m/%d/%Y" | 01/15/2026 | US-standard date format |
"%d/%m/%Y" | 15/01/2026 | International date format |
"%Y-%m-%d" | 2026-01-15 | ISO format (sorting, data) |
"%B %Y" | January 2026 | Month-year only (benchmarks) |
"%A, %B %d" | Thursday, January 15 | Day of week included |
"%b %e, %Y" | Jan 5, 2026 | No leading zero on day |
"%s" | 1736899200 | Unix timestamp (for math) |
"%w" | 4 | Day of week number (for logic) |
Try It Yourself — Module 7 Capstone Exercise
Exercise: You have two fields: qbr_date (value: "2026-05-10") and you want to display:
- The QBR date formatted as “May 10, 2026”
- How many days from today (March 23, 2026) until the QBR
- A message: “Your next QBR is in X days — that’s about Y weeks away.”
Click to reveal the answer
```liquid {%- assign qbr = qbr_date | default: "" -%} {% unless qbr == "" %} {%- assign qbr_ts = qbr | date: "%s" | plus: 0 -%} {%- assign now_ts = "now" | date: "%s" | plus: 0 -%} {%- assign diff = qbr_ts | minus: now_ts -%} {%- assign days_until = diff | divided_by: 86400 -%} {%- assign weeks_until = days_until | divided_by: 7 -%} Your next QBR is on {{ qbr | date: "%B %e, %Y" }}. That's in {{ days_until }} days — about {{ weeks_until }} weeks away. {% else %} No QBR date on file. {% endunless %} ``` Output: `Your next QBR is on May 10, 2026. That's in 48 days — about 6 weeks away.` Key details: - `date: "%s" | plus: 0` converts both dates to numeric timestamps - Subtracting gives seconds, dividing by 86400 gives days - Dividing days by 7 gives weeks (integer division rounds down) - The blank check prevents errors if no date is on fileWhat’s Next
You now know how to format, compare, and calculate with dates. In Module 8, you’ll learn about cast_titlecase — Cast’s custom filter for intelligently normalizing company names from CRM data.
đź“– Official documentation:
- Standard Filters: https://school.cast.app/liquid/liquid-filters.html
- Snippet Library (CustomerSince, DateDifference): https://school.cast.app/liquid/liquid-library.html