9 Free Public Holiday & Time APIs With No Key (2026)


Finding a free holiday or time API is the easy 10 percent. The trap is the other 90: these APIs quietly disagree, and each one fails in a way that looks like success. On July 4, 2026 I asked sunrise-sunset.org for New York’s sunset and it told me 12:32 AM. Not an error. A clean HTTP 200 with a value that reads like a bug. I lost twenty minutes before I scrolled down and saw "tzid":"UTC" sitting in the same response.

A free public holiday or time API answers a temporal question (is this a business day, what is the local time, what is this date in another calendar) without a key, a signup, or a card. The nine below need none of those. I re-verified each with a live curl on July 4, 2026 (HTTP 200), and every response you see is the real output, trimmed for length, not paraphrased. If you build schedulers, billing and SLA calendars, booking flows, HR “next working day” logic, or i18n date displays, these are the lookups I reach for. And every one of them has a field that will silently lie to you if you skip it.

Let me be straight about the scope. I am not claiming I ran a holiday resolver across all 2,190 runs. That would be a lie. I called each endpoint once on July 4, 2026 with a single request. The only thing I am generalizing from 2,190 runs is narrower: enrichment data fails as a 200 with a wrong body far more often than as a clean error, which is exactly why the field-level gotchas below matter more than the endpoint list.

Here is the full set at a glance, grouped by the job each one does, then a section each.

#APIWhat it answersExample callNo key?
1Nager.DateCountry + year to public holidaysGET date.nager.at/api/v3/PublicHolidays/2026/USYes
2OpenHolidaysEU country to holidays with subdivisionsGET openholidaysapi.org/PublicHolidays?countryIsoCode=DE…Yes (EU only)
3gov.uk Bank HolidaysUK bank holidays, three divisionsGET gov.uk/bank-holidays.jsonYes (UK only)
4Enrico / KayaposoftCountry + year holidays (community data)GET kayaposoft.com/enrico/json/v2.0/?action=getHolidaysForYear…Yes
5TimeAPI.ioIANA zone to current time + DST flagGET timeapi.io/api/time/current/zone?timeZone=America/New_YorkYes
6WorldClockAPIAuthoritative UTC “now”GET worldclockapi.com/api/json/utc/nowYes (HTTP only)
7HebcalGregorian to Hebrew date + Torah portionGET hebcal.com/converter?…g2h=1Yes
8AladhanGregorian to Hijri dateGET api.aladhan.com/v1/gToH/04-07-2026Yes
9Sunrise-SunsetLat/lng to sunrise, sunset, day lengthGET api.sunrise-sunset.org/json?lat=40.71&lng=-74.00Yes (UTC default)

Here is what makes this a list and not one API. There is no single “what day is it” service. July 4, 2026 is a Saturday everywhere, but ask what that date means and the answers scatter: 19 Tamuz 5786 to Hebcal, 19 Muharram 1448 to Aladhan, one lone holiday (Juneteenth, weeks earlier) in Enrico’s US feed, and a New York sunset that is either 12:32 AM or 8:32 PM depending on one query parameter. Which source you hit depends on the question. Reading its fields correctly is the whole job.

Group A: public holidays (fill a calendar, check a business day)

Four keyless holiday sources, four different coverage models, and four different ways to get burned.

1. Nager.Date: country and year to a holiday list

Hand Nager a two-letter country code and a year and it returns that country’s public holidays. It is the broadest keyless holiday source I found, and the one I default to.

# runnable, read-only
curl "https://date.nager.at/api/v3/PublicHolidays/2026/US"
[{"date":"2026-01-01","localName":"New Year's Day","name":"New Year's Day",
  "countryCode":"US","global":true,"counties":null,"types":["Public","Bank"]},
 {"date":"2026-02-12","localName":"Lincoln's Birthday","name":"Lincoln's Birthday",
  "countryCode":"US","global":false,
  "counties":["US-CA","US-CT","US-IL","US-IN","US-KY","US-MI","US-NY","US-MO","US-OH"],
  "types":["Observance"]}]

