Custom event calendar LWC displays incorrect times for users in different time zones

Users in different time zones see event times shifted incorrectly in our custom event calendar LWC. An event scheduled for 2:00 PM EST shows as 2:00 PM for PST users instead of 11:00 AM PST.

The component fetches events from Apex and displays them in a weekly calendar view. Here’s how we’re getting the events:

DateTime eventTime = evt.StartDateTime;
String formattedTime = eventTime.format('h:mm a');

We’re passing the formatted time string to the LWC. The calendar component uses this string directly to position events in the timeline. Users can see events but the times are wrong for anyone not in EST. Our global sales team spans 8 time zones and this is causing major scheduling conflicts - people are missing meetings or showing up at wrong times. How should we handle time zone conversion between Apex and LWC?

Your time zone issue requires changes across all three layers: user time zone detection to determine the target zone, Intl.DateTimeFormat usage for client-side formatting, and Apex UTC conversion to provide zone-agnostic timestamps. Here’s the complete solution:

User Time Zone Detection: Salesforce stores each user’s preferred time zone in User.TimeZoneSidKey. Fetch this in your Apex controller and pass it to the LWC so you can explicitly format times in the user’s configured zone rather than relying on browser detection (which may be incorrect for traveling users):

@AuraEnabled(cacheable=true)
public static EventWrapper getEvents() {
  String userTimeZone = UserInfo.getTimeZone().getID();
  List<Event> events = [SELECT Id, Subject, StartDateTime, EndDateTime FROM Event];
  return new EventWrapper(events, userTimeZone);
}

This returns both the events and the user’s IANA time zone identifier (like ‘America/New_York’). The wrapper pattern keeps data organized and allows the LWC to know which time zone to target.

Intl.DateTimeFormat Usage: In your LWC, receive the time zone from Apex and use it with Intl.DateTimeFormat to format times correctly. First, ensure your Apex returns ISO 8601 UTC timestamps (covered in next section). Then format client-side:

formatEventTime(isoString, timeZone) {
  const date = new Date(isoString);
  return new Intl.DateTimeFormat('en-US', {
    hour: 'numeric',
    minute: '2-digit',
    hour12: true,
    timeZone: timeZone
  }).format(date);
}

This produces ‘2:00 PM’ formatted in the user’s Salesforce time zone, not the browser’s zone. For your calendar grid positioning, work with Date objects and calculate positions based on hours-since-midnight in the target time zone:

getHourPosition(isoString, timeZone) {
  const date = new Date(isoString);
  const formatter = new Intl.DateTimeFormat('en-US', {
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
    timeZone: timeZone
  });
  const parts = formatter.formatToParts(date);
  const hour = parseInt(parts.find(p => p.type === 'hour').value);
  const minute = parseInt(parts.find(p => p.type === 'minute').value);
  return hour + (minute / 60);
}

This returns a decimal hour value (14.5 for 2:30 PM) in the user’s time zone, which you can multiply by your pixels-per-hour constant to position events accurately in the calendar grid.

Apex UTC Conversion: Change your Apex to return DateTime values in UTC ISO format, not formatted strings. Never format dates in Apex for display - always send raw UTC timestamps to the client:

public class EventData {
  @AuraEnabled public String eventId;
  @AuraEnabled public String subject;
  @AuraEnabled public String startDateTime;
  @AuraEnabled public String endDateTime;

  public EventData(Event evt) {
    this.eventId = evt.Id;
    this.subject = evt.Subject;
    this.startDateTime = evt.StartDateTime.formatGmt('yyyy-MM-dd\'T\'HH:mm:ss.SSS\'Z\'');
    this.endDateTime = evt.EndDateTime.formatGmt('yyyy-MM-dd\'T\'HH:mm:ss.SSS\'Z\'');
  }
}

The formatGmt() method converts the DateTime to UTC and formats it as ISO 8601 with the ‘Z’ suffix indicating UTC. JavaScript’s Date constructor parses this reliably across all browsers. The .SSS milliseconds ensure precision for event positioning.

For all-day events (where StartDateTime has time 00:00:00), add a flag in your wrapper:

@AuraEnabled public Boolean isAllDay;
this.isAllDay = evt.IsAllDayEvent;

In your LWC, render all-day events in a separate row above the timeline, without time-based positioning.

With these changes, your calendar will correctly display event times for all 8 time zones in your global sales team. An EST event at 2:00 PM will show as 11:00 AM for PST users, 7:00 PM for GMT users, etc. The client-side formatting respects each user’s Salesforce time zone preference, ensuring accurate scheduling across your distributed team.


This draft is based on general Salesforce knowledge. It has not been verified against your specific version and environment. Practitioners: verify the steps and share your experience below.

The problem is you’re formatting the DateTime in Apex using the org’s default time zone, then passing a string to LWC. Strings have no time zone information, so the browser can’t convert them. Instead, pass the raw DateTime value (as ISO string or milliseconds) to LWC and let JavaScript handle formatting based on the user’s browser time zone. Use Intl.DateTimeFormat in your LWC to format times client-side.

Tested this on a multi-region org with users across EST, PST, and GMT, and pulling TimeZoneSidKey via @AuraEnabled then passing it to Intl.DateTimeFormat eliminated all calendar time zone mismatches.

That makes sense. Should I change the Apex to return eventTime.getTime() to get milliseconds? Or is there a better format? Also, how do I use Intl.DateTimeFormat to show times in the user’s local zone? I need to display like ‘2:00 PM’ in the calendar cells.

Return ISO 8601 format from Apex using eventTime.formatGmt(‘yyyy-MM-dd'T'HH:mm:ss'Z'’) - this gives you UTC timestamps that JavaScript can parse reliably. In your LWC, parse it with new Date(isoString) and format with Intl.DateTimeFormat. Example: new Intl.DateTimeFormat(‘en-US’, { hour: ‘numeric’, minute: ‘2-digit’, hour12: true }).format(new Date(isoString)). This automatically uses the browser’s time zone setting.

Be careful with browser time zone detection. Some users travel frequently and their browser time zone might not match their Salesforce user time zone setting. Consider using the User.TimeZoneSidKey field to explicitly determine which time zone to display. You can pass the user’s time zone to Intl.DateTimeFormat options: { timeZone: ‘America/Los_Angeles’ }. This way you respect the user’s Salesforce preference rather than relying on browser settings which might be wrong.

Also think about how you’re positioning events in the calendar grid. If you’re using time strings to calculate pixel positions, that won’t work with time zones. You need to work with Date objects throughout your JavaScript logic and only format to strings for display. Calculate positions based on milliseconds or hours-since-midnight in the user’s time zone.

Don’t forget to handle edge cases like daylight saving time transitions and all-day events.