Class CalendarMath
Stateless utility for converting between a millisecond tick count and a GameDate in a custom CalendarDefinition. All operations are sign-aware so backward-running clocks (negative ticks) produce dates before the calendar's epoch with consistent arithmetic.
Inherited Members
Namespace: Scylla.Core.Time
Assembly: ScyllaCore.dll
Syntax
public static class CalendarMath
Remarks
Tick semantics. One tick equals one millisecond. The total elapsed time
in milliseconds is the long passed to TickToDate(long, CalendarDefinition); tick 0
corresponds to year EpochYearOffset, month 0,
day 1, hour 0, minute 0, second 0, millisecond 0.
Algorithm. Sub-day components (millisecond / second / minute / hour) are resolved by sequential integer division and sign-aware modulo. The absolute day count is then converted to year, month, and day via a closed-form O(1) year estimate (using the calendar's average days-per-year and a leap-year count formula) followed by a small bounded forward/backward walk (typically 0-1 iterations) to handle leap-year edge cases. The same closed-form approach is used by DateToTick(GameDate, CalendarDefinition) when accumulating days to the year start.
Leap years. Each year's day count is queried from the calendar's GetDaysInYear(int), which incorporates LeapYearRule automatically. Per-month day counts likewise route through GetDaysInMonth(int, int).
Hot-path note. For tick-based consumers such as Clock.ScyllaClock, cache the previously computed date and only re-invoke when the underlying tick value actually crosses a boundary; the per-clock date cache in Clock.ScyllaClock halves the number of conversions per frame during normal advancement.
Methods
DateToTick(GameDate, CalendarDefinition)
Converts a GameDate back to an absolute millisecond tick count.
Inverse of TickToDate(long, CalendarDefinition); the supplied date's
CalendarHash must match the calendar's
Unity instance ID, or be the default zero hash (used by dates constructed without
a calendar session context, e.g., from the ClockDefinition initial
date fields).
Declaration
public static long DateToTick(GameDate date, CalendarDefinition calendar)
Parameters
| Type | Name | Description |
|---|---|---|
| GameDate | date | The date to encode. Month is zero-based; Day is 1-based. Fields outside the calendar's valid ranges are clamped internally by the accumulation logic. |
| CalendarDefinition | calendar | The calendar to use for day-count lookups. Must be non-null, have at least one month, and all four time-unit fields must be at least 1. |
Returns
| Type | Description |
|---|---|
| long | The absolute millisecond tick count corresponding to |
Exceptions
| Type | Condition |
|---|---|
| ArgumentNullException | Thrown when |
| ArgumentException | Thrown when |
ResolveEraIndex(int, CalendarDefinition)
Returns the zero-based index of the first EraDefinition in
calendar whose [StartYear, EndYear] range contains
displayYear (inclusive on both ends), or
INDEX_NONE if no era matches.
Declaration
public static int ResolveEraIndex(int displayYear, CalendarDefinition calendar)
Parameters
| Type | Name | Description |
|---|---|---|
| int | displayYear | The display year to test (i.e., the calendar year after applying the epoch offset). Negative values represent years before the epoch. |
| CalendarDefinition | calendar | The calendar whose era list to search. |
Returns
| Type | Description |
|---|---|
| int | Zero-based index of the first matching era, or INDEX_NONE when
no era's range contains |
Remarks
A future implementation will consult ConditionProvider before falling back to year-range matching. The provider field is reserved but not yet consumed; today the resolver is purely year-range based.
ResolveSeasonIndex(int, CalendarDefinition)
Returns the season index for the supplied monthIndex, ignoring
each season's StartDayOffsetWithinFirstMonth.
For day-of-month-aware resolution that honors astronomical season starts (e.g.,
Spring beginning on March 20) prefer
ResolveSeasonIndex(int, int, CalendarDefinition).
Declaration
public static int ResolveSeasonIndex(int monthIndex, CalendarDefinition calendar)
Parameters
| Type | Name | Description |
|---|---|---|
| int | monthIndex | |
| CalendarDefinition | calendar |
Returns
| Type | Description |
|---|---|
| int |
ResolveSeasonIndex(int, int, CalendarDefinition)
Returns the season index for the given (monthIndex,
dayOfMonth) date, honoring each season's
StartDayOffsetWithinFirstMonth. When the date falls
before a season's configured start within its first month, the previous season (in
calendar order, wrapping around year boundaries) is returned instead.
Declaration
public static int ResolveSeasonIndex(int monthIndex, int dayOfMonth, CalendarDefinition calendar)
Parameters
| Type | Name | Description |
|---|---|---|
| int | monthIndex | Zero-based month index. |
| int | dayOfMonth | One-based day-of-month (matching Day). |
| CalendarDefinition | calendar | Calendar describing the seasons and months. Must be non-null. |
Returns
| Type | Description |
|---|---|
| int |
ResolveWeekdayIndex(long, CalendarDefinition)
Returns the zero-based weekday index for the given absoluteDay using
absoluteDay mod weekdayCount arithmetic. Returns INDEX_NONE
when the calendar has no weekday list or is null.
Declaration
public static int ResolveWeekdayIndex(long absoluteDay, CalendarDefinition calendar)
Parameters
| Type | Name | Description |
|---|---|---|
| long | absoluteDay | The absolute day count from the calendar's epoch (day 0 = tick 0). Negative values are handled via sign-aware modulo so backward-running clocks produce correct weekday cycles. |
| CalendarDefinition | calendar | The calendar whose weekday list to cycle through. |
Returns
| Type | Description |
|---|---|
| int | A value in |
TickToDate(long, CalendarDefinition)
Converts an absolute millisecond tick count to a fully-resolved GameDate in the supplied calendar. Sign-aware: negative ticks produce dates before the calendar's epoch with the same field semantics as positive ticks.
Declaration
public static GameDate TickToDate(long tickMilliseconds, CalendarDefinition calendar)
Parameters
| Type | Name | Description |
|---|---|---|
| long | tickMilliseconds | Absolute clock tick value in milliseconds. Tick 0 corresponds to year EpochYearOffset, month 0, day 1, 00:00:00.000. Negative values move the date before the epoch. |
| CalendarDefinition | calendar | The calendar to resolve against. Must be non-null and contain at least one MonthDefinition entry. |
Returns
| Type | Description |
|---|---|
| GameDate | A GameDate with all fields populated, including resolved WeekdayIndex, SeasonIndex, and EraIndex (or INDEX_NONE when the respective list is empty or no entry matches). CalendarHash is set to the calendar's session instance ID. |
Remarks
Sub-day components are resolved by sequential integer division with sign-aware modulo so the within-day remainder is always non-negative. The absolute day count is then converted to year/month/day via ResolveYearMonthDay(long, CalendarDefinition, out int, out int, out int), which uses a closed-form O(1) year estimate and a short bounded walk to handle leap-year edge cases.
For hot-path use (e.g., the per-clock boundary detection in Clock.ScyllaClock), consumers should cache the result and only re-invoke this method when the tick value crosses a boundary of interest.
Exceptions
| Type | Condition |
|---|---|
| ArgumentNullException | Thrown when |
| ArgumentException | Thrown when |