Opening Hours to JSON - Normalize Google Maps Business Hours avatar

Opening Hours to JSON - Normalize Google Maps Business Hours

Pricing

$0.50 / 1,000 place normalizeds

Go to Apify Store
Opening Hours to JSON - Normalize Google Maps Business Hours

Opening Hours to JSON - Normalize Google Maps Business Hours

Google Maps and Yelp give you hours as messy text. Pick the scraper's dataset and get weekly JSON, schema.org openingHoursSpecification and an open-now flag per place, with 24/7, closed and split-shift handling and day names in many languages. No re-scraping.

Pricing

$0.50 / 1,000 place normalizeds

Rating

0.0

(0)

Developer

mohamed alaya

mohamed alaya

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

16 days ago

Last modified

Share

Turns the messy opening-hours text from Google Maps, Yelp and other place scrapers into clean weekly JSON, schema.org openingHoursSpecification and an "open now" flag. Built for people who already scraped thousands of places and now have to make sense of "Mon-Fri 9 AM to 5 PM, Sat 10-2" in ten different formats.

Quick start: use it after a Google Maps scraper

  1. Run your Google Maps scraper (Compass, Lukas Krivka or any other).
  2. Start this Actor, pick that run's dataset in Google Maps / places dataset(s).
  3. Download the output as JSON, CSV or Excel.

Run it with empty input to see a demo of 8 places in English, French, German and Spanish.

Input examples

1. Dataset from a Google Maps scraper

{ "datasets": ["<pick with the dataset picker>"] }

2. Pasted rows, with coordinates for the time zone

{
"rows": [
{ "title": "Joe's Pizza", "openingHours": "Mon-Fri 9:00-17:00; Sat 10:00-14:00; Sun closed", "location": { "lat": 40.73, "lng": -74.0 } }
]
}

3. Plain hours strings, one fixed time zone, test a specific moment

{
"rows": ["lundi au vendredi 9h-18h, samedi 10h-13h", "Open 24 hours"],
"defaultTimezone": "Europe/Paris",
"checkAt": "2026-12-24T18:30:00+01:00"
}

Input guide

FieldWhat it does
datasetsPick one or more datasets (the picker gives the Actor read permission).
rows / rowsCsvPaste JSON rows, a JSON array or a CSV with a header row.
hoursFieldName of the column holding the hours. Empty = auto-detect openingHours, opening_hours, hours, businessHours, workingHours and similar.
defaultTimezoneIANA zone (e.g. Europe/Paris) used when a row has no coordinates or time zone.
checkAtISO date-time to test open/closed at, in each place's own time zone. Empty = now.
keepAllFieldsCopy every original column to the output (default on).
maxRowsSafety limit per run.

What it understands

  • Google Maps openingHours arrays ({day, hours}), plain text blocks, compact text such as Mo-Fr 09:00-17:00; Sa 10:00-14:00 (OSM-style short day names), Yelp open arrays (start/end/day), and objects keyed by day name.
  • 12-hour and 24-hour times, 9-5, 9h30, 09.00, 9:00 Uhr, narrow no-break spaces and en-dashes from Google.
  • Split shifts, overnight hours (10 AM to 4 AM), Open 24 hours, 24/7, Closed, "permanently/temporarily closed".
  • Day names in English, French, German, Spanish, Italian, Portuguese, Dutch, Swedish, Danish/Norwegian, Polish, Turkish, Indonesian, Russian, Arabic, Chinese and Japanese, plus "weekdays", "weekends", "daily".

Output

One row per input row. Your original fields are kept and these are added:

FieldMeaning
hoursStatusparsed, partial (some lines not understood), unparsed or no-hours-field.
openingHoursTextCompact text, e.g. Mo-Fr 09:00-17:00; Sa 10:00-14:00; Su off.
hoursWeekly{monday:[{open:"09:00",close:"17:00"}], ...}. An empty list means closed. close:"24:00" = midnight, overnight:true = ends the next day.
hours_mon ... hours_sunOne flat text column per day, handy for CSV/Excel.
openingHoursSpecificationschema.org array, ready for JSON-LD.
is24x7, weeklyOpenHours24/7 flag and total open hours per week.
timezone, timezoneSourceIANA zone from a field, from coordinates, or your fallback.
isOpenNow, openStatusOpen now at checkAt (or now), e.g. Open until 17:00 or Closed, opens Tue 09:00. null if the time zone is unknown.
assumedClosedDaysDays that were not mentioned in the text and are treated as closed.
unparsedLinesLines the parser could not read, so you can review them.

Sample row (shortened):

{ "title": "Boulangerie Paul", "hoursStatus": "parsed", "openingHoursText": "Mo-Fr 07:00-20:00; Sa 08:00-19:00; Su off", "timezone": "Europe/Paris", "timezoneSource": "coordinates", "isOpenNow": false, "openStatus": "Closed, opens Mon 07:00", "weeklyOpenHours": 91 }

Use it with

Google Maps scraper -> this Actor -> your CRM, delivery app or local-SEO tool. It pairs naturally with the Google Maps Emails Actor from the same author: enrich the contacts, normalize the hours.

FAQ

Does it call any website or API? No. Parsing and time zone lookup are offline; the only read is your own dataset.

Why is isOpenNow null? The row had no coordinates or time zone field and you set no fallback time zone.

Is it OSM opening_hours syntax? It reads the common short form (Mo-Fr 09:00-17:00) but not the full OSM grammar (public holidays, week numbers, months).

Honest limits

  • Text it cannot read ("Call for hours", seasonal rules, holiday exceptions) is reported in unparsedLines, never guessed. Holiday and special-day hours are not modelled.
  • Bare 9-5 is read as 09:00-17:00; ambiguous short forms in other languages may be wrong, check hoursStatus and the sample before bulk use.
  • Time zones come from coordinates (offline lookup near borders can be off).

Price

Pay per event: $0.0005 per place normalized (only rows where hours were found and delivered; unreadable or hour-less rows are free). 1,000 places = $0.50, 50,000 places = $25.