Skip to content
Closed
Show file tree
Hide file tree
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
127 changes: 127 additions & 0 deletions components/seo/TimezoneConverterSEO.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import CodeExample from "../CodeExample";

export default function TimezoneConverterSEO() {
return (
<div className="content-wrapper">
<section>
<p>
Easily convert times between different timezones with this free tool.
Perfect for remote software teams who need to schedule syncs,
meetings, and standups across multiple timezones. No more mental math
or timezone confusion.
</p>
</section>

<section>
<h2>Features:</h2>
<ul>
<li>
<b>Instant Conversion:</b> <br /> Select a time and see it converted
across all major timezones instantly.
</li>
<li>
<b>Common Timezones:</b> <br /> Pre-configured with the most common
timezones for distributed teams including US, Europe, and Asia.
</li>
<li>
<b>Open Source:</b> <br /> Made with love by the developers building
Jam.
</li>
</ul>
</section>

<section>
<h2>How to use the Timezone Converter:</h2>
<ul>
<li>
<b>Step 1:</b> <br /> Select your source timezone and enter the time
you want to convert.
</li>
<li>
<b>Step 2:</b> <br /> View the converted times across all selected
timezones.
</li>
<li>
<b>Step 3:</b> <br /> Toggle timezones on/off to customize your
view.
</li>
</ul>
</section>

<section>
<h2>Why Use a Timezone Converter?</h2>
<p>
Remote teams often span multiple continents and timezones. Scheduling
meetings that work for everyone can be challenging. A timezone
converter helps you:
</p>
<ul>
<li>
<b>Schedule Meetings:</b> <br /> Find times that work across
different regions without manual calculations.
</li>
<li>
<b>Avoid Confusion:</b> <br /> Eliminate timezone math errors that
can lead to missed meetings.
</li>
<li>
<b>Plan Ahead:</b> <br /> See how a proposed meeting time affects
team members in different locations.
</li>
</ul>
</section>

<section>
<h2>Convert Timezones in JavaScript:</h2>
<p>
If you need to convert timezones programmatically in your own
applications, here is a code snippet using the Intl API:
</p>
</section>

<section>
<CodeExample>{jsCodeExample}</CodeExample>
</section>

<section>
<h2>FAQs:</h2>
<ul>
<li>
<b>Does this tool handle Daylight Saving Time?</b> <br /> Yes, the
converter automatically accounts for DST changes in each timezone.
</li>
<li>
<b>What timezones are supported?</b> <br /> We support all major
timezones including US (PT, MT, CT, ET), Europe (GMT, CET), and Asia
(IST, SGT, JST).
</li>
<li>
<b>Can I use this for scheduling recurring meetings?</b> <br /> Yes,
simply select the date and time for your meeting and see how it
translates across timezones.
</li>
</ul>
</section>
</div>
);
}

const jsCodeExample = `function convertTimezone(date: Date, fromTz: string, toTz: string): string {
const formatter = new Intl.DateTimeFormat('en-US', {
timeZone: toTz,
hour: '2-digit',
minute: '2-digit',
hour12: true,
weekday: 'short',
month: 'short',
day: 'numeric',
});

return formatter.format(date);
}

// Example usage:
const nyTime = new Date('2024-01-15T09:00:00');
console.log(convertTimezone(nyTime, 'America/New_York', 'Europe/London'));
// Output: "Mon, Jan 15, 02:00 PM"
`;
158 changes: 158 additions & 0 deletions components/utils/timezone-converter.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
export interface TimezoneInfo {
id: string;
label: string;
offset: string;
}

export const commonTimezones: TimezoneInfo[] = [
{ id: "America/Los_Angeles", label: "Los Angeles (PT)", offset: "" },
{ id: "America/Denver", label: "Denver (MT)", offset: "" },
{ id: "America/Chicago", label: "Chicago (CT)", offset: "" },
{ id: "America/New_York", label: "New York (ET)", offset: "" },
{ id: "America/Sao_Paulo", label: "Sao Paulo (BRT)", offset: "" },
{ id: "Europe/London", label: "London (GMT/BST)", offset: "" },
{ id: "Europe/Paris", label: "Paris (CET)", offset: "" },
{ id: "Europe/Berlin", label: "Berlin (CET)", offset: "" },
{ id: "Asia/Dubai", label: "Dubai (GST)", offset: "" },
{ id: "Asia/Kolkata", label: "India (IST)", offset: "" },
{ id: "Asia/Singapore", label: "Singapore (SGT)", offset: "" },
{ id: "Asia/Tokyo", label: "Tokyo (JST)", offset: "" },
{ id: "Australia/Sydney", label: "Sydney (AEST)", offset: "" },
];

