Dates and daily games
The current date Expression returns information about the current date and time. Combined with the set random seed response and daily leaderboards, it's the foundation for building daily challenges, seasonal content, and time-aware games.
Current date expression
Format
Controls what date information is returned:
| Format | Returns |
|---|---|
| days since Castle epoch | A day number that increments by 1 each day. Useful for daily challenges, computing day differences, or as a leaderboard scope. This is the default. |
| year | The current year (e.g. 2026). |
| month | The current month as a number (1–12). |
| day | The current day of the month (1–31). |
| timestamp | A Unix timestamp (seconds since January 1, 1970). Useful for precise time calculations. |
Timezone
Controls which timezone is used to determine the date:
| Timezone | Behavior |
|---|---|
| player | Uses the player's local timezone. This is the default. |
| Castle | Uses Castle's server timezone. All players around the world share the same day boundary. Use this for daily challenges so that everyone gets the same challenge on the same day. |
In multiplayer sessions, Castle timezone is always used regardless of this setting, so that all players in the same session agree on the date.
Daily challenge pattern
A daily challenge is a game that changes each day but is the same for every player on a given day. This lets players compete on a level playing field and compare scores on a daily leaderboard. Here's how to set one up:
1. Seed the randomness to today's date
Use the set random seed response with the current date expression (format: "days since Castle epoch", timezone: Castle). This ensures that every random expression in your rules produces the same sequence of values for all players on the same day — but a different sequence tomorrow.
When this card begins:
Set the random number seed to [current date (days since Castle epoch, Castle timezone)]
Any random expressions evaluated after this point (random number in a range, Gaussian, choose, etc.) will produce the same results for every player on the same day.
The random seed only affects random expressions in rules. If you're using Lua scripting, you also need to call math.randomseed() with the same day number to seed Lua's math.random():
local date = castle.getServerDate("*t", "Castle")
math.randomseed(date.daysSinceCastleEpoch)
2. Use a daily leaderboard
Set the leaderboard scope to daily with Castle timezone. This way the leaderboard resets at the same time for everyone, matching the challenge reset.
When this receives a message "game over":
Save variable $score to the leaderboard (scope: daily, timezone: Castle)
Show the leaderboard for $score (sort: high, label: "High Scores")
The leaderboard UI will automatically show "Daily High Scores" when using daily scope.
3. Use Castle timezone consistently
Make sure both the random seed and the leaderboard use Castle timezone. If you mix timezones, a player could end up playing yesterday's challenge but posting to today's leaderboard (or vice versa).
Other date-based patterns
Seasonal content
Use the month format to change your deck based on the time of year:
When this card begins:
If [current date (month)] equals 12:
Set property Drawing: art frame to 2 -- winter art
Weekly leaderboards
Use a custom leaderboard scope with the day number divided by 7:
Save variable $score to the leaderboard (scope: custom, value: floor(current date / 7))
Time-limited events
Use the timestamp format to compare against a specific Unix timestamp and gate content before or after a deadline.
Scripting
Dates are also accessible from Lua scripts:
-- Get the current date as a table
local date = castle.getServerDate("*t", "Castle")
print(date.year, date.month, date.day)
print("Day number: " .. date.daysSinceCastleEpoch)
-- Seed both rule randomness and Lua randomness to today's date
castle.setRandomSeed(date.daysSinceCastleEpoch)
math.randomseed(date.daysSinceCastleEpoch)
-- Pick a daily level (cycles through 10 levels)
local dailyLevel = (date.daysSinceCastleEpoch % 10) + 1