UTC+05:45 is worth 15 minutes a day; New York costs 105 on EST

  • Rujen Shakya
  • 14 min read

The IANA time zone database gives Nepal three lines, and the last one begins 5:45. Every argument here comes out of those four characters, and most are not the ones people expect.

Nepal Time is UTC+05:45, so a Kathmandu day of 10:00 to 18:00 overlaps a London winter day by 195 minutes and New York by none. Round it to a whole hour and the sum returns 180: 15 minutes a day go unbooked. Reaching New York on EST means working to 19:45 NPT, 105 minutes past the nominal close.

Why Nepal Time is UTC+05:45 and not UTC+06:00

Nepal runs 5 hours 45 minutes ahead of UTC with no daylight saving rule beside it, and the asia file of the IANA time zone database dates the change to 1986. The whole entry is three lines:

text

# Zone	NAME		STDOFF	RULES	FORMAT	[UNTIL]
Zone	Asia/Kathmandu	5:41:16 -	LMT	1920
			5:30	-	%z	1986
			5:45	-	%z

Local mean time is that 5:41:16, and it reconstructs from zone1970.tab, which puts Kathmandu at 85°19′ E. Longitude 85 + 19/60 = 85.316667 degrees; 86,400 ÷ 360 = 240 seconds per degree; 85.316667 × 240 = 20,476 seconds, or 5:41:16 exactly.

Now the part that gets told backwards. UTC+05:45 is 20,700 seconds, so 20,700 − 20,476 = 224 and the civil clock sits 3 minutes 44 seconds ahead of Kathmandu’s mean solar time. UTC+05:30 was 19,800, so 20,476 − 19,800 = 676 seconds, 11 minutes 16 seconds behind. 676 ÷ 224 = 3.02, so 1986 cut the error to roughly a third and the 45 minutes is the quarter-hour nearest Kathmandu’s meridian. Why anyone made the change is not in the database, and I won’t invent one.

zdump -v Asia/Kathmandu prints fourteen lines and two of them matter. (The zone answers to Asia/Katmandu too, the old misspelling, still a live Link in the backward file — hold onto that, it comes back.)

console

$ zdump -v Asia/Kathmandu | grep '198[56]'
Asia/Kathmandu  Tue Dec 31 18:29:59 1985 UT = Tue Dec 31 23:59:59 1985 +0530 isdst=0 gmtoff=19800
Asia/Kathmandu  Tue Dec 31 18:30:00 1985 UT = Wed Jan  1 00:15:00 1986 +0545 isdst=0 gmtoff=20700

Both lines come from the macOS 26.6 system copy of tzdata, release 2026e, read on 29 October 2026.

Fifteen minutes of that night never existed.

Which time zones have a 45-minute UTC offset?

Three, and only one of them moves. Asia/Kathmandu sits at 5:45, Australia/Eucla at 8:45 and Pacific/Chatham at 12:45. Kathmandu’s RULES column is a bare -; Eucla names the AW rule, whose newest line stops at 2009, so nothing in it has fired since; Chatham names a rule with two lines running to max, so through the southern summer it is on 13:45. Python 3.14.5’s zoneinfo read the same macOS system tzdata 2026e and returned 13:45:00 for Chatham on 29 October 2026, 8:45:00 for Eucla the same day.

The count is checkable. Parse every Zone record across the seven regional files the database ships, take each one’s final continuation line, and tzdata 2026f gives 312 records: 14 carry an offset that is not a whole hour, 3 of those exactly :45.

Nepal has no letters. The FORMAT column is %z, and TZ=Asia/Kathmandu date '+%Z' prints +0545 rather than NPT. The database’s own theory.html gives the rule under ‘Time zone abbreviations’: ‘If there is no common English abbreviation, use numeric offsets like -05 and +0530 that are generated by zic’s %z notation.’

Cron has no time zone field

