Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Windows: DST timestamp "fix" (bug 18078) marks ~90% of library as changed after every clock change; freezes server when triggered by a folder browse

Open
#1,707 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@pupvogel is already working on this.

Since Oct 25, 2026.

  • #1708 by @pupvogel — open

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
45/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
perl, sqlite

Research direction

The bug is in Slim/Utils/Scanner/Local.pm around line 209 in rescan, and Slim/Utils/Misc.pm findAndScanDirectoryTree. Read those subs and the tracks/scanned_files schema. Reproduce by toggling metainformation.lastRescanTimeIsDST on Windows, then verify only actually changed files are re-read and folder browse doesn't block server. Done: no global shift, scan counts match real changes.

Written by the indexing model from the issue text.

Description

Describe the bug

This morning my Windows Lyrion server froze while streaming music.
Turns out the issue is related to the daylight saving time change last night (reported before as #824 but closed as stale).
My AI traced it to two interacting things:

  1. Perl's stat() on Windows (LMS ships Perl 5.32.1, MSWin32-x64-multi-thread, gcc build on the Microsoft C runtime) reports mtime one hour off for files whose modification date lies in the other DST half of the year. Right now (standard time) a file saved in July reads 3600 s early, a file saved in November reads correctly; in summer it is the reverse. This is the old CRT _stat behaviour; a single global offset cannot describe it.
  2. Slim::Utils::Scanner::Local::rescan (bug 18078 block, Local.pm ~line 209) compensates by shifting every row: UPDATE tracks SET timestamp = timestamp ± 3600. That is only correct for rows whose stored value was itself affected by the CRT error at the time of the last scan; for every other row it introduces a one-hour mismatch. In addition the persistent scanned_files table is not shifted at all.

Net effect: after the shift, scanned_files.timestamp doesn't match tracks.timestamp for most rows, so almost every file lands in the changed set and gets its tags re-read.

Worse, the block also runs in the in-process rescan that Slim::Utils::Misc::findAndScanDirectoryTree triggers when a client browses the music folder (Scanner::Local->rescan($path, { no_async => 1, recursive => 0 })). If that is the first scan after the clock change, tracks get shifted while the scanned_files rows from the previous full scan are not, the changed query returns essentially every track under the folder, and the server re-reads them synchronously. Today that froze my server for good: port 9000 stopped answering, players stalled, the Windows service hung in STOP_PENDING until perl.exe was killed, and the isScanning flag survived in the DB and had to be cleared with abortscan.

[26-10-25 09:30:59.9909] Slim::Utils::Scanner::Local::rescan (180) Discovering audio files in D:\la musique 'pop'\platten
[26-10-25 09:31:00.4055] Slim::Utils::Scanner::Local::__ANON__ (216) DST has changed since last scan - fix timestamps in tracks table
[26-10-25 09:31:01.0025] Slim::Utils::Scanner::Local::deleteTracks (407) Removing deleted audio files (0)
[26-10-25 09:31:01.0026] Slim::Utils::Scanner::Local::updateTracks (574) Rescanning changed audio files (59479)

To Reproduce

  1. Windows, NTFS, library whose files carry modification dates from both halves of the year, last full scan done before a DST change.
  2. Let the clock change happen (or set metainformation.lastRescanTimeIsDST to the opposite of the current state).
  3. Either run "Look for new and changed media" → nearly every file is reported as changed and re-read (see numbers below), or
  4. browse the music folder from a client (iPeng, Material, ...) → the same re-read runs inside the server process and blocks it.

Expected behavior

Only files that actually changed are re-read. A folder browse never performs a library-sized synchronous rescan inside the server.

Measurements (after the DST block had run, before the files were re-read)

Sample of 1,500 random local tracks, real_mtime − tracks.timestamp (real mtime read via the Win32 API):

offset share of resolvable tracks file dates Perl stat vs real mtime
+3600 s ~72 % winter-dated (Nov 2017 …) equal
+7200 s ~15 % summer-dated (Jul 2001, Apr 2003, May 2010) Perl reads 3600 s early
0 ~13 % winter-dated (Nov 2009) equal

External scanner run right afterwards (scanner.pl --rescan, three media dirs):

09:56:06 Discovering audio files in D:\la musique 'pop'\platten
09:56:30 Removing deleted audio files (2)
09:56:30 Rescanning changed audio files (50422)
10:04:20 Scanning new audio files (0)
10:04:20 Discovering audio files in D:\la musique 'pop'\unorg
10:04:38 Removing deleted audio files (1)
10:04:39 Rescanning changed audio files (6350)
10:06:48 Discovering audio files in D:\la musique 'pop'\kinder
10:06:49 Rescanning changed audio files (666)
10:07:07 Scanning new audio files (0)

57,438 files re-read, 3 files actually deleted, 0 new, 0 actually changed, 11 minutes. Afterwards a sample of 300 random tracks shows perl stat mtime == tracks.timestamp for all 300, i.e. the re-read merely rewrote what the shift had broken.

System Information

  • OS: Windows 11 Pro 10.0.26300, LMS running as the squeezesvc service
  • Hardware: x86_64 (Ryzen 9 9950X), library on an internal NTFS volume
  • Web skin: Default
  • Browser: Chrome
  • LMS Version: 9.1.1 (1779815526), Perl 5.32.1 MSWin32-x64-multi-thread
  • Players: Squeezebox3, iPeng (the browse that triggered the in-process scan came from iPeng), SqueezeLite
  • Library: ~57,000 local files, SQLite, dbhighmem on

Additional context / suggestions

  • The blanket ±3600 shift cannot be correct given the CRT behaviour. Options: (a) read mtime through the Win32 API (Win32API::File GetFileTime, or Win32::UTCFileTime) so the value is DST-independent and drop the shift; or (b) at minimum shift scanned_files too, so the in-process path does not see a global mismatch.
  • findAndScanDirectoryTree should not run a potentially library-sized synchronous rescan in the server; cap the changed set or hand off to the external scanner above some threshold.
  • Consider resetting isScanning on server start when no scanner process exists.

Happy to test a patch; I can reproduce on demand by toggling the DST flag in metainformation.

Dominant language
Perl
Stars
1.8k
Forks
386
Avg merge
2d 7h
Merged PRs (30d)
14

Getting set up

Open in Codespaces

Starts the project's dev container in your browser, under your own GitHub account.

  • No Dockerfile or Docker Compose file
  • No pull request template
  • No contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from LMS-Community/slimserver

All issues in LMS-Community/slimserver

Similar issues

More Perl issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.