I was working on a project and was trying to convert an ISO-8601 timestamp string from my server into localtime for display. Most libraries should handle that automatically, since the js Date object is pretty much always in local time. But it kept showing me a time that was off by a few hours.
Eventually I figured out that certain systems in my environment were using UTC time, even though I
live in Kansas City and it should be using America/Chicago
.
Check that out: even though system preferences are set to America/Chicago
, the terminal date
command
is still reporting a UTC time. Opening node
and running new Date()
also shows a UTC time. The javascript
Date issue reproduced in both firefox and safari.
Searching the internet, this seems to happen to other people sometimes. I haven’t found a definitive fix, but here’s what I learned.
Many system tools consult /etc/localtime
to determine the timezone. This file is a symlink to the actual timezone
database.
1 | $ ls -l /etc/localtime |
However, running the file
command on /etc/localtime
said it was a broken symlink.
Indeed, many of the American cities are missing from /var/db/timezone/zoneinfo
:
1 | $ ls /var/db/timezone/zoneinfo/America |
Notice there is no Chicago, New York, Los Angeles, etc.
I noticed that many of the entries in /var/db/timezone
are in turn more symlinks to the versioned timezone database,
in this case 2024a.1.0
.
1 | ➜ db/timezone |
I have another macbook from my employer, which reports the correct time. It does contain the expected database files for America/Chicago and is on the same
tz database, 2024a.1.0
. I’m not sure what happened to break it for my personal machine.
Both machines are Sonoma 14.4.1
.
One random forum user fixed this issue by backing up the timezone database from a working mac and restoring it, but you have to turn off system integrity protection to do that. I didn’t want to try all that unless I really had to.
Luckily, I found that /var/db/timezone/zoneinfo/US/Central
does exist. US/Central
and America/Chicago
are aliases
in the timezone database: they are equivalent.
So in my case, I just changed the etc/localtime
symlink to point to US/Central
instead of America/Chicago
:
1 | $ sudo ln -s /var/db/timezone/zoneinfo/US/Central /etc/localtime |
And now my date commands and javascript are correctly reporting the CDT timezone
1 | date |