The POSIX crontab specification in IEEE Std 1003.1-2024 defines five time fields and never mentions a time zone, TZ or local time anywhere on the page. Its INPUT FILES section runs minute through to ‘Day of the week ([0,6] with 0=Sunday)’.

Everything else is an extension, and each draws the line differently. cronie’s crontab(5) defines CRON_TZ per table and says where the effect stops: ‘The time used for writing into a log file is taken from the local time zone, where the daemon is running.’ So the job fires on Kathmandu time and the line recording it does not. Kubernetes took until v1.27 to mark .spec.timeZone stable, and its ‘Unsupported TimeZone specification’ section in the CronJob documentation, well below the schedule syntax, rejects cronie’s spelling outright: ‘Specifying a timezone using CRON_TZ or TZ variables inside .spec.schedule is not officially supported (and never has been). If you try to set a schedule that includes TZ or CRON_TZ timezone specification, Kubernetes will fail to create or update the resource with a validation error.’ systemd couldn’t put a calendar event outside UTC or the local zone until v235, which the project’s NEWS file dates to October 2017, not the v252 I had it filed under. Cloudflare Workers Cron Triggers take no zone at all: ‘Cron Triggers execute on UTC time.’

I went looking for the claim this piece was commissioned to make and couldn’t stand it up. Scheduler pickers that offer only whole hours and so cannot express Nepal: I checked on 29 October 2026 and found none. Kubernetes, systemd, GitHub Actions and EventBridge Scheduler all take zone names, Asia/Kathmandu among them. The whole-hour picker is a thing I remember meeting and can’t actually produce on demand. What I can produce is the database’s fixed-offset family: etcetera defines 27 Etc/GMT* zones from -12 to +14, not one with a minutes component, and the signs run backwards — TZ=Etc/GMT+5 date '+%z' prints -0500.

Work out the Kathmandu to London and Kathmandu to New York overlap in minutes

195 minutes a day with London in the northern winter, 255 in the summer, and zero with New York all year. Two numbers below are chosen, not observed: a Kathmandu day of 10:00 to 18:00 NPT and a counterparty day of 09:00 to 17:00 local, picked so the division can be checked.

Work in minutes past midnight UTC, because wall clocks are where the mistake lives. UTC+05:45 is 345 minutes, so Kathmandu’s 10:00 to 18:00 NPT is 600 − 345 = 255 through 1080 − 345 = 735, or 04:15 to 12:15 UTC. London’s 09:00 to 17:00 GMT is 540 to 1020. The overlap is min(735, 1020) − max(255, 540) = 735 − 540 = 195 minutes.

Same answer by a route that never touches UTC: London’s 09:00 GMT lands at 14:45 NPT, Kathmandu shuts at 18:00, and 18:00 − 14:45 = 3 hours 15 minutes = 195 minutes. On BST it lands at 13:45 and gives 255.

12:15 UTC has earned a name: the Kathmandu cut-off, 18:00 NPT in the clock both sides share. A counterparty whose day starts before the cut-off is reachable inside the Kathmandu day, and London’s starts at 09:00 UTC in winter and 08:00 in summer, so London always is. New York starts after it: 09:00 EST is 14:00 UTC and 09:00 EDT is 13:00 UTC, so the live overlap is zero and somebody has to stay late. An overnight refresh window and a handover window are different problems.

Reaching New York means buying evening. Call it the handover tax: the minutes a Kathmandu working day has to run past its nominal close to reach the first minute of a named counterparty’s working day. The tolerance comes first: 30 minutes of live overlap a day, because a written handover plus one short call clears a blocked ticket the same day instead of the next. The distribution is the counterparty’s start in UTC — London at 09:00 or 08:00, New York at 14:00 or 13:00. The value falls out of the conversion: 09:00 EST lands at 19:45 NPT, so 19:45 − 18:00 = 105 minutes; 09:00 EDT lands at 18:45 NPT, so 45. Add the tolerance and Kathmandu closes at 20:15 NPT in a US winter, 19:15 in a US summer.

