Because you are always dealing with the same Carbon instance.
When these are converted to json, they all end up with whatever timezone was applied last.
One option is to extract the time as a string before moving to the next value, eg
"timezonetest1" => Carbon::now('GMT+8')->toIso8601String(),
"utc" => Carbon::now('UTC')->toIso8601String(),
"now" => Carbon::now()->toIso8601String(),
"london" => now('Europe/London')->toIso8601String(),
"kolkata" => now()->tz('Asia/Kolkata')->toIso8601String(),
"Chicago" => Carbon::now()->setTimezone('America/Chicago')->toIso8601String(),
gives
{
"timezonetest1":"2023-05-17T21:03:30+08:00",
"utc":"2023-05-17T13:03:30+00:00",
"now":"2023-05-17T13:03:30+00:00",
"london":"2023-05-17T14:03:30+01:00",
"kolkata":"2023-05-17T18:33:30+05:30",
"Chicago":"2023-05-17T08:03:30-05:00"
}