--- name: date-time description: Working with dates and times in RSX using Rsx_Time and Rsx_Date classes. Use when formatting dates/times for display, handling user timezones, working with datetime columns, converting between formats, or displaying relative times like "2 hours ago". --- # RSX Date & Time Handling ## Two Classes - Strict Separation | Class | Purpose | Example | |-------|---------| --------| | `Rsx_Time` | Moments in time (with timezone) | `2025-12-24T15:30:00Z` | | `Rsx_Date` | Calendar dates (no timezone) | `2025-12-24` | **Critical**: Functions throw if wrong type passed (datetime to date function or vice versa). This is intentional - mixing types causes bugs. --- ## Strings, Not Objects RSX uses ISO strings, not Carbon objects: - **Dates**: `"2025-12-24"` - **Datetimes**: `"2025-12-24T15:30:00Z"` Same format in PHP, JavaScript, JSON, and database queries. No serialization surprises. ```php $model->created_at // "2025-12-24T15:30:45.123Z" (string) $model->due_date // "2025-12-24" (string) Rsx_Time::now_iso() // "2025-12-24T15:30:45.123Z" (string) ``` Carbon is used internally for calculations, never exposed externally. --- ## Model Casts (Automatic) `Rsx_Model_Abstract` auto-applies casts based on column type: - DATE columns → `Rsx_Date_Cast` - DATETIME columns → `Rsx_DateTime_Cast` **Never define** `$casts` with `'date'`, `'datetime'`, or `'timestamp'` - these use Carbon and are blocked by `rsx:check`. --- ## Rsx_Time - Moments in Time ### PHP Usage ```php use App\RSpade\Core\Time\Rsx_Time; // Current time Rsx_Time::now(); // Carbon (for calculations only) Rsx_Time::now_iso(); // ISO 8601: 2025-12-24T15:30:00Z // Formatting for display Rsx_Time::format_datetime($datetime); // "Dec 24, 2025 3:30 PM" Rsx_Time::format_datetime_with_tz($datetime); // "Dec 24, 2025 3:30 PM CST" Rsx_Time::format_time($datetime); // "3:30 PM" Rsx_Time::relative($datetime); // "2 hours ago" // Database storage (always UTC) Rsx_Time::to_database($datetime); // Converts to MySQL format // Timezone Rsx_Time::get_user_timezone(); // User's timezone or default Rsx_Time::to_user_timezone($datetime); // Convert to user's timezone ``` ### JavaScript Usage ```javascript // Current time (synced with server) Rsx_Time.now(); // Date object Rsx_Time.now_iso(); // ISO string // Formatting Rsx_Time.format_datetime(datetime); // "Dec 24, 2025 3:30 PM" Rsx_Time.format_datetime_with_tz(datetime); // "Dec 24, 2025 3:30 PM CST" Rsx_Time.format_time(datetime); // "3:30 PM" Rsx_Time.relative(datetime); // "2 hours ago", "in 3 days" // Arithmetic Rsx_Time.add(datetime, 3600); // Add seconds, returns ISO string Rsx_Time.subtract(datetime, 3600); // Subtract seconds ``` --- ## Rsx_Date - Calendar Dates ### PHP Usage ```php use App\RSpade\Core\Time\Rsx_Date; // Current date Rsx_Date::today(); // "2025-12-24" (user's timezone) // Formatting Rsx_Date::format($date); // "Dec 24, 2025" // Comparisons Rsx_Date::is_today($date); // Boolean Rsx_Date::is_past($date); // Boolean Rsx_Date::is_future($date); // Boolean Rsx_Date::diff_days($date1, $date2); // Days between ``` ### JavaScript Usage ```javascript // Current date Rsx_Date.today(); // "2025-12-24" // Formatting Rsx_Date.format(date); // "Dec 24, 2025" // Comparisons Rsx_Date.is_today(date); // Boolean Rsx_Date.is_past(date); // Boolean ``` --- ## Live Countdown/Countup (JavaScript) For real-time updating displays: ```javascript // Countdown to future time const ctrl = Rsx_Time.countdown(this.$sid('timer'), deadline, { short: true, // "2h 30m" vs "2 hours and 30 minutes" on_complete: () => this.reload() }); // Stop countdown when leaving page this.on_stop(() => ctrl.stop()); // Countup from past time (elapsed time) Rsx_Time.countup(this.$sid('elapsed'), started_at, { short: true }); ``` --- ## Server Time Sync Client time syncs automatically via `rsxapp` data on page load and AJAX responses. No manual sync required. ```javascript // Client always has accurate server time const server_now = Rsx_Time.now(); // Synced with server, corrects for clock skew ``` --- ## User Timezone Stored in `login_users.timezone` (IANA format, e.g., `America/Chicago`). Falls back to `config('rsx.datetime.default_timezone')`. ```php // Get user's timezone $tz = Rsx_Time::get_user_timezone(); // All Rsx_Time methods automatically use user's timezone for display ``` --- ## Component Expectations ### Date_Picker Component - `val()` returns `"YYYY-MM-DD"` or `null` - `val(value)` accepts `"YYYY-MM-DD"` or `null` - **Throws** if passed datetime format - Display shows localized format (e.g., "Dec 24, 2025") ### Datetime_Picker Component - `val()` returns ISO 8601 string or `null` - `val(value)` accepts ISO 8601 string or `null` - **Throws** if passed date-only format - Display shows localized time in user's timezone --- ## Common Patterns ### Display in Template ```jqhtml <%= Rsx_Time.format_datetime(this.data.record.created_at) %> <%= Rsx_Time.relative(this.data.record.updated_at) %> <%= Rsx_Date.format(this.data.record.due_date) %> ``` ### Conditional Display ```jqhtml <% if (Rsx_Date.is_past(this.data.task.due_date)) { %> Overdue <% } %> ``` ### Save to Database ```php // Datetime - store in UTC $record->scheduled_at = Rsx_Time::to_database($params['scheduled_at']); // Date - store as-is $record->due_date = $params['due_date']; // Already "YYYY-MM-DD" ``` ### Parse User Input ```php // If user enters a datetime string $datetime = Rsx_Time::parse($params['datetime']); // Returns Carbon $iso = Rsx_Time::to_iso($datetime); // Convert back to string // If user enters a date string $date = Rsx_Date::parse($params['date']); // Returns "YYYY-MM-DD" ``` --- ## Key Rules 1. **Never use Carbon directly** - RSX uses string-based dates 2. **Never use PHP's date()** - Use Rsx_Time/Rsx_Date 3. **Store datetimes in UTC** - Use `Rsx_Time::to_database()` 4. **Display in user's timezone** - Automatic via Rsx_Time format methods 5. **Dates have no timezone** - Use Rsx_Date for calendar dates 6. **Wrong types throw** - Date functions reject datetimes and vice versa ## More Information Details: `php artisan rsx:man time`