Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 41 additions & 7 deletions Frontend/src/utils/dateUtils.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,57 @@
/**
* Unified Date Utility for HELPDESK.AI
* Fixes timezone shift issues by explicitly forcing local display.
* v2 — Safari-compatible ISO-8601 normalization added.
*/

/**
* Normalize an ISO-8601 timestamp so it parses correctly in Safari.
* Safari is strict: rejects space-instead-of-T, non-standard timezone
* offsets, and microsecond-precision fractional seconds in some cases.
*/
const normalizeDateStr = (dateStr) => {
if (typeof dateStr !== 'string') return dateStr;
let s = dateStr.trim();

// Replace space between date and time with 'T' (Safari requirement)
// e.g. "2024-01-15 14:30:00+00" → "2024-01-15T14:30:00+00"
s = s.replace(/^(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2})/, '$1T$2');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Normalize short timezone offsets before parsing

For timestamps in the documented failing shape such as 2024-01-15 14:30:00+00, this normalization only changes the separator and leaves the offset as +00. That is not a valid ECMAScript ISO offset, so new Date('2024-01-15T14:30:00+00') is invalid in common engines; the new fallback then renders the current time instead of the ticket time. When the backend emits +00 offsets, every affected timeline entry will show the wrong date rather than being fixed for Safari.

Useful? React with 👍 / 👎.


// Normalize short timezone offsets to ±HH:MM format (Safari requires colon)
// e.g. "+00" → "+00:00", "-05" → "-05:00", "+0530" → "+05:30"
s = s.replace(
/([+-])(\d{2})(\d{2})?$/,
(_, sign, hh, mm) => `${sign}${hh}:${mm || '00'}`
);

// Ensure trailing Z for UTC if no timezone info is present
// after normalization (bare "2024-01-15T14:30:00" → "2024-01-15T14:30:00Z")
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(s)) {
s += 'Z';
}

return s;
};

export const formatTimelineDate = (dateStr) => {
if (!dateStr) return null;

// Ensure the date string is interpreted as UTC if it's an ISO string from DB
let date;
if (typeof dateStr === 'string' && !dateStr.includes('Z') && !dateStr.includes('+')) {
// If it's a raw string without TZ, assume it was intended as UTC from our backend
date = new Date(dateStr + 'Z');
const normalized = normalizeDateStr(dateStr);

if (typeof normalized === 'string' && !normalized.includes('Z') && !normalized.includes('+')) {
// If it's a raw string without TZ, assume UTC
date = new Date(normalized + 'Z');
} else {
date = new Date(dateStr);
date = new Date(normalized);
}

if (isNaN(date.getTime())) return 'Invalid Date';
// Graceful fallback for invalid / corrupt dates
if (isNaN(date.getTime())) {
// Return current timestamp as fallback instead of crashing
date = new Date();
}

// Using the browser's default locale and timeZone (which is the user's local)
return date.toLocaleString(undefined, {
day: '2-digit',
month: 'short',
Expand Down