Time.now() and Time.local() only return a numer of seconds without any further information about when the counting started.
And Time.timeStr() just takes a number of seconds (without caring about the way how you got that number) and formats that according to the data stored in the Time object (especially the zone).
A over-simplified example:
int zone = -5;
int now() { return millis()/1000; }
int local() { return now() + zone*3600; }
String timeStr(int sec) { return ("The localized time is " + String(sec + zone*3600) + " seconds after bootup"); }
If you call that the way you did above, you'll see similar behaviour (local() will show twice the zone offset).
And when you set zone = 0, you'll get the same result for local() and now()