Skip to content

Date & Time System Variables — Implementation Plan

Summary

Add built-in system variables for date and time that are always available in the flow variable system. These enable time-sensitive content (greetings, weekend offers, campaign deadlines) and date-based conditions without any SetVariable setup.

Proposed Variables

VariableExample outputDescription
{date}22.02.2026Current date, localized
{time}14:30Current time (HH:mm), user's timezone
{day}SaturdayWeekday name, localized
{day.number}6Day of week (1=Monday, 7=Sunday)
{hour}14Current hour (0–23), user's timezone
{month}FebruaryMonth name, localized
{month.number}2Month number (1–12)
{year}2026Four-digit year

Format suffixes (future/optional)

Could support {date:DD/MM/YYYY}, {time:HH:mm:ss} etc. via a colon syntax. Not MVP — the defaults above cover most use cases.

Use Cases

  1. Greetings: "Good {greeting}, welcome!" where {greeting} = morning/afternoon/evening based on {hour}
    • Or simpler: condition on {hour} → show different text operators
  2. Weekend content: "When day.number >= 6" → show weekend offer
  3. Campaign deadline: "Offer valid until March 1st — only {daysLeft} days remaining!"
    • {daysLeft} would require computed variables (future feature), but {date} and conditions get us partway
  4. Opening hours: "When hour >= 9" AND "When hour < 17" → show "We're open now!"
  5. Calendar booking: Show time-relevant availability text

Architecture

Timezone: Client-Side Resolution

The CE runs inside the user's browser, so Date and Intl APIs already use the correct local timezone. No server coordination needed.

// In CE — resolving date/time variables
const now = new Date()
const locale = navigator.language || 'en'

const dateVars = {
  'date':         now.toLocaleDateString(locale),
  'time':         now.toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit' }),
  'day':          now.toLocaleDateString(locale, { weekday: 'long' }),
  'day.number':   String(now.getDay() === 0 ? 7 : now.getDay()), // 1=Mon, 7=Sun
  'hour':         String(now.getHours()),
  'month':        now.toLocaleDateString(locale, { month: 'long' }),
  'month.number': String(now.getMonth() + 1),
  'year':         String(now.getFullYear()),
}

CE Changes

1. src/services/dataStore.ts — Inject date variables

Date/time variables should be resolved fresh on each substitution (not stored once at init), since a user might have the creative open across midnight or for extended periods.

Option A: Lazy getter in flowVariables that computes on access. Option B: Resolve in substituteVariables() directly before checking flowVariables.

Recommendation: Option B — keeps flowVariables clean (only user-set state) and avoids reactive overhead.

2. src/utils/content/richText.ts (or wherever substituteVariables lives)

Before looking up flowVariables[varName], check if varName is a date/time key and resolve it inline:

typescript
function resolveDateVariable(name: string): string | undefined {
  const now = new Date()
  const locale = navigator.language || 'en'
  switch (name) {
    case 'date':         return now.toLocaleDateString(locale)
    case 'time':         return now.toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit' })
    case 'day':          return now.toLocaleDateString(locale, { weekday: 'long' })
    case 'day.number':   return String(now.getDay() === 0 ? 7 : now.getDay())
    case 'hour':         return String(now.getHours())
    case 'month':        return now.toLocaleDateString(locale, { month: 'long' })
    case 'month.number': return String(now.getMonth() + 1)
    case 'year':         return String(now.getFullYear())
    default:             return undefined
  }
}

3. src/utils/evaluateCondition.ts

No changes needed — the condition evaluator already receives the resolved variable value. Date variables flow through the same substituteVariablesevaluateCondition pipeline.

Exception: {day} returns a localized string ("Lørdag" in Norwegian). For conditions like When day = Saturday, the user would need to type the localized name. This is fine for MVP — document it. Future: could add a day picker in the condition UI.

Composer Changes

None. Date variables are CE-only (resolved at runtime). No data flows through the JSON/composer.

Frontend Changes

1. VariableSuggestions.vue

Add date/time variables to the availableVariables computed, in a "Date & Time" group:

typescript
// After system vars (answer, answer.position):
vars.push(
  { name: 'date', description: "Today's date" },
  { name: 'time', description: 'Current time' },
  { name: 'day', description: 'Day of the week' },
  { name: 'hour', description: 'Current hour (0–23)' },
)

Keep it minimal — don't show all 8 variables. date, time, day, hour cover the common cases. Advanced users can type month, year etc. manually.

2. ConditionFields.vue

Add the same variables to availableVariables for the datalist.

For {day} conditions: could add a datalist of localized weekday names as suggested values (like we do for answer choices). Nice-to-have.

For {hour} conditions: no special suggestions needed — user types a number.

MVP Scope

  1. CE: resolveDateVariable() function + integrate into substitution pipeline
  2. CE: Freeze date variables at step creation (same as {answer} freeze in Text.vue)
  3. Frontend: Add date, time, day, hour to VariableSuggestions + ConditionFields
  4. Test: {time} in a text operator shows current time, condition on {hour} works

Out of Scope (future)

  • Format suffixes ({date:DD/MM})
  • {greeting} computed variable (morning/afternoon/evening)
  • Date arithmetic ({daysUntil:2026-03-01})
  • Server-side date resolution (for analytics/server-rendered contexts)
  • Day picker UI in condition fields
  • Countdown timer variable ({countdown:2026-03-01T00:00})

Interaction with Existing Features

  • Variable substitution: Date vars go through the same {varName} → value pipeline
  • Conditions: Work with existing evaluateCondition — numeric comparison for hour/day.number, string comparison for day
  • Text.vue freeze: Date variables get frozen at render time (same as {answer}), so a message saying "Sent at {time}" keeps its original time
  • SetVariable: Users could technically SetVariable date = {date} to snapshot a date — works automatically since substitution happens before storage

Internal documentation