#Working across US and India time zones
AddedIndia is 10 hours 30 minutes ahead of Austin for most of the year and 11 hours 30 minutes ahead in winter, and that one hour decides whether your teams share 90 minutes a day or 30. India Standard Time is UTC+5:30 all year; India has no daylight saving time. Austin is on US Central time: CDT (UTC−5) from the second Sunday in March to the first Sunday in November, CST (UTC−6) the rest of the year. In 2026 the US changes are on 8 March and 1 November; in 2027, 14 March and 7 November. India never moves, so every US change shifts the whole overlap by an hour.
The mental model is a relay race's exchange zone. Runners can only hand the baton over inside a short marked zone; anywhere else, the baton has to be left somewhere the next runner will find it. The overlap is the exchange zone: the only time a question can be asked and answered in the same conversation. Everything else has to be handed over in writing, clearly labelled, so the next runner can pick it up without asking. A distributed team succeeds or fails on two things: how it uses the zone (only for what needs a conversation), and how good the handovers are outside it.
Rather than trusting a table, compute it from the time-zone database, which is what calendars do. This model uses Intl.DateTimeFormat with the IANA zones America/Chicago and Asia/Kolkata (Node 26 here ships tz data 2026a), on dates either side of both 2026 US changes, for two India schedules:
// Overlap between an Austin team and an India team, from the IANA time-zone rules Node ships with:
// America/Chicago follows US daylight saving time; Asia/Kolkata has no DST (always UTC+5:30).
const AUSTIN = "America/Chicago";
const INDIA = "Asia/Kolkata";
// A zone's offset from UTC in minutes at one instant (e.g. -300 for UTC-5).
function offsetMinutes(zone, instant) {
const name = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "longOffset" })
.formatToParts(instant).find((p) => p.type === "timeZoneName").value; // "GMT-05:00"
const m = name.match(/GMT([+-])(\d\d):(\d\d)/);
return m ? (m[1] === "-" ? -1 : 1) * (Number(m[2]) * 60 + Number(m[3])) : 0;
}
// "2026-03-09", "08:00" on the wall clock in `zone` → the real instant.
function wallToInstant(date, time, zone) {
const asIfUtc = Date.parse(`${date}T${time}:00Z`);
let guess = asIfUtc - offsetMinutes(zone, new Date(asIfUtc)) * 60_000;
guess = asIfUtc - offsetMinutes(zone, new Date(guess)) * 60_000; // second pass settles DST edges
return new Date(guess);
}
const clock = (instant, zone) =>
new Intl.DateTimeFormat("en-GB", { timeZone: zone, hour: "2-digit", minute: "2-digit", hourCycle: "h23" }).format(instant);
const hm = (min) => `${Math.floor(Math.abs(min) / 60)}:${String(Math.abs(min) % 60).padStart(2, "0")}`;
const utc = (min) => `UTC${min < 0 ? "-" : "+"}${hm(min)}`;
const austinDay = { start: "08:00", end: "17:00" };
const indiaDays = {
"India 09:30–18:30": { start: "09:30", end: "18:30" }, // a typical office day
"India 11:00–20:00": { start: "11:00", end: "20:00" }, // a shifted day, common on US-facing teams
};
const dates = ["2026-03-06", "2026-03-09", "2026-10-30", "2026-11-02"]; // either side of both US clock changes
for (const [label, indiaDay] of Object.entries(indiaDays)) {
console.log(`Austin 08:00–17:00 with ${label}`);
for (const date of dates) {
const aStart = wallToInstant(date, austinDay.start, AUSTIN), aEnd = wallToInstant(date, austinDay.end, AUSTIN);
const iStart = wallToInstant(date, indiaDay.start, INDIA), iEnd = wallToInstant(date, indiaDay.end, INDIA);
const from = new Date(Math.max(aStart, iStart)), to = new Date(Math.min(aEnd, iEnd));
const minutes = Math.max(0, (to - from) / 60_000);
const aOff = offsetMinutes(AUSTIN, aStart), iOff = offsetMinutes(INDIA, aStart);
const window = minutes
? `overlap ${clock(from, AUSTIN)}–${clock(to, AUSTIN)} Austin = ${clock(from, INDIA)}–${clock(to, INDIA)} IST (${minutes} min)`
: "no overlap";
console.log(` ${date} Austin ${utc(aOff)} India ${utc(iOff)} India ${hm(iOff - aOff)} ahead ${window}`);
}
}Austin 08:00–17:00 with India 09:30–18:30
2026-03-06 Austin UTC-6:00 India UTC+5:30 India 11:30 ahead no overlap
2026-03-09 Austin UTC-5:00 India UTC+5:30 India 10:30 ahead no overlap
2026-10-30 Austin UTC-5:00 India UTC+5:30 India 10:30 ahead no overlap
2026-11-02 Austin UTC-6:00 India UTC+5:30 India 11:30 ahead no overlap
Austin 08:00–17:00 with India 11:00–20:00
2026-03-06 Austin UTC-6:00 India UTC+5:30 India 11:30 ahead overlap 08:00–08:30 Austin = 19:30–20:00 IST (30 min)
2026-03-09 Austin UTC-5:00 India UTC+5:30 India 10:30 ahead overlap 08:00–09:30 Austin = 18:30–20:00 IST (90 min)
2026-10-30 Austin UTC-5:00 India UTC+5:30 India 10:30 ahead overlap 08:00–09:30 Austin = 18:30–20:00 IST (90 min)
2026-11-02 Austin UTC-6:00 India UTC+5:30 India 11:30 ahead overlap 08:00–08:30 Austin = 19:30–20:00 IST (30 min)offsetMinutesasksIntlfor the zone's offset at a specific instant (longOffsetgives a name likeGMT-05:00) and turns it into minutes. Asking at an instant, not per zone, is the whole point: Chicago is −360 minutes on 6 March and −300 on 9 March.wallToInstantturns a wall-clock time in a zone ("08:00 in Austin on 9 March") into a real instant. It guesses with the offset at the naive time, then corrects once with the offset at the guess, which settles the days when the offset changes.- With a typical India office day (09:30–18:30 IST) there's no overlap in any season. 18:30 IST is 08:00 Austin in summer and 07:00 in winter, so the India day ends before or as Austin's begins. Teams that "work US hours" in India, or Austin people who start at 07:00, exist because of this row.
- With a shifted India day (11:00–20:00 IST, common on US-facing teams), the overlap is 08:00–09:30 Austin = 18:30–20:00 IST in summer, 90 minutes. After 1 November it's 08:00–08:30 Austin = 19:30–20:00 IST, 30 minutes. India's hours didn't change and Austin's didn't change; only the US clocks did.
- The difference column reads 11:30 on 6 March, 10:30 on 9 March and 30 October, and 11:30 again on 2 November: India is 11:30 ahead until the US change on 8 March, 10:30 ahead until the change on 1 November, then 11:30 again. Plan the year with both numbers: about eight months at 10:30 and four at 11:30.
- If you changed
austinDay.startto"07:30", winter overlap doubles to 60 minutes. Small, deliberate shifts on both sides are how teams buy overlap; the model makes the cost of each choice visible.
A recurring meeting is stored in the time zone of whoever created it. That decides which site's clock moves when the US changes its clocks:
// A weekly sync is created in one time zone. Which side's clock moves when the US changes its clocks?
const AUSTIN = "America/Chicago";
const INDIA = "Asia/Kolkata";
function offsetMinutes(zone, instant) {
const name = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "longOffset" })
.formatToParts(instant).find((p) => p.type === "timeZoneName").value;
const m = name.match(/GMT([+-])(\d\d):(\d\d)/);
return m ? (m[1] === "-" ? -1 : 1) * (Number(m[2]) * 60 + Number(m[3])) : 0;
}
function wallToInstant(date, time, zone) {
const asIfUtc = Date.parse(`${date}T${time}:00Z`);
let guess = asIfUtc - offsetMinutes(zone, new Date(asIfUtc)) * 60_000;
guess = asIfUtc - offsetMinutes(zone, new Date(guess)) * 60_000;
return new Date(guess);
}
const show = (instant, zone) =>
new Intl.DateTimeFormat("en-GB", { timeZone: zone, weekday: "short", hour: "2-digit", minute: "2-digit", hourCycle: "h23" }).format(instant);
// 1. The days US clocks change, found by scanning noon UTC each day for a change in Chicago's offset.
for (const year of [2026, 2027]) {
const changes = [];
let prev = offsetMinutes(AUSTIN, new Date(Date.UTC(year, 0, 1, 12)));
for (let d = 1; d <= 365; d++) {
const noon = new Date(Date.UTC(year, 0, 1 + d, 12));
const now = offsetMinutes(AUSTIN, noon);
if (now !== prev) changes.push(`${noon.toISOString().slice(0, 10)} (UTC${now / 60})`);
prev = now;
}
console.log(`${year}: Chicago changes on ${changes.join(" and ")}`);
}
// 2. The same Tuesday sync, owned by each side, on the Tuesdays either side of 1 November 2026.
const tuesdays = ["2026-10-27", "2026-11-03"];
const owners = [
{ name: "Created in Austin, 08:30 America/Chicago", zone: AUSTIN, time: "08:30" },
{ name: "Created in India, 19:00 Asia/Kolkata", zone: INDIA, time: "19:00" },
];
for (const owner of owners) {
console.log(owner.name);
for (const date of tuesdays) {
const at = wallToInstant(date, owner.time, owner.zone);
console.log(` ${date}: Austin ${show(at, AUSTIN)} India ${show(at, INDIA)}`);
}
}2026: Chicago changes on 2026-03-08 (UTC-5) and 2026-11-01 (UTC-6)
2027: Chicago changes on 2027-03-14 (UTC-5) and 2027-11-07 (UTC-6)
Created in Austin, 08:30 America/Chicago
2026-10-27: Austin Tue 08:30 India Tue 19:00
2026-11-03: Austin Tue 08:30 India Tue 20:00
Created in India, 19:00 Asia/Kolkata
2026-10-27: Austin Tue 08:30 India Tue 19:00
2026-11-03: Austin Tue 07:30 India Tue 19:00- The first part finds the US change dates the same way a calendar would, from the tz data: it checks Chicago's offset at noon UTC each day of the year and prints the days it changed. 2026: 8 March (to UTC−5) and 1 November (to UTC−6). 2027: 14 March and 7 November.
- A sync created in Austin at 08:30
America/Chicagostays at 08:30 for Austin all year. For India it's 19:00 on 27 October and 20:00 on 3 November: the India team absorbs the change, and their meeting now starts just as their working day ends. - The same sync created in India at 19:00
Asia/Kolkatastays at 19:00 in India. For Austin it moves from 08:30 to 07:30: now the Austin people absorb it. - Neither is wrong, but someone always pays, and it's decided by whoever clicked "create". Decide deliberately, write it down in the team's working agreement, and look at the calendar in the week each US change happens (and the weeks between the US and European changes, if the client has people in Europe too).
- The rules themselves can change. The US House passed the Sunshine Protection Act (H.R. 139), which would make daylight time permanent, on 14 July 2026 by 308–117 (House Clerk, roll call 238). It still needs the Senate and the President; news reports up to October 2026 say the Senate hadn't voted on it (checked 27 October 2026 in the news only; the Senate's own record wasn't checked). If it ever becomes law, the tz database is updated and code like this follows it; a table of hard-coded offsets wouldn't. That's the reason to compute from
Intland never to store "India is 10.5 hours ahead".
The overlap matters most for blocking questions: an India developer can't continue until someone in Austin answers. This model follows one question from the moment it's asked to the moment the developer can act on the answer, with Austin on 08:00–17:00 CT and India on 11:00–20:00 IST, both Monday to Friday:
// An India engineer gets stuck and asks the Austin lead a question. When can work continue?
// Austin works 08:00–17:00 America/Chicago, India 11:00–20:00 Asia/Kolkata, both Monday–Friday.
const hours = {
"America/Chicago": { start: 8 * 60, end: 17 * 60 },
"Asia/Kolkata": { start: 11 * 60, end: 20 * 60 },
};
const wall = (zone, instant) => {
const p = Object.fromEntries(
new Intl.DateTimeFormat("en-US", { timeZone: zone, weekday: "short", hour: "numeric", minute: "numeric", hourCycle: "h23" })
.formatToParts(instant).map((x) => [x.type, x.value]),
);
return { day: p.weekday, minute: Number(p.hour) * 60 + Number(p.minute) };
};
const working = (zone, instant) => {
const { day, minute } = wall(zone, instant);
return day !== "Sat" && day !== "Sun" && minute >= hours[zone].start && minute < hours[zone].end;
};
// Step forward a minute at a time (fine for a model) until `zone` is at work.
const nextWorking = (zone, instant) => {
let t = instant.getTime();
while (!working(zone, new Date(t))) t += 60_000;
return new Date(t);
};
const fmt = (instant, zone) =>
new Intl.DateTimeFormat("en-GB", { timeZone: zone, weekday: "short", hour: "2-digit", minute: "2-digit", hourCycle: "h23" }).format(instant);
const hoursBetween = (a, b) => ((b - a) / 3_600_000).toFixed(1);
const ASK = "Asia/Kolkata", ANSWER = "America/Chicago";
const questions = [
"2026-10-27T12:00:00+05:30", // Tuesday lunchtime in India
"2026-10-27T19:15:00+05:30", // Tuesday evening in India, inside the overlap
"2026-10-30T19:45:00+05:30", // Friday evening in India
"2026-11-03T12:00:00+05:30", // Tuesday again, after US clocks went back on 1 November
];
for (const iso of questions) {
const asked = new Date(iso);
const seen = nextWorking(ANSWER, asked); // the lead reads it when their day starts
const answered = new Date(seen.getTime() + 20 * 60_000); // 20 minutes to read, check and reply
const resumed = nextWorking(ASK, answered); // the engineer can act on it in their working hours
console.log(
`asked ${fmt(asked, ASK)} IST → lead sees ${fmt(seen, ANSWER)} Austin → unblocked ${fmt(resumed, ASK)} IST` +
` (${hoursBetween(asked, resumed)} h)`,
);
}asked Tue 12:00 IST → lead sees Tue 08:00 Austin → unblocked Tue 18:50 IST (6.8 h)
asked Tue 19:15 IST → lead sees Tue 08:45 Austin → unblocked Tue 19:35 IST (0.3 h)
asked Fri 19:45 IST → lead sees Fri 09:15 Austin → unblocked Mon 11:00 IST (63.3 h)
asked Tue 12:00 IST → lead sees Tue 08:00 Austin → unblocked Tue 19:50 IST (7.8 h)nextWorkingsteps forward a minute at a time until the given zone is inside its working hours on a weekday (fine for a model; a real scheduler would jump). The lead reads the question at the start of their day and takes 20 minutes to reply.- A question asked at 12:00 IST on Tuesday is seen at 08:00 Austin (18:30 IST) and answered by 18:50 IST: 6.8 hours, most of the India working day lost. Asked inside the overlap (19:15 IST), the same question costs 20 minutes.
- The Friday case is the expensive one. Asked at 19:45 IST on Friday, the lead sees it at 09:15 Austin and answers at 09:35, which is 20:05 IST, five minutes after the India day ended. The developer acts on it at 11:00 IST on Monday: 63.3 hours. Austin's Friday afternoon is India's weekend.
- The last row is the same Tuesday question after the US clocks went back: 7.8 hours instead of 6.8, because the Austin day now starts an hour later on the India clock.
- What a lead does about it: make most questions non-blocking (good tickets, written decisions, a documented default for each open question), give every India developer a next item to switch to when blocked, answer India questions first thing in the Austin morning before anything else, and never leave a decision for "Friday afternoon".
When work crosses from one site to the other, the note is the baton. A template that works for an end-of-day handoff (India evening to Austin morning, or the reverse):
Handoff: API-298, device settings PATCH, from Dev 3 (India) to Austin, Tue 27 Oct 19:40 IST
State: Branch feat/api-298 pushed; PR #412 open as draft; CI green except the contract test below.
Done today: PATCH handler and validation; unit tests for 0, 100, 101, -1.
Not done: Contract test fails against firmware 9.8: it returns 500, not 400, for level=101.
Log and request/response saved in the PR description.
Decision needed (blocking): Do we map firmware 9.8's 500 to a 400 in our API, or document 9.8 as
unsupported for this endpoint? Default if no answer by 11:00 IST: map it, behind a flag.
Next for Austin (optional, if you have time): try the PR against the 9.8 simulator image.
Next for me tomorrow: finish error mapping per the decision; then UI-207.- The header says what, who, from where and when, with the time zone. A reader in Austin at 08:00 knows immediately whether this is theirs and how fresh it is.
- State points to artefacts, not descriptions: the branch, the draft PR, the CI status. Anyone can pick it up from the repository without a call.
- Not done includes the evidence (log and request/response saved in the PR), so the Austin reader doesn't have to reproduce the problem before thinking about it.
- Decision needed is the most important line: one question, marked blocking, with a default and a deadline. If Austin doesn't answer by 11:00 IST, Dev 3 proceeds with the default instead of waiting a day. That turns a blocking question into a non-blocking one.
- Next for both sides makes the plan explicit, so the night isn't wasted and nobody duplicates work. The note is linked from the ticket, so it's still findable next month.
Most friction on distributed teams comes from expectations nobody wrote down: when people are reachable, how fast a reply is due, who takes the late meeting. A working agreement makes them explicit. The team writes it together, in the repository, and reviews it at a retro each time the US clocks change:
# Working agreement (Austin + India). Agreed 2026-11-02; review at the March 2027 retro.
Hours
- Austin 08:00–17:00 CT. India 11:00–20:00 IST.
- Overlap: 08:00–09:30 CT / 18:30–20:00 IST (US daylight time); 08:00–08:30 CT / 19:30–20:00 IST (US standard time).
- The overlap is for: Daily Scrum, blocking questions, decisions, live reviews. No status meetings in it.
Replies
- Ticket and PR comments: within the other site's next working day.
- Blocking questions: in the team channel, tagged, with a default. Answered in the next overlap.
- Nobody is expected to read chat outside their working hours. Urgent production issues go to on-call.
Meetings
- Every invite shows both times: "08:00 CT / 19:30 IST".
- Long events (Planning, Review, Retro) rotate between an early Austin slot and a late India slot each Sprint.
- Every meeting has notes in writing within the day; decisions go in docs/decisions.md.
Handoffs
- End-of-day handoff note on any ticket that crosses sites (template: docs/templates/handoff.md).
- Nothing India-bound is left for Friday afternoon Austin time.
Holidays
- Both sites' holiday lists are in the team calendar by 15 January.- Hours state both sites' days and both seasons' overlap windows, with the times computed (as in the model above), so nobody has to work them out or gets them wrong in March and November.
- Saying what the overlap is for protects it. Thirty minutes in winter is gone if a status meeting takes it; listing the Daily Scrum, blocking questions, decisions and live reviews, and banning status meetings, keeps it for what only a conversation can do.
- Replies set response-time expectations per channel, and say explicitly that nobody reads chat outside their hours. That one sentence stops the slow creep of India engineers answering Austin messages at midnight, and gives production issues a proper path (on-call) instead.
- Meetings make the cost of the inconvenient slot shared (rotation) and visible (both times in every invite), and require written notes so the people who couldn't attend aren't second-class.
- Review it when the clocks change. The agreement's numbers are only right for half the year each; putting the review in the March and November retros keeps them true.
Follow-the-sun means passing the same piece of work between sites at the end of each day so it progresses around the clock. It sounds like doubling speed; in software it usually isn't, and the research says why:
- Herbsleb and Mockus, "An Empirical Study of Speed and Communication in Globally Distributed Software Development" (IEEE Transactions on Software Engineering, 2003), combined change-management data with surveys in a multi-site development organisation (and replicated the analysis in a second one) and found that distributed work items appeared to take about two and a half times as long as similar items done at one site. Their abstract ties the delay to distributed items involving more people, and the number of people to the calendar time an item takes. The practical conclusion usually drawn from it (this page's reading; the paper's full recommendations weren't checked) is to reduce the need for cross-site communication, for example by dividing work so each site can work on its own part independently.
- Every handoff costs context: the receiver has to rebuild what the sender knew. In development, that rebuild often costs more than the hours gained.
- Where follow-the-sun does work is in queue-shaped work with small, self-contained units: support tickets, incident response with a good runbook, and monitoring.
The practical shape for a US–India product team is the opposite of follow-the-sun: give each site whole pieces it can finish, a feature, a component or an API, end to end, and hand over at boundaries (contracts, PRs), not mid-task. Use the overlap for decisions and reviews, not for passing half-done work.
- Get both holiday lists in January. India's three national holidays have fixed dates (Republic Day 26 January, Independence Day 15 August, Gandhi Jayanti 2 October), but many others (Diwali, Holi, Eid, and regional festivals that differ by state and city) follow lunar calendars and move every year. US holidays mostly fall on fixed weekdays (Thanksgiving is the fourth Thursday of November; Memorial Day the last Monday of May).
- The week shapes the calendar too. There are five overlap windows a week, but they're lopsided. India's Monday morning is Sunday night in Austin, so India's Monday questions wait for the Monday overlap; Austin's Friday afternoon is India's Friday night, so anything Austin produces after Friday's overlap isn't seen in India until Monday at 11:00 IST, two to two and a half days later. Ask for decisions early in the week, and don't leave India-bound handoffs for Friday afternoon.
- Put both sites' holidays in the capacity plan (see Estimation and planning), and in release plans: don't schedule a release that needs India support on Diwali, or one that needs Austin sign-off on the Friday after Thanksgiving.
An Austin product manager books a demo for 09:00 Austin time on Friday 6 March 2026 and again on Friday 13 March 2026. What time is each in India, and is either inside an 11:00–20:00 IST working day?
Show answer
6 March: 20:30 IST, outside the India day. 13 March: 19:30 IST, inside it, with 30 minutes left.
- On 6 March 2026 the US is still on standard time (the change is on Sunday 8 March), so Austin is CST, UTC−6. 09:00 CST = 15:00 UTC = 20:30 IST (UTC+5:30), half an hour past the end of the India day.
- On 13 March Austin is on CDT, UTC−5. 09:00 CDT = 14:00 UTC = 19:30 IST, inside the India day.
- Same Austin time, a week apart, an hour's difference in India, because only one side changed its clocks.
- The fix for the 6 March demo is to move it to 08:00 Austin (19:30 IST), or to record it for the India team and take their questions in writing.