-
-
+
+
+
+
+
+
+
+
+
-
-
@@ -190,13 +249,20 @@
Shareable link
const copyStatus = document.getElementById('copy-status');
const shareableUrlInput = document.getElementById('shareable-url');
const inferredTimezoneValue = document.getElementById('inferred-timezone-value');
+ const baseTimezoneSelect = document.getElementById('base-timezone-select');
+ const timezoneSourceNote = document.getElementById('timezone-source-note');
+ const sharedMomentCard = document.getElementById('shared-moment-card');
+ const sharedSource = document.getElementById('shared-source');
+ const sharedTarget = document.getElementById('shared-target');
+ const sharedOrigin = document.getElementById('shared-origin');
+ const comparisonHint = document.getElementById('comparison-hint');
const resolvedZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const fallbackZone = resolvedZone || DateTime.local().zoneName || 'UTC';
- let localZone = fallbackZone;
- let localRowEntry = null;
+ let baseZone = fallbackZone;
let timezoneManuallySet = false;
const comparisonRows = [];
+ let sharedMoment = null;
function ensureOptionForZone(zone) {
const exists = Array.from(timezoneSelect.options).some(option => option.value === zone);
@@ -204,7 +270,8 @@
Shareable link
const option = document.createElement('option');
option.value = zone;
option.textContent = zone;
- timezoneSelect.append(option);
+ timezoneSelect.append(option.cloneNode(true));
+ baseTimezoneSelect.append(option);
}
}
@@ -230,10 +297,11 @@
Shareable link
const option = document.createElement('option');
option.value = zone;
option.textContent = zone;
- timezoneSelect.append(option);
+ timezoneSelect.append(option.cloneNode(true));
+ baseTimezoneSelect.append(option);
}
- ensureOptionForZone(localZone);
+ ensureOptionForZone(baseZone);
}
function createTimezoneSelectElement() {
@@ -247,35 +315,6 @@
Shareable link
inferredTimezoneValue.textContent = zone || 'Unavailable';
}
- function addLocalComparisonRow() {
- const row = document.createElement('tr');
- row.className = 'comparison-row comparison-row-fixed';
- row.dataset.rowType = 'local';
-
- const labelCell = document.createElement('th');
- labelCell.scope = 'row';
- labelCell.innerHTML = `
Your timezone
${localZone}
`;
-
- const timeCell = document.createElement('td');
- timeCell.className = 'comparison-time';
-
- const actionCell = document.createElement('td');
- actionCell.className = 'comparison-actions-cell';
-
- row.append(labelCell, timeCell, actionCell);
- comparisonRowsContainer.append(row);
-
- localRowEntry = {
- getZone: () => localZone,
- timeCell,
- updateLabel(zone) {
- labelCell.innerHTML = `
Your timezone
${zone}
`;
- }
- };
-
- comparisonRows.push(localRowEntry);
- }
-
function addCustomComparisonRow(initialZone) {
ensureOptionForZone(initialZone);
const row = document.createElement('tr');
@@ -330,28 +369,32 @@
Shareable link
return row;
}
- function updateLocalZone(zone, { updateSelect = true, updateComparison = true } = {}) {
+ function updateBaseZone(zone, note = '', { updateSelect = true, updateComparison: shouldUpdateComparison = true } = {}) {
if (!zone) {
updateInferredTimezoneDisplay('Unavailable');
return;
}
- const previousZone = localZone;
- const zoneChanged = zone !== localZone;
- localZone = zone;
-
- if (localRowEntry) {
- localRowEntry.updateLabel(zone);
- }
-
+ const previousZone = baseZone;
+ const zoneChanged = zone !== baseZone;
+ baseZone = zone;
updateInferredTimezoneDisplay(zone);
+ timezoneSourceNote.textContent = note || '';
ensureOptionForZone(zone);
+ if (updateSelect) {
+ baseTimezoneSelect.value = zone;
+ }
+
if (updateSelect && !timezoneManuallySet && (timezoneSelect.value === previousZone || !timezoneSelect.value)) {
timezoneSelect.value = zone;
}
- if (updateComparison && (zoneChanged || !comparisonTable.hidden)) {
+ if (zoneChanged) {
+ updateSharedMomentCard();
+ }
+
+ if (shouldUpdateComparison && (zoneChanged || !comparisonTable.hidden)) {
updateComparison();
}
}
@@ -401,7 +444,8 @@
Shareable link
if (!datetimeValue || !selectedZone) {
comparisonOutput.textContent = 'Choose a date, time, and timezone to see how it translates to your current timezone.';
- comparisonTable.hidden = true;
+ comparisonTable.hidden = comparisonRows.length === 0;
+ comparisonHint.hidden = comparisonRows.length > 0;
shareableUrlInput.value = location.href;
return;
}
@@ -410,7 +454,8 @@
Shareable link
if (!momentInSelectedZone.isValid) {
comparisonOutput.textContent = 'The selected date or timezone could not be parsed. Please check your inputs.';
- comparisonTable.hidden = true;
+ comparisonTable.hidden = comparisonRows.length === 0;
+ comparisonHint.hidden = comparisonRows.length > 0;
shareableUrlInput.value = location.href;
return;
}
@@ -419,7 +464,8 @@
Shareable link
const sourceText = `${formatDateTime(momentInSelectedZone)} in ${momentInSelectedZone.zoneName} (${selectedOffset})`;
comparisonOutput.textContent = `${sourceText}. Here's how that moment translates across the selected timezones:`;
- comparisonTable.hidden = false;
+ comparisonTable.hidden = comparisonRows.length === 0;
+ comparisonHint.hidden = comparisonRows.length > 0;
for (const entry of comparisonRows) {
const zoneName = entry.getZone();
@@ -499,6 +545,14 @@
Shareable link
datetimeInput.value = combined;
}
+ if (dateParam && timeParam && timezoneParam) {
+ sharedMoment = DateTime.fromISO(`${dateParam}T${timeParam}`, { zone: timezoneParam });
+ }
+
+ if (dateParam && timeParam) {
+ sharedOrigin.textContent = 'Loaded from URL parameters';
+ }
+
if (timezoneParam) {
ensureOptionForZone(timezoneParam);
timezoneSelect.value = timezoneParam;
@@ -508,6 +562,8 @@
Shareable link
if (datetimeInput.value && timezoneSelect.value) {
updateComparison(true);
}
+
+ updateSharedMomentCard();
}
async function detectTimezoneFromIp() {
@@ -525,15 +581,28 @@
Shareable link
}
if (detectedZone) {
- updateLocalZone(detectedZone);
+ updateBaseZone(detectedZone, 'Inferred from your IP address (worldtimeapi.org).');
} else {
- updateLocalZone(fallbackZone, { updateSelect: false, updateComparison: false });
+ updateBaseZone(fallbackZone, 'Using your browser-reported time zone.', { updateSelect: false, updateComparison: false });
+ }
+ }
+
+ function updateSharedMomentCard() {
+ if (!sharedMoment || !sharedMoment.isValid) {
+ sharedMomentCard.hidden = true;
+ return;
}
+
+ const baseZoneMoment = sharedMoment.setZone(baseZone);
+ const sourceLine = `${sharedMoment.toFormat('HH:mm')} on the ${sharedMoment.toFormat('dd')} of ${sharedMoment.toFormat('LL')}, ${sharedMoment.toFormat('yyyy')} ${sharedMoment.zoneName} is`;
+ sharedSource.textContent = sourceLine;
+ sharedTarget.textContent = baseZoneMoment.isValid ? `${baseZoneMoment.toFormat('HH:mm')} on ${baseZoneMoment.toFormat('dd LLL yyyy')} (${baseZoneMoment.offsetNameShort})` : 'Unable to convert to your base time zone.';
+ sharedMomentCard.hidden = false;
}
populateTimezones();
- addLocalComparisonRow();
- timezoneSelect.value = localZone;
+ timezoneSelect.value = baseZone;
+ baseTimezoneSelect.value = baseZone;
datetimeInput.value = DateTime.now().toISO({ suppressSeconds: true, suppressMilliseconds: true }).slice(0, 16);
updateComparison(true);
@@ -546,9 +615,12 @@
Shareable link
timezoneManuallySet = true;
updateComparison();
});
+ baseTimezoneSelect.addEventListener('change', () => {
+ updateBaseZone(baseTimezoneSelect.value, 'Manually selected base time zone.');
+ });
copyButton.addEventListener('click', copyLink);
addComparisonRowButton.addEventListener('click', () => {
- const defaultZone = timezoneSelect.value || localZone;
+ const defaultZone = timezoneSelect.value || baseZone;
addCustomComparisonRow(defaultZone);
updateComparison();
});