Skip to the content.
← Back to Timezone Handling Back to JavaScript Development

Timezone Input Controller

Location: app/assets/js/controllers/timezone-input-controller.js
Framework: Stimulus.js
Dependencies: KMP_Timezone utility
Related: KMP_Timezone API Reference

Overview

The Timezone Input Controller automatically handles timezone conversion for datetime-local HTML form inputs. It simplifies the workflow of converting UTC values from the server to the user’s local timezone for display and editing, then converting back to UTC before form submission.

Key responsibility: Bridge between server-side UTC storage and client-side user timezone display/input.

Features

Installation & Setup

Controller Registration

The controller is automatically registered in app/assets/js/index.js:

// All Stimulus controllers are registered automatically
for (var controller in window.Controllers) {
    Stimulus.register(controller, window.Controllers[controller]);
}

No Additional Setup Required

Simply use the controller in your HTML forms with the appropriate data attributes.

Basic Usage

Simplest Example

<form data-controller="timezone-input">
    <div class="mb-3">
        <label for="start_date" class="form-label">Start Date/Time</label>
        <input type="datetime-local" 
               id="start_date"
               name="start_date"
               data-timezone-input-target="datetimeInput"
               data-utc-value="2025-03-15T14:30:00Z"
               class="form-control">
    </div>
    <button type="submit" class="btn btn-primary">Save</button>
</form>

What happens:

  1. On page load: UTC value 2025-03-15T14:30:00Z is converted to user’s local time (e.g., 2025-03-15T09:30 for Chicago)
  2. User edits the time locally
  3. On form submit: Local time is converted back to UTC for storage

With Timezone Notice

Show the user which timezone is being used:

<form data-controller="timezone-input">
    <div class="mb-3">
        <label for="start_date" class="form-label">Start Date/Time</label>
        <input type="datetime-local" 
               id="start_date"
               name="start_date"
               data-timezone-input-target="datetimeInput"
               data-utc-value="2025-03-15T14:30:00Z"
               class="form-control">
        <small data-timezone-input-target="notice" class="text-muted d-block mt-2"></small>
    </div>
</form>

Output: <i class="bi bi-clock"></i> Times shown in America/Chicago (CDT)

With Custom Timezone

Override the detected timezone:

<form data-controller="timezone-input" 
      data-timezone-input-timezone-value="America/New_York">
    <input type="datetime-local" 
           name="start_date"
           data-timezone-input-target="datetimeInput"
           data-utc-value="2025-03-15T14:30:00Z"
           class="form-control">
</form>

Use cases:

Disabling Timezone Notice

<form data-controller="timezone-input" 
      data-timezone-input-show-notice-value="false">
    <input type="datetime-local" 
           name="start_date"
           data-timezone-input-target="datetimeInput"
           data-utc-value="2025-03-15T14:30:00Z"
           class="form-control">
</form>

Stimulus Targets

datetimeInput (required)

The datetime-local input elements to convert.

Attributes required:

Example:

<input type="datetime-local" 
       name="event_start"
       data-timezone-input-target="datetimeInput"
       data-utc-value="2025-03-15T14:30:00Z">

notice (optional)

Elements to display timezone information to the user.

Features:

Example:

<small data-timezone-input-target="notice" class="text-muted"></small>

Auto-populated content:

<i class="bi bi-clock"></i> Times shown in America/Chicago (CDT)

Stimulus Values

timezone (optional)

Override the detected timezone with a specific IANA timezone identifier.

Type: String
Default: Browser-detected timezone
Example: America/Chicago, America/New_York, UTC

Usage:

<form data-controller="timezone-input" 
      data-timezone-input-timezone-value="America/New_York">

showNotice (optional)

Control whether timezone notice elements are populated.

Type: Boolean
Default: true
Values: true or false

Usage:

<!-- Show notice (default) -->
<form data-controller="timezone-input" 
      data-timezone-input-show-notice-value="true">

<!-- Hide notice -->
<form data-controller="timezone-input" 
      data-timezone-input-show-notice-value="false">

Lifecycle Methods

connect() - Controller Initialization

Called when the form element connects to the DOM.

What it does:

  1. Detects or retrieves configured timezone
  2. Converts all UTC input values to local time
  3. Populates timezone notice if enabled
  4. Sets up submit and reset event listeners

Key features:

convertUtcToLocal() - Convert on Page Load

Processes all datetime inputs and converts UTC values to local time.

What it does:

  1. Finds all inputs with data-utc-value attribute
  2. Converts each UTC value to local time for the configured timezone
  3. Sets input value to the converted local time
  4. Stores original and converted values in data attributes for reference

Data attributes set:

updateNotice() - Display Timezone Info

Updates all notice target elements with current timezone information.

Output format:

<i class="bi bi-clock"></i> Times shown in {TIMEZONE} ({ABBR})

Example:

<i class="bi bi-clock"></i> Times shown in America/Chicago (CDT)

handleSubmit() - Convert Before Submission

Called on form submission to convert local times back to UTC.

What it does:

  1. Iterates through all datetime inputs
  2. Converts local time to UTC for each input
  3. Creates hidden input fields with UTC values
  4. Disables original inputs to prevent duplicate submission
  5. Appends hidden inputs to form

Result: Server receives UTC values in hidden inputs

handleReset() - Restore on Form Reset

Called when form is reset (via reset button or JavaScript).

