TL;DR — webOS's WebAppManager engine resolves the default Intl time zone to Etc/Unknown, which ICU formats as UTC. Date is perfectly correct; only Intl is broken. jellyfin-web renders every clock through Intl, so they all shift together by your UTC offset. Nothing about your TV, server, or container time zone is misconfigured. Fix: pin the zone from JavaScript (webos-intl-timezone-fix.js).
In the Jellyfin app on an LG Smart TV, every rendered time is behind (or ahead) by exactly your UTC offset:
- the header clock next to the profile image
- "Ends at HH:MM" on media detail pages
- "Ends at HH:MM" in the playback info / OSD
Observed with a UTC+03:30 device: real time 17:10, Jellyfin showed 13:40.
Everything else about the app works normally. Other Jellyfin clients on the same server (desktop browser, phone, Android TV) show the correct time.
Worth stating plainly, because these are the obvious suspects and all of them are dead ends:
- ❌ The TV's time zone setting. It is correct, and setting it again changes nothing.
- ❌ The Jellyfin server's
TZenv var or the host's/etc/timezone. - ❌ Jellyfin's user display preferences.
- ❌ A stale app process holding an old
TZ. Force-closing and relaunching the app does not help. - ❌ Anything server-side at all. The server is only serving UTC timestamps over the API, which is correct and normal — clients are supposed to localize them.
Do not diagnose this using the TV's Web Browser app. webOS runs two different web engines:
| App | User-Agent | Intl default zone |
toLocaleTimeString() |
|---|---|---|---|
| Web Browser | ...(Linux; NetCast; U)... Colt/2.0 |
undefined |
✅ correct local time |
| Jellyfin (and other web apps) | ...(Web0S; Linux/SmartTV)... WebAppManager |
Etc/Unknown |
❌ UTC |
Point the TV's browser at a page that prints new Date() and the TV looks completely healthy. The bug only reproduces inside a webOS app.
Captured from inside the running Jellyfin app on an LG C5 (webOS, Chrome 120 / WebAppManager), device zone UTC+03:30:
{
"toString": "Thu Aug 06 2026 17:35:52 GMT+0330 (+03:30)",
"offsetMin": -210,
"getHours": 17,
"bare_localeTime": "2:05:52 PM",
"opt_localeTime": "2:05 PM",
"tz_UTC": "2:05 PM",
"tz_Tehran": "5:35 PM",
"intlTZ": "Etc/Unknown",
"intlLocale": "en-US",
"ua": "Mozilla/5.0 (Web0S; Linux/SmartTV) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.270 Safari/537.36 WebAppManager"
}Reading that:
toString,offsetMinandgetHoursare all correct — the engine knows it is UTC+03:30.bare_localeTimeis identical totz_UTC— proof that the default zone is being treated as UTC.tz_Tehran(an explicitly passed IANA zone) is correct — so ICU has the zone data; it just can't resolve the default.intlTZisEtc/Unknown— the root cause. It is ICU's "I have no idea" sentinel, and it behaves as UTC.
The webOS Jellyfin client (jellyfin-webos) is a thin wrapper. Its README:
This is a small wrapper around the web interface provided by the server … the app hands off control to the hosted webUI.
So the code running on your TV is your server's own jellyfin-web, executing under webOS's WebAppManager engine. That engine fails to hand ICU a usable default time zone, so Intl.DateTimeFormat().resolvedOptions().timeZone comes back as Etc/Unknown and every Intl format call without an explicit timeZone renders in UTC.
jellyfin-web formats all of its clocks through Date.prototype.toLocaleTimeString() / toLocaleString() (see datetime.js), which are Intl-backed. Hence: every clock, all shifted by the same amount, while the underlying Date objects are correct.
Because it is a wrapper, the fix can be injected from the server — no need to modify, sideload, or root anything on the TV.
webos-intl-timezone-fix.js wraps Intl.DateTimeFormat and the three Date.prototype.toLocale*String methods so that a missing timeZone option defaults to your zone.
Set TIME_ZONE at the top of the file to your IANA zone (Europe/Berlin, America/New_York, Asia/Tehran, …). It cannot be auto-detected — the engine's inability to report it is the bug.
It is safe to apply server-wide because it gates twice before patching anything:
- the engine's own
Intlformatting must disagree withDate.prototype.getHours(), and - your configured zone must match the device's real local time.
On a healthy client both gates fail and the script returns immediately, leaving Intl untouched. Verified: on desktop Chrome/Edge the marker window.__webosIntlTimeZonePatched stays undefined and formatting is unchanged.
It is also idempotent (guarded by that same marker), and it deliberately preserves RangeError on invalid locales, because jellyfin-web's datetime.js feature-detects localization support with toLocaleTimeString('i') and expects it to throw.
- Install the JavaScript Injector plugin (Dashboard ▸ Plugins).
- Dashboard ▸ Plugins ▸ JavaScript Injector ▸ add a custom script.
- Paste the file contents, set Enabled, leave Requires Authentication off so it loads before login too.
- Save.
Takes effect on the client's next load — no Jellyfin restart required. Relaunch the Jellyfin app on the TV.
Useful for scripting it. The plugin stores scripts in its plugin configuration, so read-modify-write:
JELLYFIN_URL="http://your-server:8096"
API_KEY="your-api-key" # Dashboard > API Keys
PLUGIN_ID="f5a34f7b2e8a4e6aa7223a216a81b374" # JavaScript Injector
AUTH="Authorization: MediaBrowser Token=${API_KEY}"
curl -fsS -H "$AUTH" "${JELLYFIN_URL}/Plugins/${PLUGIN_ID}/Configuration" -o config.json
python3 - <<'PY'
import json
config = json.load(open('config.json'))
source = open('webos-intl-timezone-fix.js', encoding='utf-8').read()
entries = config.setdefault('CustomJavaScripts', [])
name = 'webOS Intl timezone fix'
entry = next((e for e in entries if e.get('Name') == name), None)
if entry is None:
entry = {'Name': name, 'Id': 'webos-intl-timezone-fix'}
entries.append(entry)
entry.update({'Script': source, 'Enabled': True, 'RequiresAuthentication': False})
json.dump(config, open('config.json', 'w'))
PY
curl -fsS -X POST -H "$AUTH" -H "Content-Type: application/json" \
--data-binary @config.json "${JELLYFIN_URL}/Plugins/${PLUGIN_ID}/Configuration"Read-modify-write matters: a blind POST would drop entries other plugins have registered there.
Add to jellyfin-web's index.html before </head>:
<script src="/web/webos-intl-timezone-fix.js"></script>Confirm the script is actually being served:
curl -s "http://your-server:8096/JavaScriptInjector/public.js" | grep -c webosIntlTimeZonePatchedThen relaunch the Jellyfin app on the TV and look at the header clock.
To check programmatically, temporarily append this to the script — it prints to the app's console, or you can beacon it to a machine you control via an image request:
setTimeout(function () {
var d = new Date();
console.log(JSON.stringify({
toString: d.toString(),
getHours: d.getHours(),
localeTime: d.toLocaleTimeString(),
intlTZ: Intl.DateTimeFormat().resolvedOptions().timeZone,
patched: window.__webosIntlTimeZonePatched
}));
}, 5000);Before → after on the affected TV:
| before | after | |
|---|---|---|
toLocaleTimeString() |
2:05:52 PM ❌ |
5:40:12 PM ✅ |
Intl…resolvedOptions().timeZone |
Etc/Unknown |
Asia/Tehran ✅ |
__webosIntlTimeZonePatched |
undefined |
Asia/Tehran |
- Scope. This patches display formatting only.
Dateobjects, the epoch values sent to the server, and playback reporting are untouched — nothing is shifted on the wire. - DST. Pinning a named IANA zone (not a fixed offset) means DST is handled by ICU as normal.
- Other webOS web apps built the same way are likely affected by the same engine bug; the same wrapper approach applies.
- Applies to Tizen (Samsung) too? Unverified here. If your Samsung client shows the same skew, check
Intl.DateTimeFormat().resolvedOptions().timeZonefirst — if it reportsEtc/Unknown, this fix should apply unchanged. - Tested on an LG C5 (OLED65C56LA), webOS
WebAppManager/ Chrome 120, Jellyfin server 12.0.0,Jellyfin for WebOS1.2.2, JavaScript Injector 3.4.0.
Public domain / CC0. Use it however you like.