DateTimeUtil Class Reference
Overview
The DateTimeUtil class is a static utility class that provides comprehensive date and time handling functionality for Magentrix applications. This class enables developers to work with dates and times while properly managing timezone conversions, user preferences, and fiscal period calculations.
Key Features:
- Timezone conversion between UTC and user local time
- Relative time formatting (e.g., "5 minutes ago")
- Fiscal year and quarter calculations
- User timezone preference management
- Date/time manipulation utilities
Core Concepts
UTC Storage Model
Magentrix stores all date and time values in UTC (Coordinated Universal Time) format in the database. This ensures consistency across different timezones and eliminates ambiguity when users are distributed globally.
Why UTC Storage?
- Provides a single, unambiguous timestamp for all records
- Eliminates daylight saving time complications in storage
- Enables accurate timezone conversions for any user location
- Simplifies date/time calculations and comparisons
User Timezone Preferences
Each user can configure their preferred timezone in their user preferences. If no user timezone is set, the system falls back to the company's default timezone configured in Setup > Company Preferences.
Timezone Preference Hierarchy:
- User Timezone - Individual user preference (highest priority)
- Company Timezone - Organization default (fallback)
Automatic vs Manual Conversions
Automatic Conversions: Magentrix UI components such as FieldDateTime and InputField automatically handle timezone conversions. These components:
- Display UTC database values in the user's local timezone
- Convert user input back to UTC before saving to the database
- No developer intervention required for standard UI scenarios
Manual Conversions: The DateTimeUtil class is required when:
- Working with dates/times in custom controllers or business logic
- Processing dates programmatically outside of UI components
- Building custom APIs or data exports
- Implementing custom date formatting or calculations
Methods Summary
Methods
ConvertFromUTC
Converts UTC time to the current user's local timezone.
Description: This method takes a UTC DateTime value (typically retrieved from the database) and converts it to the user's local timezone based on their timezone preference. This is the primary method for displaying database timestamps to users.
Parameters:
utcTime (DateTime) - The UTC time to convert
Returns:
- DateTime - The time converted to the user's local timezone
Usage Example:
// Retrieve a record from the database with a UTC timestamp
var account = Database.Retrieve<Account>("account-id");
// Convert the UTC CreatedDate to user's local time for display
DateTime userLocalTime = DateTimeUtil.ConvertFromUTC(account.CreatedDate);
// Display to user
string displayTime = userLocalTime.ToString("yyyy-MM-dd h:mm tt");
// Example output: "2025-10-30 2:30 PM" (if user is in EST)
Notes:
- The method uses the current user's timezone preference from
SystemInfo.User.Timezone - If the user has no timezone preference, it falls back to the company timezone from
SystemInfo.Company.TimeZone - This method is functionally equivalent to the
ToUserTime() extension method
ConvertToUTC
Converts a DateTime value from the user's local timezone to UTC for database storage.
Description: This method converts a DateTime value from the user's local timezone to UTC format, preparing it for storage in the database. This ensures all timestamps are stored consistently in UTC regardless of the user's location.
Parameters:
value (DateTime) - The local time to convert to UTC
Returns:
- DateTime - The time converted to UTC
Usage Example:
// User enters a deadline date/time in their local timezone
DateTime userInputTime = new DateTime(2025, 12, 31, 23, 59, 59);
// Convert to UTC before saving to database
DateTime utcTime = DateTimeUtil.ConvertToUTC(userInputTime);
// Save to database
var opportunity = Database.Retrieve<Opportunity>("opp-id");
opportunity.CloseDate = utcTime;
Database.Update(opportunity);
Notes:
- The method automatically handles
DateTimeKind conversion - If the input DateTime has
DateTimeKind.Utc, it is converted to DateTimeKind.Unspecified before conversion - The conversion uses the current user's timezone preference
Warnings: ⚠️ Always use this method before saving user-entered date/time values to the database to ensure proper UTC storage
ConvertToUserTime
Extension method that converts UTC DateTime to a specified user's timezone.
Description: This extension method allows you to convert a UTC DateTime to any specified timezone, not just the current user's timezone. This is useful when processing data for multiple users or when you need to display times in a specific timezone.
Parameters:
utcDateTime (DateTime) - The UTC time to converttimezone (string) - The target timezone identifier (e.g., "Eastern Standard Time", "Pacific Standard Time")
Returns:
- DateTime - The time converted to the specified timezone
Usage Example:
// Get a UTC timestamp from database
DateTime utcEventTime = DateTime.Parse("2025-10-30 18:00:00").ToUniversalTime();
// Convert to specific timezone for event display
string pacificTimeZone = "Pacific Standard Time";
DateTime pacificTime = utcEventTime.ConvertToUserTime(pacificTimeZone);
// Output: "2025-10-30 11:00:00 AM" (Pacific Time is UTC-7)
Alternative Usage with User Object:
// Convert time to a specific user's timezone
var targetUser = Database.Retrieve<User>("user-id");
DateTime userTime = utcDateTime.ConvertToUserTime(targetUser.Timezone);
Notes:
- If the timezone parameter is null or empty, the method uses the company's default timezone
- Standard Windows timezone identifiers should be used (e.g., "Eastern Standard Time", not "EST")
GetFiscalEndDate
Gets the fiscal year end date from company preferences.
Description: Returns the end date of the current fiscal year as configured in the company preferences. The fiscal year is configured in Setup > Company Preferences > Company Information tab.
Parameters: None
Returns:
- DateTime - The fiscal year end date
Usage Example:
// Get the current fiscal year end date
DateTime fiscalEnd = DateTimeUtil.GetFiscalEndDate();
// Use in a query to filter records within the current fiscal year
var opportunities = Database.Query<Opportunity>()
.Where(o => o.CloseDate <= fiscalEnd)
.ToList();
// Display to user
string fiscalYearInfo = $"Current Fiscal Year ends on: {fiscalEnd:MMM dd, yyyy}";
// Example output: "Current Fiscal Year ends on: Dec 31, 2025"
Notes:
- The fiscal year configuration is set at the company level in Setup > Company Preferences
- Returns the value from
SystemInfo.Company.FiscalEndDate - The fiscal year end date is determined by the fiscal start month and naming convention configured by administrators
💡 Related: See GetFiscalStartDate() for the beginning of the fiscal year
GetFiscalQuarter
Gets fiscal quarter information including start and end dates.
Description: Returns a Quarter object containing the start and end dates for a specified fiscal quarter. This method supports relative quarter references such as "lastquarter", "thisquarter", and "nextquarter".
Parameters:
qtr (string) - The quarter identifier. Supported values:
"lastquarter" - Previous fiscal quarter"thisquarter" - Current fiscal quarter"nextquarter" - Next fiscal quarter
Returns:
- Quarter - Object containing
Start and End DateTime properties
Usage Example:
// Get the current fiscal quarter information
Quarter currentQuarter = DateTimeUtil.GetFiscalQuarter("thisquarter");
// Access start and end dates
DateTime quarterStart = currentQuarter.Start;
DateTime quarterEnd = currentQuarter.End;
// Use in queries
var dealsThisQuarter = Database.Query<Deal>()
.Where(d => d.CloseDate >= quarterStart && d.CloseDate <= quarterEnd)
.ToList();
// Display quarter information
string quarterInfo = $"Q{GetQuarterNumber(quarterStart)} runs from {quarterStart:MMM dd} to {quarterEnd:MMM dd, yyyy}";
// Example output: "Q3 runs from Jul 01 to Sep 30, 2025"
Advanced Example - Comparing Quarters:
// Get last quarter's data
Quarter lastQuarter = DateTimeUtil.GetFiscalQuarter("lastquarter");
var lastQuarterRevenue = Database.Query<Opportunity>()
.Where(o => o.CloseDate >= lastQuarter.Start &&
o.CloseDate <= lastQuarter.End &&
o.IsClosed)
.Sum(o => o.Amount);
// Get this quarter's data
Quarter thisQuarter = DateTimeUtil.GetFiscalQuarter("thisquarter");
var thisQuarterRevenue = Database.Query<Opportunity>()
.Where(o => o.CloseDate >= thisQuarter.Start &&
o.CloseDate <= thisQuarter.End &&
o.IsClosed)
.Sum(o => o.Amount);
// Calculate quarter-over-quarter growth
decimal growth = ((thisQuarterRevenue - lastQuarterRevenue) / lastQuarterRevenue) * 100;
Notes:
- Quarter boundaries are calculated based on the company's fiscal year start date configuration
- The
Quarter object provides direct access to Start and End properties as DateTime values - Quarter calculations respect the fiscal year configuration, which may differ from calendar quarters
💡 Configuration: Fiscal quarters are determined by the fiscal year start month configured in Setup > Company Preferences > Company Information
GetFiscalStartDate
Gets the fiscal year start date from company preferences.
Description: Returns the start date of the current fiscal year as configured in the company preferences. The fiscal year is configured in Setup > Company Preferences > Company Information tab.
Parameters: None
Returns:
- DateTime - The fiscal year start date
Usage Example:
// Get the current fiscal year start date
DateTime fiscalStart = DateTimeUtil.GetFiscalStartDate();
DateTime fiscalEnd = DateTimeUtil.GetFiscalEndDate();
// Calculate fiscal year-to-date revenue
var ytdRevenue = Database.Query<Opportunity>()
.Where(o => o.CloseDate >= fiscalStart &&
o.CloseDate <= DateTime.UtcNow &&
o.IsClosed)
.Sum(o => o.Amount);
// Display fiscal year information
string fiscalYearInfo = $"Fiscal Year {fiscalStart.Year}: {fiscalStart:MMM dd, yyyy} - {fiscalEnd:MMM dd, yyyy}";
// Example output: "Fiscal Year 2025: Apr 01, 2025 - Mar 31, 2026"
Usage in Date Range Filtering:
// Create fiscal year filter for reports
DateTime fiscalStart = DateTimeUtil.GetFiscalStartDate();
DateTime fiscalEnd = DateTimeUtil.GetFiscalEndDate();
var opportunities = Database.Query<Opportunity>()
.Where(o => o.CloseDate >= fiscalStart && o.CloseDate <= fiscalEnd)
.OrderBy(o => o.CloseDate)
.ToList();
Notes:
- The fiscal year configuration is set at the company level in Setup > Company Preferences
- Returns the value from
SystemInfo.Company.FiscalStartDate - Common fiscal year start months include January (calendar year), April (UK), July (Australia), and October (US government)
💡 Related: See GetFiscalEndDate() for the end of the fiscal year and GetFiscalQuarter() for quarter-level date ranges
GetUserTimezoneOffset
Gets the current user's timezone offset from UTC as a TimeSpan.
Description: Returns the timezone offset between UTC and the user's local timezone, accounting for daylight saving time. This offset can be used for custom timezone calculations or display logic.
Parameters: None
Returns:
- TimeSpan - The offset from UTC (positive for timezones ahead of UTC, negative for timezones behind)
Usage Example:
// Get the user's timezone offset
TimeSpan offset = DateTimeUtil.GetUserTimezoneOffset();
// Display offset information
int hours = offset.Hours;
string offsetDisplay = $"Your timezone is UTC{(hours >= 0 ? "+" : "")}{hours}";
// Example output: "Your timezone is UTC-5" (Eastern Time)
// Example output: "Your timezone is UTC+1" (Central European Time)
Advanced Usage - Manual Time Calculations:
// Get user's offset
TimeSpan userOffset = DateTimeUtil.GetUserTimezoneOffset();
// Get current UTC time
DateTime utcNow = DateTime.UtcNow;
// Calculate user's local time manually
DateTime userLocalTime = utcNow.Add(userOffset);
// Display time with offset
string display = $"Current time: {userLocalTime:h:mm tt} (UTC{(userOffset.Hours >= 0 ? "+" : "")}{userOffset.Hours})";
// Example output: "Current time: 2:30 PM (UTC-5)"
Usage in API Responses:
public ActionResponse GetTimeInfo()
{
var offset = DateTimeUtil.GetUserTimezoneOffset();
return Json(new
{
utcTime = DateTime.UtcNow,
userOffset = offset.TotalHours,
offsetDisplay = $"UTC{(offset.Hours >= 0 ? "+" : "")}{offset.Hours}"
});
}
Notes:
- The method automatically considers daylight saving time adjustments
- Offset is calculated based on the current user's timezone preference or company default
- The TimeSpan includes both hours and minutes components (e.g., some timezones have 30-minute offsets like India Standard Time at UTC+5:30)
- If the user has no timezone configured, the company's default timezone is used
💡 Tip: For most display scenarios, use ConvertFromUTC() or ToUserTime() instead of manually calculating with offsets
SetTime
Extension method that sets the time portion of a DateTime while preserving the date.
Description: This extension method allows you to modify the time component of a DateTime object while keeping the date portion unchanged. This is useful when you need to set specific times (like start of day, end of day, or specific meeting times) on existing dates.
Parameters:
datetime (DateTime) - The DateTime to modifytime (string) - The time string to set (must be parseable by DateTime.Parse)
Returns:
- DateTime - A new DateTime with the specified time and original date
Usage Example:
// Set a specific time on today's date
DateTime today = DateTime.Now.Date;
DateTime startOfBusiness = today.SetTime("9:00 AM");
DateTime endOfBusiness = today.SetTime("5:00 PM");
// Example: Create a same-day event
var meeting = new Event
{
Subject = "Team Standup",
StartDate = today.SetTime("9:30 AM"),
EndDate = today.SetTime("10:00 AM")
};
Database.Insert(meeting);
Setting End of Day:
// Get the last moment of a specific date
DateTime deadline = DateTime.Parse("2025-12-31");
DateTime endOfDay = deadline.SetTime("11:59:59 PM");
// Use in queries
var dueTodayItems = Database.Query<Task>()
.Where(t => t.DueDate <= endOfDay)
.ToList();
Working with Date Ranges:
// Create a date range for a full day
DateTime selectedDate = DateTime.Parse("2025-10-30");
DateTime dayStart = selectedDate.SetTime("12:00 AM"); // Start of day
DateTime dayEnd = selectedDate.SetTime("11:59:59 PM"); // End of day
// Query records within the day
var activities = Database.Query<Activity>()
.Where(a => a.ActivityDate >= dayStart && a.ActivityDate <= dayEnd)
.ToList();
24-Hour Format:
// Using 24-hour time format
DateTime appointment = DateTime.Today.SetTime("14:30"); // 2:30 PM
DateTime lateNight = DateTime.Today.SetTime("23:45"); // 11:45 PM
Notes:
- The time string must be in a format that
DateTime.Parse can interpret - Supported formats include: "9:00 AM", "9:00:00 AM", "14:30", "14:30:00"
- The original DateTime's
DateTimeKind is preserved in the returned DateTime - This method does not perform timezone conversions; it only modifies the time component
Warnings: ⚠️ The time string must be valid and parseable. Invalid time strings will throw a FormatException
⚠️ Be careful with timezone implications. If working with UTC times, ensure your time string represents the intended UTC time, not local time
ToRelativeTime
Extension method that converts a DateTime to a human-readable relative time string.
Description: Converts a DateTime value into a relative time string like "5 minutes ago", "2 hours ago", or "3 days ago". This method provides user-friendly time displays for activity feeds, notifications, and timestamps where exact times are less important than relative recency.
Parameters:
datetime (DateTime) - The DateTime to convert to relative timeisUtc (bool, optional) - Indicates whether the input DateTime is in UTC. Default: falseshortForm (bool, optional) - Whether to use abbreviated format (e.g., "5m" instead of "5 minutes ago"). Default: false
Returns:
- string - The relative time string (automatically localized based on user's culture)
Usage Example - Basic:
// Display when a record was created
DateTime createdTime = DateTime.Now.AddMinutes(-30);
string relativeTime = createdTime.ToRelativeTime();
// Output: "30 minutes ago"
// Display in UI
string message = $"Post created {relativeTime}";
// Output: "Post created 30 minutes ago"
Usage Example - Short Form:
// Use short form for compact displays
DateTime lastActive = DateTime.Now.AddHours(-2);
string shortTime = lastActive.ToRelativeTime(shortForm: true);
// Output: "2h"
// Useful for activity indicators
string status = $"Active {shortTime}";
// Output: "Active 2h"
Usage Example - With UTC Times:
// When working with UTC database times
DateTime utcCreatedDate = account.CreatedDate; // Already in UTC
string relativeTime = utcCreatedDate.ToRelativeTime(isUtc: true);
// Output: "5 days ago" (converted to user's timezone for calculation)
Common Time Ranges:
| Actual Time Difference | Long Form | Short Form |
|---|
| < 1 minute | "just now" | "1s" - "59s" |
| 1 minute | "one minute ago" | "1m" |
| 2-44 minutes | "X minutes ago" | "Xm" |
| 45-89 minutes | "an hour ago" | "1h" |
| 90 minutes - 23 hours | "X hours ago" | "Xh" |
| 24-47 hours | "X hours ago" | "Xh" |
| 2-29 days | "X days ago" | "Xd" |
| 30-364 days | "X months ago" | "X months" |
| 365+ days | "X years ago" | "Xy" |
Advanced Example - Activity Feed:
// Build an activity feed with relative times
var recentActivities = Database.Query<Activity>()
.Where(a => a.OwnerId == SystemInfo.UserId)
.OrderByDescending(a => a.CreatedDate)
.Take(10)
.ToList();
foreach (var activity in recentActivities)
{
// Convert UTC database time to relative time
string timeAgo = activity.CreatedDate.ToRelativeTime(isUtc: true);
string message = $"{activity.Subject} - {timeAgo}";
// Example output: "Meeting with client - 2 hours ago"
}
Future Times:
// The method also handles future times
DateTime futureEvent = DateTime.Now.AddHours(2);
string timeUntil = futureEvent.ToRelativeTime();
// Output: "2 hours left" (for future dates)
DateTime tomorrow = DateTime.Now.AddDays(1);
string daysLeft = tomorrow.ToRelativeTime();
// Output: "1 day left"
Notes:
- Strings are automatically localized based on the user's culture settings (
CultureInfo.CurrentUICulture) - The method supporting multiple languages
- When
isUtc is true, the method converts to user's local timezone before calculating relative time - For times less than 1 second, displays "just now"
- The method intelligently switches between seconds, minutes, hours, days, months, and years based on the time difference
💡 Best Practice: Use relative times for activity feeds, notifications, and recent activity displays. Use absolute times for important deadlines, scheduled events, and historical records.
ToUserRelativeTime
Extension method that converts a UTC DateTime to a relative time string in the user's timezone.
Description: Convenience method that combines timezone conversion and relative time formatting in a single call. It converts a UTC DateTime to the user's local timezone and then formats it as a relative time string (e.g., "5 minutes ago").
Parameters:
datetime (DateTime) - The UTC DateTime to convert (should be in UTC)
Returns:
- string - The relative time string in the user's timezone (automatically localized)
Usage Example:
// Retrieve a record with UTC timestamp from database
var comment = Database.Retrieve<Comment>("comment-id");
// Convert UTC CreatedDate to relative time in user's timezone
string timeAgo = comment.CreatedDate.ToUserRelativeTime();
// Output: "5 minutes ago" (in user's local timezone)
// Display in UI
string display = $"Comment posted {timeAgo}";
// Output: "Comment posted 5 minutes ago"
Usage in List Views:
// Display relative times for a list of records
var notifications = Database.Query<Notification>()
.Where(n => n.RecipientId == SystemInfo.UserId && !n.IsRead)
.OrderByDescending(n => n.CreatedDate)
.ToList();
foreach (var notification in notifications)
{
// Each CreatedDate is in UTC from database
string timeAgo = notification.CreatedDate.ToUserRelativeTime();
string message = $"{notification.Title} - {timeAgo}";
// Example output: "New message received - 10 minutes ago"
}
Comparison with ToRelativeTime:
// These two approaches are equivalent:
// Approach 1: Two-step process
DateTime userLocalTime = DateTimeUtil.ConvertFromUTC(utcDateTime);
string relativeTime1 = userLocalTime.ToRelativeTime();
// Approach 2: Single method call (preferred)
string relativeTime2 = utcDateTime.ToUserRelativeTime();
// Both produce the same result
Activity Timeline Example:
public class ActivityViewModel
{
public string Subject { get; set; }
public string TimeAgo { get; set; }
}
// Build activity timeline with relative times
var activities = Database.Query<Activity>()
.Where(a => a.AccountId == accountId)
.OrderByDescending(a => a.ActivityDate)
.Take(20)
.ToList()
.Select(a => new ActivityViewModel
{
Subject = a.Subject,
TimeAgo = a.ActivityDate.ToUserRelativeTime() // UTC to relative time
})
.ToList();
// Results ready for display in user's timezone
// Example: [{ Subject: "Phone call", TimeAgo: "2 hours ago" }, ...]
Notes:
- This method assumes the input DateTime is in UTC (as stored in the database)
- Internally calls
ConvertFromUTC() followed by ToRelativeTime() - Automatically localized based on user's culture settings
- Ideal for displaying database timestamps in a user-friendly format
💡 When to Use: This is the preferred method when working with UTC database timestamps that need to be displayed as relative times. It's more concise and clearer than manually converting and formatting.
ToUserTime
Extension method that converts a UTC DateTime to the current user's local time.
Description: Converts a UTC DateTime value to the user's local timezone. This is an extension method version of ConvertFromUTC(), providing a more fluent syntax for timezone conversions.
Parameters:
utcDateTime (DateTime) - The UTC DateTime to convert
Returns:
- DateTime - The DateTime converted to the user's local timezone
Usage Example:
// Retrieve record with UTC timestamp from database
var opportunity = Database.Retrieve<Opportunity>("opp-id");
// Convert UTC CloseDate to user's local time using extension method
DateTime userLocalCloseDate = opportunity.CloseDate.ToUserTime();
// Display to user
string displayDate = userLocalCloseDate.ToString("MMM dd, yyyy h:mm tt");
// Example output: "Dec 31, 2025 11:59 PM" (in user's timezone)
Fluent Chaining:
// Extension method allows for fluent syntax
string formattedDate = account.CreatedDate
.ToUserTime()
.ToString("yyyy-MM-dd");
// Equivalent to:
DateTime userTime = DateTimeUtil.ConvertFromUTC(account.CreatedDate);
string formattedDate = userTime.ToString("yyyy-MM-dd");
Usage in LINQ Queries:
// Convert and format dates in LINQ projections
var upcomingEvents = Database.Query<Event>()
.Where(e => e.StartDate > DateTime.UtcNow)
.OrderBy(e => e.StartDate)
.ToList()
.Select(e => new
{
Title = e.Subject,
LocalStartTime = e.StartDate.ToUserTime(), // Convert to user time
FormattedTime = e.StartDate.ToUserTime().ToString("g")
})
.ToList();
Null Handling:
// Safe handling of nullable DateTime fields
DateTime? lastModifiedUtc = record.ModifiedDate;
DateTime? userLocalTime = lastModifiedUtc?.ToUserTime();
// Display with null check
string displayTime = userLocalTime?.ToString("g") ?? "Never modified";
Comparison: ToUserTime vs ConvertFromUTC:
// Both methods are functionally equivalent:
// Method 1: Static method
DateTime result1 = DateTimeUtil.ConvertFromUTC(utcDateTime);
// Method 2: Extension method (more fluent)
DateTime result2 = utcDateTime.ToUserTime();
// Choose based on coding style preference
Notes:
- This method is functionally identical to
ConvertFromUTC() but provides extension method syntax - Uses the current user's timezone preference from
SystemInfo.User.Timezone - Falls back to company timezone if user has no timezone preference
- Input DateTime should be in UTC (as stored in the database)
💡 Coding Style: Use ToUserTime() for a more fluent, readable coding style, especially when chaining methods. Use ConvertFromUTC() when you prefer explicit static method calls.
Common Usage Patterns
Pattern 1: Displaying Database Times to Users
When retrieving date/time values from the database, they are stored in UTC and need to be converted to the user's timezone for display.
public ActionResponse ViewOpportunity(string id)
{
// Retrieve opportunity from database (dates are in UTC)
var opportunity = Database.Retrieve<Opportunity>(id);
// Convert UTC times to user's local timezone for display
DateTime localCloseDate = opportunity.CloseDate.ToUserTime();
DateTime localCreatedDate = opportunity.CreatedDate.ToUserTime();
DateTime localModifiedDate = opportunity.ModifiedDate.ToUserTime();
// Create view model with converted times
var viewModel = new OpportunityViewModel
{
Name = opportunity.Name,
Amount = opportunity.Amount,
CloseDate = localCloseDate.ToString("MMM dd, yyyy"),
CreatedDate = localCreatedDate.ToString("g"),
ModifiedDate = localModifiedDate.ToString("g")
};
return View(viewModel);
}
Alternative using relative time for timestamps:
// For activity timestamps, use relative time
var viewModel = new OpportunityViewModel
{
Name = opportunity.Name,
CreatedTime = opportunity.CreatedDate.ToUserRelativeTime(), // "5 days ago"
LastModified = opportunity.ModifiedDate.ToUserRelativeTime() // "2 hours ago"
};
Pattern 2: Saving User Input to Database
When accepting date/time input from users, convert their local time to UTC before saving to the database.
[HttpPost]
public ActionResponse CreateEvent(string subject, DateTime startDate, DateTime endDate)
{
// User entered dates in their local timezone
// Convert to UTC before saving to database
DateTime utcStartDate = DateTimeUtil.ConvertToUTC(startDate);
DateTime utcEndDate = DateTimeUtil.ConvertToUTC(endDate);
// Create and save event with UTC times
var newEvent = new Event
{
Subject = subject,
StartDate = utcStartDate,
EndDate = utcEndDate,
OwnerId = SystemInfo.UserId
};
Database.Insert(newEvent);
return Json(new { success = true, id = newEvent.Id });
}
Setting specific times on dates:
[HttpPost]
public ActionResponse CreateTask(string subject, DateTime dueDate)
{
// User selected a date, set end of day as deadline
DateTime endOfDay = dueDate.SetTime("11:59:59 PM");
// Convert to UTC for storage
DateTime utcDueDate = DateTimeUtil.ConvertToUTC(endOfDay);
var task = new Task
{
Subject = subject,
DueDate = utcDueDate,
OwnerId = SystemInfo.UserId
};
Database.Insert(task);
return Json(new { success = true });
}
Pattern 3: Working with Relative Times
Display user-friendly relative time strings for activity feeds, notifications, and recent activity lists.
public ActionResponse GetActivityFeed()
{
// Get recent activities (dates in UTC from database)
var activities = Database.Query<Activity>()
.Where(a => a.OwnerId == SystemInfo.UserId)
.OrderByDescending(a => a.CreatedDate)
.Take(20)
.ToList();
// Convert to view models with relative times
var feedItems = activities.Select(a => new
{
Id = a.Id,
Subject = a.Subject,
Description = a.Description,
TimeAgo = a.CreatedDate.ToUserRelativeTime(), // "5 minutes ago"
TimeAgoShort = a.CreatedDate.ToRelativeTime(isUtc: true, shortForm: true) // "5m"
}).ToList();
return Json(feedItems);
}
Notification system with relative times:
public class NotificationService
{
public List<NotificationViewModel> GetUnreadNotifications(string userId)
{
var notifications = Database.Query<Notification>()
.Where(n => n.RecipientId == userId && !n.IsRead)
.OrderByDescending(n => n.CreatedDate)
.ToList();
return notifications.Select(n => new NotificationViewModel
{
Id = n.Id,
Title = n.Title,
Message = n.Message,
TimeDisplay = GetSmartTimeDisplay(n.CreatedDate),
Icon = n.Type
}).ToList();
}
private string GetSmartTimeDisplay(DateTime utcCreatedDate)
{
// Show relative time for recent notifications
var localTime = utcCreatedDate.ToUserTime();
var hoursSince = (DateTime.Now - localTime).TotalHours;
if (hoursSince < 24)
{
// Less than 24 hours: show relative time
return utcCreatedDate.ToUserRelativeTime(); // "5 minutes ago"
}
else
{
// Older: show absolute date
return localTime.ToString("MMM dd, yyyy"); // "Oct 15, 2025"
}
}
}
Pattern 4: Working with Fiscal Periods
Calculate fiscal year and quarter boundaries for reporting and filtering.
public ActionResponse GetFiscalYearSummary()
{
// Get fiscal year boundaries
DateTime fiscalStart = DateTimeUtil.GetFiscalStartDate();
DateTime fiscalEnd = DateTimeUtil.GetFiscalEndDate();
// Calculate year-to-date revenue
var ytdOpportunities = Database.Query<Opportunity>()
.Where(o => o.CloseDate >= fiscalStart &&
o.CloseDate <= DateTime.UtcNow &&
o.IsClosed)
.ToList();
decimal ytdRevenue = ytdOpportunities.Sum(o => o.Amount);
// Calculate full year pipeline
var fullYearOpportunities = Database.Query<Opportunity>()
.Where(o => o.CloseDate >= fiscalStart &&
o.CloseDate <= fiscalEnd)
.ToList();
decimal fullYearPipeline = fullYearOpportunities.Sum(o => o.Amount);
return Json(new
{
FiscalYearStart = fiscalStart.ToString("MMM dd, yyyy"),
FiscalYearEnd = fiscalEnd.ToString("MMM dd, yyyy"),
YTDRevenue = ytdRevenue,
FullYearPipeline = fullYearPipeline,
PercentComplete = (decimal)DateTime.UtcNow.DayOfYear / 365 * 100
});
}
Quarterly reporting with comparisons:
public ActionResponse GetQuarterlyReport()
{
// Get current and previous quarter information
Quarter thisQuarter = DateTimeUtil.GetFiscalQuarter("thisquarter");
Quarter lastQuarter = DateTimeUtil.GetFiscalQuarter("lastquarter");
// Calculate revenue for each quarter
decimal thisQuarterRevenue = Database.Query<Opportunity>()
.Where(o => o.CloseDate >= thisQuarter.Start &&
o.CloseDate <= thisQuarter.End &&
o.IsClosed)
.Sum(o => o.Amount);
decimal lastQuarterRevenue = Database.Query<Opportunity>()
.Where(o => o.CloseDate >= lastQuarter.Start &&
o.CloseDate <= lastQuarter.End &&
o.IsClosed)
.Sum(o => o.Amount);
// Calculate growth
decimal growth = lastQuarterRevenue > 0
? ((thisQuarterRevenue - lastQuarterRevenue) / lastQuarterRevenue) * 100
: 0;
return Json(new
{
CurrentQuarter = new
{
Start = thisQuarter.Start.ToString("MMM dd, yyyy"),
End = thisQuarter.End.ToString("MMM dd, yyyy"),
Revenue = thisQuarterRevenue
},
PreviousQuarter = new
{
Start = lastQuarter.Start.ToString("MMM dd, yyyy"),
End = lastQuarter.End.ToString("MMM dd, yyyy"),
Revenue = lastQuarterRevenue
},
QuarterOverQuarterGrowth = $"{growth:F2}%"
});
}
Fiscal quarter-based filtering:
public ActionResponse GetQuarterlyPipeline(string quarter)
{
// Get the specified quarter's date range
Quarter selectedQuarter = DateTimeUtil.GetFiscalQuarter(quarter);
// Query opportunities within the quarter
var opportunities = Database.Query<Opportunity>()
.Where(o => o.CloseDate >= selectedQuarter.Start &&
o.CloseDate <= selectedQuarter.End)
.OrderBy(o => o.CloseDate)
.ToList();
// Group by month within quarter
var monthlyBreakdown = opportunities
.GroupBy(o => new { o.CloseDate.Year, o.CloseDate.Month })
.Select(g => new
{
Month = new DateTime(g.Key.Year, g.Key.Month, 1).ToString("MMM yyyy"),
Count = g.Count(),
TotalAmount = g.Sum(o => o.Amount)
})
.ToList();
return Json(new
{
QuarterStart = selectedQuarter.Start.ToString("MMM dd, yyyy"),
QuarterEnd = selectedQuarter.End.ToString("MMM dd, yyyy"),
TotalOpportunities = opportunities.Count,
TotalValue = opportunities.Sum(o => o.Amount),
MonthlyBreakdown = monthlyBreakdown
});
}
Pattern 5: Modifying Time Components
Use SetTime() to set specific times on dates while preserving the date portion.
public ActionResponse CreateDaySchedule(DateTime date)
{
// Define business hours
DateTime dayStart = date.SetTime("9:00 AM");
DateTime lunchStart = date.SetTime("12:00 PM");
DateTime lunchEnd = date.SetTime("1:00 PM");
DateTime dayEnd = date.SetTime("5:00 PM");
// Create scheduled events
var morningMeeting = new Event
{
Subject = "Team Standup",
StartDate = DateTimeUtil.ConvertToUTC(date.SetTime("9:30 AM")),
EndDate = DateTimeUtil.ConvertToUTC(date.SetTime("10:00 AM")),
OwnerId = SystemInfo.UserId
};
var clientCall = new Event
{
Subject = "Client Review",
StartDate = DateTimeUtil.ConvertToUTC(date.SetTime("2:00 PM")),
EndDate = DateTimeUtil.ConvertToUTC(date.SetTime("3:00 PM")),
OwnerId = SystemInfo.UserId
};
// Save events
Database.Insert(morningMeeting);
Database.Insert(clientCall);
return Json(new { success = true });
}
Creating date ranges for queries:
public ActionResponse GetDailyActivity(DateTime selectedDate)
{
// Create full-day range using SetTime
DateTime dayStart = selectedDate.SetTime("12:00 AM");
DateTime dayEnd = selectedDate.SetTime("11:59:59 PM");
// Convert to UTC for database query
DateTime utcStart = DateTimeUtil.ConvertToUTC(dayStart);
DateTime utcEnd = DateTimeUtil.ConvertToUTC(dayEnd);
// Query all activities for the day
var activities = Database.Query<Activity>()
.Where(a => a.ActivityDate >= utcStart &&
a.ActivityDate <= utcEnd &&
a.OwnerId == SystemInfo.UserId)
.OrderBy(a => a.ActivityDate)
.ToList();
// Convert back to user time for display
var displayActivities = activities.Select(a => new
{
Subject = a.Subject,
Time = a.ActivityDate.ToUserTime().ToString("h:mm tt"),
Description = a.Description
}).ToList();
return Json(displayActivities);
}
Scheduling with specific times:
public ActionResponse ScheduleRecurringMeeting(DateTime startDate, int occurrences)
{
// Set specific meeting time
DateTime meetingTime = startDate.SetTime("10:00 AM");
// Create recurring meetings
for (int i = 0; i < occurrences; i++)
{
DateTime occurrenceDate = meetingTime.AddDays(i * 7); // Weekly
DateTime occurrenceEnd = occurrenceDate.AddHours(1); // 1-hour meeting
var meeting = new Event
{
Subject = "Weekly Team Meeting",
StartDate = DateTimeUtil.ConvertToUTC(occurrenceDate),
EndDate = DateTimeUtil.ConvertToUTC(occurrenceEnd),
OwnerId = SystemInfo.UserId
};
Database.Insert(meeting);
}
return Json(new { success = true, meetingsCreated = occurrences });
}
Method Comparison Guide
When to Use Which Conversion Method?
| Scenario | Recommended Method | Reason |
|---|
| Converting UTC from database for display | ConvertFromUTC() or ToUserTime() | Both are equivalent; ToUserTime() provides fluent syntax as extension method |
| Converting with specific timezone | ConvertToUserTime(timezone) | Allows you to specify a custom timezone parameter |
| Converting user input to UTC for storage | ConvertToUTC() | Properly handles DateTimeKind and converts from user's timezone to UTC |
| Display relative time from UTC database value | ToUserRelativeTime() | Combines timezone conversion and relative formatting in one call |
| Display relative time (already converted to local) | ToRelativeTime() | Use when DateTime is already in user's timezone |
| Display relative time in short format | ToRelativeTime(shortForm: true) | Provides abbreviated format like "5m", "2h", "3d" |
Conversion Method Decision Tree
Do you have a UTC database value?
│
├─ YES → Need to display it?
│ │
│ ├─ As absolute time → Use ConvertFromUTC() or ToUserTime()
│ │
│ └─ As relative time → Use ToUserRelativeTime()
│
└─ NO → Have user's local time?
│
└─ Need to save to database? → Use ConvertToUTC()
Relative Time Method Comparison
| Method | Input Type | Output | Use Case |
|---|
ToRelativeTime() | Local DateTime | Relative string | DateTime already in user's timezone |
ToRelativeTime(isUtc: true) | UTC DateTime | Relative string | UTC DateTime, need timezone conversion |
ToUserRelativeTime() | UTC DateTime | Relative string | Preferred for UTC database values |
ToRelativeTime(shortForm: true) | Any DateTime | Short relative string | Compact displays (e.g., "5m", "2h") |
Best Practices
1. Always Store in UTC
Store all date and time values in UTC format in the database. Never store local times.
// ✅ CORRECT
DateTime userInput = GetUserDateInput();
DateTime utcValue = DateTimeUtil.ConvertToUTC(userInput);
record.DueDate = utcValue;
Database.Update(record);
// ❌ INCORRECT - storing local time
record.DueDate = userInput; // This is local time!
Database.Update(record);
2. Convert for Display
Always convert UTC database values to user's local time before displaying.
// ✅ CORRECT
var record = Database.Retrieve<Opportunity>(id);
DateTime displayTime = record.CloseDate.ToUserTime();
ViewBag.CloseDate = displayTime.ToString("g");
// ❌ INCORRECT - displaying UTC time
ViewBag.CloseDate = record.CloseDate.ToString("g"); // User sees UTC time!
3. Let UI Components Handle Standard Cases
For standard form input and display, use Magentrix UI components (FieldDateTime, InputField) which handle conversions automatically.
// ✅ UI components handle timezone conversion automatically
<aspx:InputField runat='server' value='{!Model.DueDate}' />
// Component automatically:
// - Displays UTC database value in user's local time
// - Converts user input back to UTC on save
// ⚠️ Only use DateTimeUtil for custom business logic or programmatic processing
4. Check DateTimeKind
Be aware of the DateTimeKind property, especially when working with ConvertToUTC().
// ✅ CORRECT - ConvertToUTC handles DateTimeKind
DateTime userInput = DateTime.Parse("2025-10-30 10:00:00"); // Kind: Unspecified
DateTime utcValue = DateTimeUtil.ConvertToUTC(userInput); // Properly converts
// ⚠️ Be careful with DateTime.UtcNow
DateTime utcNow = DateTime.UtcNow; // Kind: UTC
// ConvertToUTC automatically adjusts if Kind is UTC
5. Use Relative Times Appropriately
Relative times are great for recent activity but not suitable for important dates.
// ✅ GOOD - Relative time for activity feed
string activityTime = activity.CreatedDate.ToUserRelativeTime();
// Output: "5 minutes ago"
// ❌ BAD - Relative time for important deadline
string deadline = opportunity.CloseDate.ToUserRelativeTime();
// Output: "3 days ago" - User can't tell the exact date!
// ✅ BETTER - Absolute time for deadlines
string deadline = opportunity.CloseDate.ToUserTime().ToString("MMM dd, yyyy");
// Output: "Oct 30, 2025"
When to Use Relative vs Absolute:
| Use Relative Time For | Use Absolute Time For |
|---|
| Activity feeds | Deadlines and due dates |
| Notification timestamps | Scheduled events |
| "Last updated" indicators | Contract dates |
| Comment timestamps | Fiscal year boundaries |
| Recent activity | Historical records |
6. Cache Timezone Information
If performing multiple timezone operations in the same request, cache the timezone offset.
// ✅ EFFICIENT - Cache offset for multiple operations
TimeSpan userOffset = DateTimeUtil.GetUserTimezoneOffset();
foreach (var record in records)
{
// Use cached offset instead of calling GetUserTimezoneOffset repeatedly
DateTime localTime = record.CreatedDate.Add(userOffset);
// ... process record
}
// ⚠️ INEFFICIENT - Calling method repeatedly
foreach (var record in records)
{
TimeSpan offset = DateTimeUtil.GetUserTimezoneOffset(); // Repeated calls
DateTime localTime = record.CreatedDate.Add(offset);
}
// ✅ EVEN BETTER - Use ToUserTime() which is optimized
foreach (var record in records)
{
DateTime localTime = record.CreatedDate.ToUserTime();
// ... process record
}
7. Handle Null DateTime Values
Always check for null DateTime values before conversion.
// ✅ CORRECT - Null check before conversion
DateTime? lastModified = record.ModifiedDate;
string displayTime = lastModified.HasValue
? lastModified.Value.ToUserTime().ToString("g")
: "Never modified";
// ✅ ALTERNATIVE - Using null-conditional operator
string displayTime = record.ModifiedDate?.ToUserTime().ToString("g") ?? "Never modified";
// ❌ INCORRECT - May throw exception
string displayTime = record.ModifiedDate.ToUserTime().ToString("g"); // Null reference!
8. Be Consistent with Date Formats
Use consistent date/time formats throughout your application.
// ✅ GOOD - Consistent formatting
string shortDate = dateTime.ToString("MMM dd, yyyy"); // Oct 30, 2025
string longDate = dateTime.ToString("MMMM dd, yyyy"); // October 30, 2025
string dateTime = dateTime.ToString("g"); // 10/30/2025 2:30 PM
string iso = dateTime.ToString("yyyy-MM-dd"); // 2025-10-30
// Consider creating format constants
public static class DateFormats
{
public const string ShortDate = "MMM dd, yyyy";
public const string LongDate = "MMMM dd, yyyy";
public const string DateTime = "g";
public const string ISO = "yyyy-MM-dd";
}
9. Fiscal Period Calculations
When working with fiscal periods, always use the DateTimeUtil methods rather than hardcoding dates.
// ✅ CORRECT - Use fiscal methods
DateTime fiscalStart = DateTimeUtil.GetFiscalStartDate();
DateTime fiscalEnd = DateTimeUtil.GetFiscalEndDate();
var ytdRevenue = Database.Query<Opportunity>()
.Where(o => o.CloseDate >= fiscalStart && o.CloseDate <= fiscalEnd)
.Sum(o => o.Amount);
// ❌ INCORRECT - Hardcoded dates
var ytdRevenue = Database.Query<Opportunity>()
.Where(o => o.CloseDate >= new DateTime(2025, 1, 1)) // Assumes calendar year!
.Sum(o => o.Amount);
10. Testing with Different Timezones
When testing, verify behavior across different timezones.
// Test helper method
public void TestTimezoneBehavior()
{
// Create test data in UTC
DateTime utcTime = new DateTime(2025, 10, 30, 18, 0, 0, DateTimeKind.Utc);
// Simulate different user timezones
string[] testTimezones = new[]
{
"Eastern Standard Time", // UTC-5
"Pacific Standard Time", // UTC-8
"GMT Standard Time", // UTC+0
"Tokyo Standard Time" // UTC+9
};
foreach (var timezone in testTimezones)
{
DateTime localTime = utcTime.ConvertToUserTime(timezone);
Console.WriteLine($"{timezone}: {localTime:g}");
}
}
Troubleshooting
Problem: Times Showing Incorrectly
Symptoms:
- Displayed times don't match user's expected timezone
- Times are off by several hours
- Dates show wrong day
Solutions:
- Verify DateTimeKind:
// Check the DateTimeKind of your DateTime
SystemInfo.Debug($"DateTime Kind: {myDateTime.Kind}");
// Should be Utc for database values, Unspecified for user input
// If incorrect, specify the kind:
DateTime utcTime = DateTime.SpecifyKind(myDateTime, DateTimeKind.Utc);
- Verify User Timezone Configuration:
// Check user's timezone setting
string userTimezone = SystemInfo.User.Timezone;
Console.WriteLine($"User Timezone: {userTimezone}");
// Check company default timezone
string companyTimezone = SystemInfo.Company.TimeZone;
SystemInfo.Debug($"Company Timezone: {companyTimezone}");
- Verify Conversion Direction:
// ✅ CORRECT - Database to display
DateTime displayTime = databaseUtcTime.ToUserTime();
// ❌ WRONG DIRECTION - Display to database
DateTime wrongTime = userInputTime.ToUserTime(); // Makes it MORE wrong!
// ✅ CORRECT - User input to database
DateTime dbTime = userInputTime.ConvertToUTC();
Problem: Relative Times Not Localized
Symptoms:
- Relative time strings appear in wrong language
- Format doesn't match user's culture
- "ago" text not translated
Solutions:
- Check Culture Settings:
// Verify current culture
var currentCulture = System.Globalization.CultureInfo.CurrentCulture;
var currentUICulture = System.Globalization.CultureInfo.CurrentUICulture;
SystemInfo.Debug($"Culture: {currentCulture.Name}");
SystemInfo.Debug($"UI Culture: {currentUICulture.Name}");
- Verify WebResources are Available:
// The ToRelativeTime() method uses WebResources for localization
// Ensure resource files are properly deployed for your culture
- Use SystemInfo for Culture Information:
var userCulture = SystemInfo.UICulture();
SystemInfo.Debug($"User Culture: {userCulture.DisplayName}");
Problem: Fiscal Dates Returning Unexpected Values
Symptoms:
- Fiscal start/end dates don't match expectations
- Quarter boundaries seem incorrect
- Fiscal year calculations produce wrong results
Solutions:
Verify Company Fiscal Year Configuration:
- Navigate to Setup > Company Preferences
- Click Edit > Company Information tab
- Verify "Fiscal Year Start Month" setting
- Verify "Fiscal Year Name Based On" setting
Check Fiscal Year Boundaries:
// Debug fiscal year configuration
DateTime fiscalStart = DateTimeUtil.GetFiscalStartDate();
DateTime fiscalEnd = DateTimeUtil.GetFiscalEndDate();
SystemInfo.Debug($"Fiscal Year: {fiscalStart:MMM dd, yyyy} to {fiscalEnd:MMM dd, yyyy}");
// Verify quarters align with fiscal year
Quarter q1 = DateTimeUtil.GetFiscalQuarter("thisquarter");
SystemInfo.Debug($"Current Quarter: {q1.Start:MMM dd} to {q1.End:MMM dd}");
- Verify Quarter String Parameters:
// ✅ CORRECT - Valid quarter strings
var thisQ = DateTimeUtil.GetFiscalQuarter("thisquarter");
var lastQ = DateTimeUtil.GetFiscalQuarter("lastquarter");
var nextQ = DateTimeUtil.GetFiscalQuarter("nextquarter");
// ❌ INCORRECT - Invalid quarter strings
var invalid = DateTimeUtil.GetFiscalQuarter("Q1"); // Not supported
var invalid2 = DateTimeUtil.GetFiscalQuarter("first quarter"); // Not supported
Problem: SetTime Throws Exception
Symptoms:
FormatException when calling SetTime()- "String was not recognized as a valid DateTime"
Solutions:
- Use Valid Time Format:
// ✅ CORRECT - Valid time formats
var time1 = date.SetTime("9:00 AM");
var time2 = date.SetTime("9:00:00 AM");
var time3 = date.SetTime("14:30"); // 24-hour format
var time4 = date.SetTime("14:30:00");
// ❌ INCORRECT - Invalid formats
var invalid1 = date.SetTime("9 AM"); // Missing minutes
var invalid2 = date.SetTime("25:00"); // Invalid hour
var invalid3 = date.SetTime("9:00 PM EST"); // Timezone not supported
- Validate Time String Before Use:
public DateTime SafeSetTime(DateTime date, string timeString)
{
try
{
return date.SetTime(timeString);
}
catch (FormatException)
{
// Log error and return safe default
SystemInfo.Error($"Invalid time format: {timeString}");
return date.SetTime("12:00 AM"); // Default to start of day
}
}
Problem: Performance Issues with Large Datasets
Symptoms:
- Slow performance when converting many dates
- Timeout errors when processing large lists
Solutions:
- Batch Process Efficiently:
// ✅ EFFICIENT - Convert in memory after query
var records = Database.Query<Activity>()
.Where(a => a.OwnerId == userId)
.ToList(); // Execute query first
// Then convert times in memory
var displayRecords = records.Select(r => new
{
Subject = r.Subject,
LocalTime = r.CreatedDate.ToUserTime()
}).ToList();
// ❌ INEFFICIENT - Multiple database round trips
foreach (var record in records)
{
var detail = Database.Retrieve<Activity>(record.Id); // Extra query!
var localTime = detail.CreatedDate.ToUserTime();
}
- Cache Timezone Information:
// ✅ EFFICIENT - Cache offset
TimeSpan userOffset = DateTimeUtil.GetUserTimezoneOffset();
var times = records.Select(r => r.CreatedDate.Add(userOffset)).ToList();
// ✅ BETTER - Use ToUserTime() which is optimized
var times = records.Select(r => r.CreatedDate.ToUserTime()).ToList();
Problem: Daylight Saving Time Issues
Symptoms:
- Times off by exactly 1 hour during DST transitions
- Inconsistent results across different dates
Solutions:
- Use Timezone Methods (Not Manual Offsets):
// ✅ CORRECT - Handles DST automatically
DateTime userTime = utcTime.ToUserTime();
// ❌ INCORRECT - Fixed offset doesn't account for DST
TimeSpan fixedOffset = TimeSpan.FromHours(-5); // EST
DateTime wrongTime = utcTime.Add(fixedOffset); // Wrong during DST!
- Verify Timezone Offset for Specific Dates:
// Check offset for specific date (accounts for DST)
DateTime summerDate = new DateTime(2025, 7, 15, 0, 0, 0, DateTimeKind.Utc);
DateTime winterDate = new DateTime(2025, 1, 15, 0, 0, 0, DateTimeKind.Utc);
var summerTime = summerDate.ToUserTime();
var winterTime = winterDate.ToUserTime();
// Offsets will differ if timezone observes DST
Additional Notes
Localization Support
The ToRelativeTime() methods automatically use WebResources for localized strings based on the user's culture settings. This ensures relative time displays appear in the user's language:
- English: "5 minutes ago", "2 hours ago"
- French: "il y a 5 minutes", "il y a 2 heures"
- Spanish: "hace 5 minutos", "hace 2 horas"
Related Documentation
- SystemInfo Class - Access user and company information, including timezone preferences
- FieldDateTime Component - UI component with automatic timezone conversion
- InputField Component - Form input component with automatic date/time handling