New Year’s Day comes back with "global":true. Lincoln’s Birthday comes back with "global":false and a counties array of nine states. That is the gotcha, and it is a live one: state-only holidays sit in the same array as nationwide ones. Filter on "global":true (or read counties) or you will show a California observance to a user in Texas. While reading the raw body I also caught Good Friday listed twice, once per set of states that observe it, so a naive count is wrong too. There is a companion GET /api/v3/AvailableCountries that lists every supported code, also keyless. No published hard rate limit; it is an open-source project, so cache and be polite. Verify the current terms at date.nager.at.

When to use it: any country, when you want one consistent shape and can filter on global.

2. OpenHolidays: European holidays with subdivision detail

OpenHolidays is the one to reach for inside the EU, because it carries subdivision-level detail that Nager flattens. Its catch cost me an afternoon once, so I will lead with it: it is European only, and it tells you that with an empty 200, not a 404.

# runnable, read-only
curl "https://openholidaysapi.org/PublicHolidays?countryIsoCode=DE&languageIsoCode=EN&validFrom=2026-01-01&validTo=2026-12-31"
[{"startDate":"2026-01-01","endDate":"2026-01-01","type":"Public",
  "name":[{"language":"EN","text":"New Year's Day"}],"nationwide":true},
 {"startDate":"2026-01-06","type":"Public",
  "name":[{"language":"EN","text":"Epiphany"}],"nationwide":false,
  "subdivisions":[{"code":"DE-ST"},{"code":"DE-BW"},{"code":"DE-BY"}]}]

For Germany you get Epiphany flagged "nationwide":false with the exact states (Saxony-Anhalt, Baden-Wurttemberg, Bavaria) that observe it. Now watch the failure. Change countryIsoCode to US:

# runnable, read-only
curl "https://openholidaysapi.org/PublicHolidays?countryIsoCode=US&languageIsoCode=EN&validFrom=2026-01-01&validTo=2026-12-31"
[]

That is an HTTP 200 with an empty array. I only found this the first time because my calendar view rendered blank and I assumed my own code was broken. It was 200 the whole time; the coverage just stops at Europe’s edge. The endpoint also requires both validFrom and validTo, or it will not answer.

When to use it: EU countries where you need which region observes what. Not for the US or Asia.

3. gov.uk Bank Holidays: the UK, straight from the government

The UK government publishes its bank holidays as one static JSON file. No key, effectively unlimited, and it is the primary source rather than a scrape of one.

# runnable, read-only
curl "https://www.gov.uk/bank-holidays.json"
{"england-and-wales":{"division":"england-and-wales","events":[
  {"title":"New Year's Day","date":"2019-01-01","notes":"","bunting":true},
  {"title":"New Year's Day","date":"2026-01-01","notes":"","bunting":true},
  {"title":"Good Friday","date":"2026-04-03","notes":"","bunting":false},
  {"title":"Summer bank holiday","date":"2026-08-31","notes":"","bunting":true}]},
 "scotland":{"division":"scotland","events":[
  {"title":"2nd January","date":"2026-01-02","bunting":true},
  {"title":"St Andrew's Day","date":"2026-11-30","bunting":true}]},
 "northern-ireland":{"events":[]}}

Two things to read carefully. First, the array runs all the way back to 2019-01-01, so filter by year or you will process seven years of history. Second, this is one endpoint holding three different calendars: england-and-wales, scotland, and northern-ireland genuinely differ. Scotland has 2 January and St Andrew’s Day; England does not. Pick the division your user lives in. The bunting boolean is a real field, by the way, telling you whether flags are traditionally flown. Confirmed 2026 dates in my pull included 2026-01-01, 2026-04-03, 2026-05-04, 2026-05-25, 2026-08-31, and 2026-12-25.

When to use it: anything UK. Just pick the right division.

4. Enrico / Kayaposoft: wide country coverage, thin in places

Enrico covers a long list of countries from community-maintained data, which is its strength and its weakness. I include it with a warning attached, because it taught me a lesson worth passing on.

# runnable, read-only
curl "https://kayaposoft.com/enrico/json/v2.0/?action=getHolidaysForYear&year=2026&country=usa&holidayType=public_holiday"
[{"date":{"day":19,"month":6,"year":2026,"dayOfWeek":5},
  "name":[{"lang":"en","text":"Juneteenth National Independence Day"}],
  "holidayType":"public_holiday"}]