export function getTimezoneOffset(timezone: string, date: Date): string {
const formatter = new Intl.DateTimeFormat("en-US", {
timeZone: timezone,
timeZoneName: "shortOffset",
});
const parts = formatter.formatToParts(date);
const offsetPart = parts.find((part) => part.type === "timeZoneName");
return offsetPart?.value || "";
}

export function convertTime(
sourceTime: string,
sourceDate: string,
sourceTimezone: string,
targetTimezones: string[]
): { timezone: string; label: string; time: string; date: string }[] {
if (!sourceTime || !sourceDate) {
return [];
}

const [hours, minutes] = sourceTime.split(":").map(Number);
const [year, month, day] = sourceDate.split("-").map(Number);

const sourceFormatter = new Intl.DateTimeFormat("en-US", {
timeZone: sourceTimezone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
hour12: false,
});

const tempDate = new Date(year, month - 1, day, hours, minutes);
const sourceParts = sourceFormatter.formatToParts(tempDate);

const getPartValue = (
parts: Intl.DateTimeFormatPart[],
type: Intl.DateTimeFormatPartTypes
) => parts.find((p) => p.type === type)?.value || "";

const sourceYear = parseInt(getPartValue(sourceParts, "year"));
const sourceMonth = parseInt(getPartValue(sourceParts, "month"));
const sourceDay = parseInt(getPartValue(sourceParts, "day"));
const sourceHour = parseInt(getPartValue(sourceParts, "hour"));
const sourceMinute = parseInt(getPartValue(sourceParts, "minute"));

const utcDate = new Date(
Date.UTC(sourceYear, sourceMonth - 1, sourceDay, sourceHour, sourceMinute)
);

const sourceOffset = getTimezoneOffsetMinutes(sourceTimezone, utcDate);
utcDate.setMinutes(utcDate.getMinutes() - sourceOffset);

return targetTimezones.map((tz) => {
const tzInfo = commonTimezones.find((t) => t.id === tz);
const formatter = new Intl.DateTimeFormat("en-US", {
timeZone: tz,
hour: "2-digit",
minute: "2-digit",
hour12: true,
weekday: "short",
month: "short",
day: "numeric",
});

const formatted = formatter.format(utcDate);
const parts = formatted.split(", ");
const weekday = parts[0];
const datePart = parts[1];
const timePart = parts[2];

return {
timezone: tz,
label: tzInfo?.label || tz,
time: timePart,
date: `${weekday}, ${datePart}`,
};
});
}

function getTimezoneOffsetMinutes(timezone: string, date: Date): number {
const utcDate = new Date(date.toLocaleString("en-US", { timeZone: "UTC" }));
const tzDate = new Date(date.toLocaleString("en-US", { timeZone: timezone }));
return (tzDate.getTime() - utcDate.getTime()) / 60000;
}

export function getCurrentTimeInTimezone(timezone: string): {
time: string;
date: string;
} {
const now = new Date();
const formatter = new Intl.DateTimeFormat("en-US", {
timeZone: timezone,
hour: "2-digit",
minute: "2-digit",
hour12: true,
weekday: "short",
month: "short",
day: "numeric",
});

const formatted = formatter.format(now);
const parts = formatted.split(", ");
const weekday = parts[0];
const datePart = parts[1];
const timePart = parts[2];

return {
time: timePart,
date: `${weekday}, ${datePart}`,
};
}

export function formatTimeForInput(date: Date, timezone: string): string {
const formatter = new Intl.DateTimeFormat("en-US", {
timeZone: timezone,
hour: "2-digit",
minute: "2-digit",
hour12: false,
});
const parts = formatter.formatToParts(date);
const hour = parts.find((p) => p.type === "hour")?.value || "00";
const minute = parts.find((p) => p.type === "minute")?.value || "00";
return `${hour}:${minute}`;
}

export function formatDateForInput(date: Date, timezone: string): string {
const formatter = new Intl.DateTimeFormat("en-CA", {
timeZone: timezone,
year: "numeric",
month: "2-digit",
day: "2-digit",
});
return formatter.format(date);
}
6 changes: 6 additions & 0 deletions components/utils/tools-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,10 @@ export const tools = [
"Generate cryptographically secure random strings with configurable character sets. Perfect for API keys, tokens, passwords, and secure identifiers.",
link: "/utilities/random-string-generator",
},
{
title: "Timezone Converter",
description:
"Convert times between timezones for remote team scheduling. Perfect for distributed software teams coordinating meetings across multiple timezones.",
link: "/utilities/timezone-converter",
},
];
Loading