What it does:

  1. Removes any hidden UTC input fields created during submission
  2. Re-enables original datetime inputs
  3. Restores local time values from stored data
  4. Uses setTimeout to ensure DOM is ready before restoring values

Public Methods

updateTimezone(newTimezone)

Manually update the timezone being used for conversion.

Parameters:

What it does:

  1. Updates controller’s timezone setting
  2. Re-converts all input values with the new timezone
  3. Updates notice if enabled

Example:

// Get controller instance
const form = document.querySelector('[data-controller="timezone-input"]');
const controller = form._stimulus_module.element;

// Update to different timezone
controller.updateTimezone('America/New_York');

getTimezone()

Get the current timezone being used.

Returns: IANA timezone identifier string

Example:

const timezone = controller.getTimezone();
console.log(timezone); // "America/Chicago"

disconnect() - Cleanup

Called when the controller disconnects from the DOM.

What it does:

  1. Removes submit event listener
  2. Removes reset event listener
  3. Clears cached event handler references
  4. Prevents memory leaks

Complete Example

Multi-Field Form with Timezone Control

<form id="eventForm" data-controller="timezone-input">
    <fieldset>
        <legend>Event Details</legend>
        
        <!-- Event Start Time -->
        <div class="mb-3">
            <label for="start_date" class="form-label">Event Start</label>
            <input type="datetime-local" 
                   id="start_date"
                   name="start_date"
                   data-timezone-input-target="datetimeInput"
                   data-utc-value="2025-03-15T14:30:00Z"
                   class="form-control"
                   required>
        </div>

        <!-- Event End Time -->
        <div class="mb-3">
            <label for="end_date" class="form-label">Event End</label>
            <input type="datetime-local" 
                   id="end_date"
                   name="end_date"
                   data-timezone-input-target="datetimeInput"
                   data-utc-value="2025-03-15T16:30:00Z"
                   class="form-control"
                   required>
        </div>

        <!-- Timezone Notice -->
        <div class="alert alert-info" role="alert">
            <small data-timezone-input-target="notice"></small>
        </div>
    </fieldset>

    <div class="button-group">
        <button type="submit" class="btn btn-primary">Save Event</button>
        <button type="reset" class="btn btn-secondary">Clear</button>
    </div>
</form>

Behavior:

  1. Both datetime inputs display in user’s local timezone
  2. User edits times as needed
  3. Notice shows current timezone
  4. On submit: Both values sent as UTC to server
  5. On reset: Both values restored to original local times

Form Data Flow

Submission Flow

User Input (Local Time)
           ↓
datetime-local input contains: 2025-03-15T09:30
           ↓
Form submission triggered
           ↓
handleSubmit() converts to UTC
           ↓
Hidden inputs created: 2025-03-15T14:30:00.000Z
           ↓
Original inputs disabled
           ↓
Hidden inputs included in form data
           ↓
Server receives: name_of_input=2025-03-15T14:30:00.000Z

Reset Flow

Form reset triggered
           ↓
handleReset() removes hidden inputs
           ↓
Original datetime inputs re-enabled
           ↓
Values restored from data-local-value
           ↓
Form state returns to pre-submission local times

Integration with KMP_Timezone

The controller uses the global KMP_Timezone utility for all timezone operations:

Methods used:

See: KMP_Timezone API Reference for complete API documentation.

Common Patterns

Pattern 1: Simple Date/Time Input

<form data-controller="timezone-input">
    <input type="datetime-local" 
           name="appointment"
           data-timezone-input-target="datetimeInput"
           data-utc-value="2025-03-15T14:00:00Z">
</form>

Pattern 2: Event with Location Timezone

<form data-controller="timezone-input" 
      data-timezone-input-timezone-value="<?= h($event->timezone) ?>">
    <input type="datetime-local" 
           name="start_time"
           data-timezone-input-target="datetimeInput"
           data-utc-value="<?= h($event->start_time->toIso8601String()) ?>">
    <small data-timezone-input-target="notice" class="text-muted"></small>
</form>

Pattern 3: Date Range

<form data-controller="timezone-input">
    <div class="row">
        <div class="col-md-6">
            <label>From:</label>
            <input type="datetime-local" 
                   name="date_from"
                   data-timezone-input-target="datetimeInput"
                   data-utc-value="2025-03-15T00:00:00Z">
        </div>
        <div class="col-md-6">
            <label>To:</label>
            <input type="datetime-local" 
                   name="date_to"
                   data-timezone-input-target="datetimeInput"
                   data-utc-value="2025-03-15T23:59:59Z">
        </div>
    </div>
    <small data-timezone-input-target="notice" class="text-muted d-block mt-2"></small>
</form>

Troubleshooting

Issue: Times showing as UTC instead of local timezone

Cause: Controller not initialized or data-controller="timezone-input" missing

Solution:

Issue: Timezone notice not appearing

Cause: Missing or incorrect notice target

Solution:

Issue: Form not converting times to UTC on submit

Cause: Missing or incorrect datetime input targets

Solution:

Issue: Custom timezone not being used

Cause: Invalid timezone identifier or typo in data attribute

Solution:

Performance Considerations

Browser Compatibility

The controller relies on:

Fallback: For older browsers, the input will display as text, but timezone conversion will still work.

See Also

← Back to Timezone Handling Back to JavaScript Development