The tax, then. Zero to London all year, 45 to New York on EDT, 105 on EST. The 60-minute gap, 105 − 45, is the US daylight saving shift and Nepal contributes nothing to it; at UTC+06:00 the tax would be 60 and 120, and at UTC+05:00 it would be 0 and 60. So the 45 minutes buys 15 against the whole hour above and costs 45 against the one below.

What rounding UTC+05:45 to the nearest hour costs a team each day

Fifteen minutes a day, and they’re 15 you already have and never booked, not 15 you lost. Round UTC+05:45 up to UTC+06:00 and Kathmandu’s day becomes 04:00 to 12:00 UTC, London’s is still 540 to 1020, and the overlap is 720 − 540 = 180 against a true 195.

Two divisions, two denominators. The shortfall is 15 of the true 195, so 15 ÷ 195 = 7.69% of the real window goes unbooked; against the rounded estimate, 195 ÷ 180 = 1.0833, so the window is 8.33% bigger than the plan says. Print both, or somebody decides one is a typo.

Round the other way and it costs more. At UTC+05:00 London’s 09:00 lands at 14:00 NPT and the sum returns 240 against a true 195 — 45 minutes of overlap that does not exist, and the expensive part isn’t the arithmetic but the promise somebody makes out of it.

The daily figure climbs a short ladder on two chosen multipliers: five contact days a week, and 48 working weeks, which is 52 less four weeks of leave. 15 minutes a day × 5 = 75 minutes a week; 75 ÷ 60 = 1.25 hours a week; 1.25 × 48 = 60 hours a year; 60 ÷ 8 = 7.5 eight-hour days a year the plan never had. Seven and a half days is the bill for real time in another currency.

Stretch the Kathmandu day to 10:00–20:00 and the intuition breaks. True overlap with London on GMT becomes 315, the UTC+06:00 sum returns 300, and the gap is still exactly 15. A longer day does not enlarge the error, because it is a boundary offset and not a rate; what moves is the share, from 8.33% to 15 ÷ 300 = 5.00%.

Derate the tolerance and New York hardly stirs. Cut the 30 minutes of live overlap to 10, a 3x derating, and the winter close moves from 20:15 to 19:55 NPT: 135 minutes of evening becomes 115, down 14.8%, for a meeting a third as long. The decision doesn’t flip. The 105 minutes is a toll paid before the window opens; the only lever is moving the Kathmandu day.

A Sunday to Friday working week breaks the cron weekday preset

We work Sunday to Friday, which makes * * * * 1-5 the wrong five days, and 1-5 is the expression cronie’s own example crontab comments as ‘run at 10 pm on weekdays’. Sunday to Friday under POSIX cron, where the day-of-week field is ‘[0,6] with 0=Sunday’, is 0-5. On Cloudflare Workers Cron Triggers it is 1-6, because Cloudflare renumbers the week and says so: ‘Days of the week go from 1 = Sunday to 7 = Saturday, which is different on some other cron systems (where 0 = Sunday and 6 = Saturday).’ A 1-5 copied between the two is Monday-to-Friday on one and Sunday-to-Thursday on the other, and nothing raises an error.

The locale data is wrong in a subtler way. Unicode CLDR’s supplementalData.xml has Nepal’s first day of the week right in its weekData block (NP sits in the territory list on <firstDay day="sun" .../>) and its weekend wrong, because NP appears in no weekendStart or weekendEnd element and so inherits the world default territory 001, Saturday to Sunday. India is special-cased on <weekendStart day="sun" territories="IN UG"/>. Nepal isn’t. Ten seconds in a terminal shows it:

console

$ node -e "console.log(new Intl.Locale('ne-NP').getWeekInfo())"
{ firstDay: 7, weekend: [ 6, 7 ] }
$ node -e "console.log(new Intl.Locale('en-IN').getWeekInfo())"
{ firstDay: 7, weekend: [ 7 ] }

