What is in the file
An .ics file is plain text. It wraps everything in a VCALENDAR, and each event is a VEVENT block with a handful of properties: a UID that identifies it across systems, a SUMMARY for the title, a DTSTART, either a DTEND or a DURATION, and optionally a RRULE describing how it repeats.
You can open one in a text editor and read it. Doing that once explains more about calendar syncing than any amount of documentation, because every import problem is visible in the file if you know what to look at.
The four fields that cause almost every problem
DTSTART with no timezone. A start time can be written three ways: with a TZID naming a zone, with a trailing Z meaning UTC, or as a bare local time meaning nothing in particular. The third is called a floating time, and every reader interprets it in whatever zone it feels like. This is the root cause of most “imported an hour out” reports.
DTEND versus DURATION. Both express how long an event is. They differ across a daylight-saving change: a two-hour event stored as a duration stays two hours, while one stored as an end time comes out an hour short or long. Most exporters use DTEND, which is why so many calendars are wrong for one weekend a year.
RRULE with an ordinal. BYDAY=2TU means “the second Tuesday”. A reader that only handles frequency and interval treats it as “monthly” and produces the wrong dates without any error at all.
EXDATE. This lists occurrences that have been cancelled. It is common for a reader to parse it and then never apply it — leaving a cancelled class showing on your public page.
Publishing one from WordPress
The other direction matters more than people expect. If your site publishes its own .ics feed, a regular at your venue can subscribe once in their phone's calendar and get every future date, including changes, without ever visiting your website again. That is a better relationship with a customer than making them check a page each week.
It is also the strongest test of whether a calendar's date handling is correct: subscribe to your own feed from Google Calendar, and if the times come back right, the underlying model is sound. Another calendar is a harsher judge than any test suite.
Why the reader above cannot fetch a URL
Browsers refuse to fetch a calendar feed from another domain unless that domain explicitly permits it, and none of the calendar providers do. A website claiming to read your feed URL in the browser is proxying it through a server you cannot see. A WordPress plugin has no such problem, because the fetch happens on your own server.