That is the entire response. One holiday for the whole of 2026 for the United States. Not one page, one holiday. I almost shipped that as “US holidays for 2026” before cross-checking against Nager, which returned the full set. Community data is sparse in spots, so treat Enrico as breadth-of-countries, not depth, and never trust a suspiciously short list from any single holiday source. Verify current coverage at kayaposoft.com/enrico.

When to use it: reaching a country the others do not cover, with a cross-check in place.

Group B: time zones and current time (schedulers, display, DST math)

Two keyless services answer “what time is it, really, over there,” and one of them does the DST arithmetic you would otherwise get wrong.

5. TimeAPI.io: current time for any IANA zone, with a DST flag

Give TimeAPI.io an IANA time zone name and it returns the current local time plus a dstActive flag. That flag is the reason to call it instead of hardcoding an offset.

# runnable, read-only
curl "https://timeapi.io/api/time/current/zone?timeZone=America/New_York"
{"year":2026,"month":7,"day":4,"hour":14,"minute":26,"seconds":30,
 "dateTime":"2026-07-04T14:26:30.2654687","timeZone":"America/New_York",
 "dayOfWeek":"Saturday","dstActive":true}

On July 4 it returned "dstActive":true, because New York is on daylight time in summer. If you had stored a fixed UTC offset for “New York” you would be an hour off for half the year. The service also does zone conversion over POST:

# runnable, read-only
curl -X POST "https://timeapi.io/api/conversion/converttimezone" \
  -H "Content-Type: application/json" \
  -d '{"fromTimeZone":"America/New_York","dateTime":"2026-07-04 14:00:00","toTimeZone":"Europe/London","dstAmbiguity":""}'
{"fromTimezone":"America/New_York","fromDateTime":"2026-07-04T14:00:00",
 "toTimeZone":"Europe/London",
 "conversionResult":{"dateTime":"2026-07-04T19:00:00","timeZone":"Europe/London","dstActive":true}}

2:00 PM in New York maps to 7:00 PM in London, with both ends flagged as on daylight time. One honest note: this is a live clock, so the hour and minute above have already moved. Run the curl yourself; free clock endpoints drift by the second and the shape is the point, not my timestamp. No key on the free tier; be reasonable and verify current limits at timeapi.io.

When to use it: any scheduler or display that must respect DST for a named zone.

6. WorldClockAPI: a plain authoritative “now”

WorldClockAPI is the minimalist option. It hands you an authoritative UTC “now” and a few useful extras, and nothing more.

# runnable, read-only
curl "http://worldclockapi.com/api/json/utc/now"
{"$id":"1","currentDateTime":"2026-07-04T18:26Z","utcOffset":"00:00:00",
 "isDayLightSavingsTime":false,"dayOfTheWeek":"Saturday","timeZoneName":"UTC",
 "currentFileTime":134276632058538289,"ordinalDate":"2026-185","serviceResponse":null}

Two caveats. First, the endpoint I hit is HTTP only, no TLS, so do not send anything sensitive and do not depend on it inside a strict HTTPS-only pipeline. Second, it is deliberately thin; there is no rich zone math here. What it is good for is a quick sanity anchor (“what is the authoritative now?”) plus the extras: ordinalDate gives you 2026-185 (day 185 of the year) and currentFileTime gives you a Windows FILETIME if you need one. Same live-clock caveat as above: re-run it, the timestamp has moved. Verify current status at worldclockapi.com.

When to use it: a lightweight UTC anchor and day-of-year, when you do not need per-zone conversion.

Group C: alternative calendars (i18n and religious calendars)

Two keyless converters turn a Gregorian date into a Hebrew or Islamic one. Both are signup-free, and both have a field that decides whether you are right or off by a day.

7. Hebcal: Gregorian to Hebrew, plus the weekly Torah portion

Hebcal converts a Gregorian date to the Hebrew calendar and throws in the week’s Torah reading for free.

