Vishnu Priyan
Vishnu Priyan

Reputation: 13

Laravel - Carbon giving wrong time when using shiftTimeZone and setTimeZone

Laravel carbon is returning time in UTC when printing Carbon::now() but doesn't give the correct time while using shiftTimezone and setTimezone

Below are the results:

Carbon::now(); //"2021-07-20T07:30:29.775871Z"
Carbon::now()->timezoneName; //UTC
Carbon::now()->shiftTimezone('Asia/Kolkata'); //"2021-07-20T02:00:29.452997Z"
Carbon::now()->shiftTimezone('+05:30'); //"2021-07-20T02:00:29.452997Z"
Carbon::now()->shiftTimezone('Asia/Kolkata'); //"2021-07-20T07:30:29.775871Z"

In case of shiftTimeZone, it should add 05:30 hours to the time. But what it actually does is reduces 05:30 from the UTC time. And for setTimezone it is taking the same time as UTC.

Any idea where I'm getting it wrong?

Upvotes: 0

Views: 2374

Answers (3)

tinystone
tinystone

Reputation: 644

Cannot reproduce the issue with Carbon. Here is my test:

use Carbon\Carbon;
Carbon::now(); // "2023-09-15 01:16:27.000000 UTC (+00:00)"
Carbon::now()->timezoneName; // UTC
Carbon::now()->shiftTimezone('Asia/Kolkata'); // "2023-09-15 01:16:27.000000 Asia/Kolkata (+05:30)"
Carbon::now()->shiftTimezone('+05:30'); // "2023-09-15 01:16:27.000000 +05:30"
Carbon::now()->shiftTimezone('Asia/Kolkata'); // "2023-09-15 01:16:27.000000 Asia/Kolkata (+05:30)"
Carbon::now()->setTimezone('Asia/Kolkata'); // "2023-09-15 06:46:27.000000 Asia/Kolkata (+05:30)"

note:

  • shiftTimezone changes the timestamp (points to a different moment)
  • setTimezone doesn't change the timestamp (still points to the same moment).
  • how they print is another thing. You may want to use shiftTimezone to let time part (y m d h m s) be the same 1 and shiftTimezone results in moment changed.
$d0 = Carbon::parse('2024-01-01 00:00:00');
$d1 = $d0->copy()->setTimezone('America/Los_Angeles');
$d2 = $d0->copy()->setTimezone('Pacific/Niue');
$d0->getTimestamp(); // 1704067200
$d1->getTimestamp(); // 1704067200
$d2->getTimestamp(); // 1704067200

$d0 = Carbon::parse('2024-01-01 00:00:00');
$d1 = $d0->copy()->shiftTimezone('America/Los_Angeles');
$d2 = $d0->copy()->shiftTimezone('Pacific/Niue');
$d0->getTimestamp(); // 1704067200
$d1->getTimestamp(); // 1704096000
$d2->getTimestamp(); // 1704106800

Upvotes: 1

KyleK
KyleK

Reputation: 5121

What you put in comments here is not the content of the instance, it's an UTC ISO-8601 string as it's converted to be rendered in JSON output for instance:

echo Carbon::now()->format('Y-m-d H:i:s.u p'); // 2021-07-20 09:36:08.596951 Z
echo Carbon::now()->shiftTimezone('Asia/Kolkata')->format('Y-m-d H:i:s.u p'); // 2021-07-20 09:36:08.596951 +05:30
echo Carbon::now()->shiftTimezone('+05:30')->format('Y-m-d H:i:s.u p'); // 2021-07-20 09:36:08.596951 +05:30
echo Carbon::now()->shiftTimezone('Asia/Kolkata')->format('Y-m-d H:i:s.u p'); // 2021-07-20 09:36:08.596951 +05:30

JSON is converted to UTC because it's a standard way to exchange datetime information, timezone should be a separated information and you only need it to force a timezone, but 99% you want the user/client/browser to use its own timezone so new Date('2021-07-20T09:36:08.596951Z') in JavaScript or equivalent in other languages will work just fine and apply the current device timezone, which is the correct way for proper localization. Very specific cases where you want to display a date in a timezone that IS NOT the user device timezone, then you should pass "Asia/Kolkata" explicitly in your JSON output.

Upvotes: 0

Saiyan Prince
Saiyan Prince

Reputation: 4020

In my application, I never use shiftTimezone or setTimezone.

I always go with something like the following:

Carbon::now()->timezone('Asia/Kolkata');

It returns me the date in Asia/Kolkata timezone, without any issue.

Upvotes: 0

Related Questions