The day numbers there are ECMA-402’s, not CLDR’s: getWeekInfo() returns ISO 8601 numbering, 1 = Monday through 7 = Sunday, while CLDR writes sat and sun as names. So 6 is Saturday, 7 is Sunday, and every runtime built on that data believes Sunday is a weekend day in Nepal. It is a working day. Anything that greys out non-working days, counts business days or declines to page an on-call engineer gets Sunday wrong by default; that output is Node v24.11.1 on 29 October 2026. Six Kathmandu working days against five London ones intersect in five, so 5 ÷ 6 = 83.3% of our week is contactable and the sixth day adds no contact day.

And I cannot cite a law for any of it. Section 40 of Nepal’s Labour Act, 2017 (2074) says only that ‘A labour shall get the weekly leave of one day in each month’, and the word Saturday appears nowhere in the Act. The Saturday weekend is how the country runs, not what the statute says, and those are different kinds of fact.

Use the IANA zone name, not a stored UTC offset

Store Asia/Kathmandu and America/New_York as strings and let the runtime resolve them, because the 45 minutes is the stable half of this problem and the counterparty’s daylight saving is the half that moves. A good engineer would store +05:45 instead, for real reasons: one column, it sorts, no zone database needed, and for Nepal it is never wrong, since the zone has not moved since 1986.

Then the number. A stored offset is right on the Nepal side and wrong by a full hour on the other for most of the year: New York ran on EDT from 8 March to 31 October in 2026, which is 24 days of March plus April through October entire, 238 of 365. 60 ÷ 15 = 4, so that error is four times the 15-minute one this whole piece is about. It wins in one condition: a runtime whose zone database can’t be updated, an embedded target or an air-gapped image, where a frozen wrong offset beats a frozen stale one.

The wire format knows its own limit. RFC 3339 fixes an offset at ("+" / "-") time-hour ":" time-minute, and Section 5.8, well past where anybody stops reading, prints a timestamp whose real offset the grammar cannot hold and says so: ‘Standard time in the Netherlands was exactly 19 minutes and 32.13 seconds ahead of UTC by law from 1909-05-01 through 1937-06-30. This time zone cannot be represented exactly using the HH:MM format, and this timestamp uses the closest representable UTC offset.’ Nepal’s quarter-hour fits that grammar. A 19-minute-32-second offset did not.

Zone names aren’t free. They need a scheduler that takes them, which rules out Cloudflare Workers Cron Triggers and puts a floor under Kubernetes at v1.27 and systemd at v235. They need a zone database in the image, which could be stale and will be the moment nobody owns the rebuild. Whatever stores the string must also accept Asia/Katmandu, because backward still links it. What moves under a schedule is never Nepal: the US and the EU change on different Sundays, so for 28 days of 2026 — 8 to 28 March, then 25 to 31 October — New York and London sat four hours apart rather than five.

And if the only counterparty is in the UK, I would not build anything for this. The tolerance that decides it: tooling earns its keep when the rounding changes an answer, not when it makes one slightly wrong. Rounding UTC+05:45 up moves the Kathmandu cut-off from 12:15 UTC to 12:00, so the counterparties whose reachability flips are the ones starting inside that 15-minute band. London starts at 08:00 or 09:00 UTC and New York at 13:00 or 14:00, so both clear it by 45 minutes or more, and we haven’t built anything. It’s really just a calendar entry and a habit of rounding the right way. Microsoft Learn’s Configure scheduled refresh page sets the scale: Power BI targets a start within 15 minutes of the scheduled slot, ‘but a delay of up to one hour can occur if the service can’t allocate the required resources sooner’. Sixty minutes of documented slack against a 15-minute rounding error, the same four-to-one as before. Fixing the 15 before the 60 is the wrong order. The day-of-week numbering is the part worth paying for: a one-line fix, wrong in production in more places than anyone has counted, and the only piece of this we treat as a standing check on a software delivery engagement.

Tell us what’s broken.

Twenty minutes, no deck. We’ll tell you straight whether this is work we should be doing, and if it isn’t, we usually know who should.

We come back within one business day.