# runnable, read-only
curl "https://www.hebcal.com/converter?cfg=json&gy=2026&gm=7&gd=4&g2h=1"
{"gy":2026,"gm":7,"gd":4,"afterSunset":false,"hy":5786,"hm":"Tamuz","hd":19,
 "hebrew":"…","events":["Parashat Pinchas"]}

July 4, 2026 is 19 Tamuz 5786, in the week of Parashat Pinchas. The field that matters is afterSunset. The Hebrew date rolls over at sunset, not midnight, so if your event happens in the evening you must pass gs=on (or set afterSunset correctly) or your conversion lands a day early. Miss that and the bug only shows up for evening timestamps, which is a miserable one to debug. Keyless; cache and be polite. Verify at hebcal.com.

When to use it: rendering or converting Hebrew dates, especially near sunset.

8. Aladhan: Gregorian to Hijri, and it tells you its method

Aladhan converts a Gregorian date to the Islamic (Hijri) calendar. Its honesty is the feature: it tells you which calculation method it used.

# runnable, read-only
curl "https://api.aladhan.com/v1/gToH/04-07-2026"
{"code":200,"status":"OK","data":{
 "hijri":{"date":"19-01-1448","day":"19",
  "month":{"number":1,"en":"Muharram","days":29},
  "year":"1448","designation":{"abbreviated":"AH"},"method":"HJCoSA"},
 "gregorian":{"date":"04-07-2026","weekday":{"en":"Saturday"}}}}

July 4, 2026 comes back as 19 Muharram 1448 AH, and the response labels its method as HJCoSA. Here is the caveat that keeps you honest: the Hijri calendar is calculation-method dependent, and month length flips between 29 and 30 days. The API is transparent about which method it applied, so do not treat a single call as the one canonical answer for religious observance, which may depend on local moon sighting. Same date, two calendars: Aladhan says 19 Muharram, Hebcal says 19 Tamuz, and both are correct in their own system.

When to use it: displaying or storing Hijri dates, with the method recorded alongside.

Group D: solar day-length (the bonus temporal utility)

One more keyless endpoint, and it is the one that opened this post.

9. Sunrise-Sunset: sunrise, sunset, and the UTC trap

Sunrise-sunset.org returns sunrise, sunset, solar noon, and day length for any latitude and longitude. It is genuinely useful and it hides the single best example of a silent-wrong response on this whole list.

# runnable, read-only
curl "https://api.sunrise-sunset.org/json?lat=40.7128&lng=-74.0060&date=2026-07-04"
{"results":{"sunrise":"9:28:49 AM","sunset":"12:32:13 AM","solar_noon":"5:00:31 PM",
 "day_length":"15:03:24"},"status":"OK","tzid":"UTC"}

A sunset at 12:32 AM. For New York in July, that is nonsense on its face, and it is a clean HTTP 200. The tell is "tzid":"UTC": the times are in UTC by default, and New York in summer is four hours behind. Pass the zone and it snaps into place:

# runnable, read-only
curl "https://api.sunrise-sunset.org/json?lat=40.7128&lng=-74.0060&date=2026-07-04&tzid=America/New_York"
{"results":{"sunrise":"5:28:49 AM","sunset":"8:32:13 PM",
 "day_length":"15:03:24"},"status":"OK","tzid":"America/New_York"}

Now sunrise is 5:28 AM and sunset is 8:32 PM, which is a real July day in New York. Note day_length was correct both times (15 hours, 3 minutes); only the wall-clock fields shifted. Pass formatted=0 if you want ISO 8601 timestamps instead of the “AM/PM” strings. This is the failure mode the whole post is about: not a 500, not a 404, just a 200 with values that look broken until you read one field.

When to use it: daylight-aware scheduling, solar features, “golden hour” logic. Always send tzid.

Why some “free” holiday and time APIs did not make the cut

