Solved (Sorta): My Mac Thinks its in UTC Timezone

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
2
$ ls -l /etc/localtime
lrwxr-xr-x 1 root wheel 41 Mar 29 17:07 /etc/localtime -> /var/db/timezone/zoneinfo/America/Chicago

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
2
3
4
5
6
7
8
9
10
11
12
$ ls /var/db/timezone/zoneinfo/America
Adak Cordoba Guadeloupe Menominee Sitka
Anchorage Costa_Rica Hermosillo Mexico_City St_Johns
Anguilla Curacao Indiana Miquelon St_Kitts
Araguaina Danmarkshavn Iqaluit Montevideo Swift_Current
Argentina Dawson_Creek Juneau Montserrat Thule
Aruba Ensenada Kentucky Nome Thunder_Bay
Asuncion Fort_Nelson Louisville North_Dakota Tijuana
Atka Glace_Bay Maceio Ojinaga Toronto
Barbados Godthab Marigot Panama Virgin
Cambridge_Bay Grand_Turk Martinique Pangnirtung Winnipeg
Caracas Grenada Mendoza Shiprock

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
2
3
4
5
6
7
➜  db/timezone
$ ls -l
total 0
lrwxr-xr-x 1 root wheel 35 Apr 6 00:19 icutz -> /var/db/timezone/tz/2024a.1.0/icutz
drwxr-xr-x 3 root wheel 96 Mar 16 22:21 tz
lrwxr-xr-x 1 root wheel 29 Feb 21 03:46 tz_latest -> /var/db/timezone/tz/2024a.1.0
lrwxr-xr-x 1 root wheel 38 Apr 6 00:19 zoneinfo -> /var/db/timezone/tz/2024a.1.0/zoneinfo

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
2
3
4
5
6
7
8
9
10
date
Thu Apr 11 08:46:10 CDT 2024

node
Welcome to Node.js v20.10.0.
Type ".help" for more information.
> new Date()
2024-04-11T13:46:37.247Z
> new Date().getTimezoneOffset()
300