The list stays honest by showing what it rejected. Every code below is from a live curl on July 4, 2026.

  • Calendarific (calendarific.com/api/v2/holidays?country=US&year=2026) returned HTTP 401 {"meta":{"code":401,"error_type":"auth failed","error_detail":"Missing or invalid api credentials..."}}. It is a popular holiday API, but it wants a key. Excluded.
  • WorldTimeAPI.org (worldtimeapi.org/api/timezone/America/New_York) was the classic keyless time option for years. It returned HTTP 000, connection failed, on repeated retries over both HTTPS and HTTP, including a fresh re-curl right before publishing. It is unreachable at test time, so it stays off the list. Use TimeAPI.io or WorldClockAPI instead, and if worldtimeapi.org comes back, verify it yourself before wiring it in.
  • ipgeolocation.io time API is key-gated per its docs, so it never made the shortlist for a “no key” roundup.

Keeping these right under real traffic

The endpoint is the easy part. Reading the fields is the job. A few habits that have saved me:

Filter on the scope field, every time. Nager gives you global. OpenHolidays gives you nationwide and subdivisions. gov.uk gives you three divisions. Skip that field and you will show a regional holiday to a national audience, or count Good Friday twice. The scope field is the answer, full stop. Read it every time.

Always pass the zone. Sunrise-Sunset defaults to UTC. Hebcal rolls at sunset via afterSunset. Aladhan records a method. Time is never “just a number,” and the query parameter you omit is the bug you ship. Send tzid, send gs, read method.

Never trust a single temporal source blind. Enrico handed me one US holiday for a year. OpenHolidays handed me an empty array for the US. Both were HTTP 200. Cross-check a suspiciously short or empty list against a second source before it reaches a user. This is the same silent-wrong trap I hit with keyless geocoding: the danger is not the honest error, it is the confident 200 with the wrong body.

Cache what is stable, re-fetch what moves. Holiday lists and calendar conversions for a fixed date do not change, so cache them hard. The two live clocks (TimeAPI.io, WorldClockAPI) move by the second, so never cache “now.” Mixing those two policies up is its own class of bug.

For context, not a claim of scale: I build web-scraping and data-enrichment tool layers, currently 2,190 runs across 32 actors in production, and the output is always a list of rows that need enrichment columns. Location was the geocoding column. Security posture was the CVE column. Time and calendar is this one. Same keyless, no-card enrichment layer, different question, and the same failure mode every time: a 200 that is empty or wrong, never an honest 500.

FAQ

What is the best free public holiday API with no API key? It depends on coverage. Nager.Date is the broadest for country-plus-year lists worldwide, OpenHolidays gives the richest EU subdivision detail (but returns an empty 200 outside Europe), and gov.uk covers the UK straight from the government. All are keyless, no signup.

Is there a free time zone API without an API key? Yes. TimeAPI.io returns the current time for any IANA zone with a dstActive flag and does zone conversion over POST. WorldClockAPI gives a plain authoritative UTC “now” (over HTTP only). Both are keyless.

Why does the holiday API return an empty list for the US? OpenHolidays covers European countries only. A request with countryIsoCode=US returns HTTP 200 with an empty array [], not a 404, so it looks like “no holidays” when it means “no coverage.” Use Nager.Date or Enrico for the US.

How do I get sunrise and sunset times for free? sunrise-sunset.org, keyless, by latitude and longitude. The times are UTC by default, so a New York sunset can read as “12:32 AM.” Pass tzid=America/New_York for local time, and formatted=0 for ISO timestamps.

Can I convert a date to the Hebrew or Islamic calendar without a key? Yes. Hebcal converts Gregorian to Hebrew (watch the afterSunset field, since the Hebrew day rolls at sunset) and adds the weekly Torah portion. Aladhan converts Gregorian to Hijri and records the calculation method it used. Both are keyless.


Written by Aleksei Spinov. I build web-scraping and data-enrichment tool layers, currently 2,190 runs across 32 actors in production. Every API above was re-verified with a live curl (HTTP 200, real response) on July 4, 2026 before publishing; responses are trimmed, not paraphrased. Holiday and calendar values for a fixed date are stable, but the two live clocks (TimeAPI.io and WorldClockAPI) move by the second, so run the curl yourself before you wire one in. Drafted with an AI assistant, fact-checked and edited by me.

Follow for the next batch of keyless tools I test for the enrichment layer. And tell me: which temporal source has quietly lied to you with a clean 200, and what field finally gave the bug away? I read every comment.


More production scraping tips: t.me/scraping_ai