Repository: briannesbitt/Carbon (PHP)

Issue:
The result of startOfWeek() varies when mixin() is used, and no locale is set.
<!--
    🛑 DON'T REMOVE ME.
    This issue template applies to all
      - bug reports,
      - feature proposals,
      - and documentation requests

    Having all those informations will allow us to know exactly
    what you expect and answer you faster and precisely (answer
    that matches your Carbon version, PHP version and usage).
    
    Note: Comments between <!- - and - -> won't appear in the final
    issue (See [Preview] tab).
-->
Hello,

I encountered an issue with the following code:
<!--
    ⚠️ Your code below (not the code from inside Carbon library)
    Be sure it's dependency-free and enough to reproduce the issue
    when we run it on:
    https://play.phpsandbox.io/embed/nesbot/carbon
-->
```php
require('vendor/autoload.php');

use Carbon\Carbon;

trait CarbonMixin {

    public function mixinCopy()
    {
        return $this->copy();
    }
}

Carbon::mixin(CarbonMixin::class);

// Use a known date for replicating this issue.
$date = '2023-07-08';

// No locale is set, but confirm that the default is 'en'.
echo "Carbon defalt locale: " . Carbon::now()->locale() . "\n";

// Before we call the mixin method, we get '2023-07-03', which is a Monday.
$startOfWeekWithoutMixin = Carbon::parse($date)->startOfWeek()->format("Y-m-d");
echo "Without the Mixin being used: {$startOfWeekWithoutMixin}\n";

// This causes the default locale to be loaded, as a side-effect, resulting in '2023-07-02', which is a Sunday.
$startOfWeekWithMixin = Carbon::parse($date)->mixinCopy()->startOfWeek()->format("Y-m-d");
echo "With the Mixin being used: {$startOfWeekWithMixin}\n";
```

Carbon version: 2.68.1
<!--
    ⚠️ Run the command `composer show nesbot/carbon` to get "versions"
-->

PHP version: 8.2.7

<!--
    Use `echo phpversion();`
    to get PHP version.

    Some issues can depends on your context, settings,
    macros, timezone, language. So to be sure the code
    you give is enough to reproduce your bug, try it
    first in:
    https://play.phpsandbox.io/embed/nesbot/carbon?input=%3C%3Fphp%0A%0Aecho%20Carbon%3A%3Aparse('2018-06-01')-%3EsubDay()-%3Emonth%3B

    You can use the [Options] button to change the version
    then when you get the bug with this editor, you can use
    the [Export] button, copy the link of the opened tab,
    then paste it in the issue. Then we can immediatly get
    your issue.
-->


I expected to get:

```
Carbon defalt locale: en
Without the Mixin being used: 2023-07-03
With the Mixin being used: 2023-07-03
```
<!--
    Always give your expectations. Each use has their owns.
    You may want daylight saving time to be taken into account,
    someone else want it to be ignored. You may want timezone
    to be used in comparisons, someone else may not, etc.
-->

But I actually get:

```
Carbon defalt locale: en
Without the Mixin being used: 2023-07-03
With the Mixin being used: 2023-07-02
```
<!--
    If you did not succeed to get the same result in
    https://play.phpsandbox.io/embed/nesbot/carbon?input=%3C%3Fphp%0A%0Aecho%20Carbon%3A%3Aparse('2018-06-01')%3B then precise the
    result you get.
-->

From what I can tell, this is the due to changes made in #2804, specifically where `->settings($result->getSettings())` is called (in `src/Carbon/Traits/Mixin.php`), which results in the `en` locale being loaded, whereas before this no locale is in use.

As to whether this should result in Monday or Sunday, I am not sure, but I do think it should be consistent. This returned Monday in both cases with v2.66.0.

My workaround for this is to set `en_001` as the locale, which I'd recommend to anyone else hitting this issue.

Thanks!



Discussion:
Hello,

I will investigate.

Meanwhile, you can also do: `->startOfWeek(Carbon::MONDAY)` which will guarantee to use Monday as the start of week.

Thanks.
Thanks for sorting this out @kylekatarnls!



Patch:
diff --git a/src/Carbon/Traits/Options.php b/src/Carbon/Traits/Options.php
index 6f021942ac..48f9739773 100644
--- a/src/Carbon/Traits/Options.php
+++ b/src/Carbon/Traits/Options.php
@@ -422,7 +422,7 @@ public function getSettings()
         foreach ($map as $property => $key) {
             $value = $this->$property ?? null;
 
-            if ($value !== null) {
+            if ($value !== null && ($key !== 'locale' || $value !== 'en' || $this->localTranslator)) {
                 $settings[$key] = $value;
             }
         }
@@ -437,7 +437,7 @@ public function getSettings()
      */
     public function __debugInfo()
     {
-        $infos = array_filter(get_object_vars($this), function ($var) {
+        $infos = array_filter(get_object_vars($this), static function ($var) {
             return $var;
         });
 


Test patch:
diff --git a/tests/Carbon/MacroTest.php b/tests/Carbon/MacroTest.php
index 9e63473836..5eb4e6ab99 100644
--- a/tests/Carbon/MacroTest.php
+++ b/tests/Carbon/MacroTest.php
@@ -308,8 +308,12 @@ public function testMutabilityOfMixinMethodReturnedValue()
 
         $now = Carbon::now();
 
+        $this->assertSame('Monday', $now->copy()->startOfWeek()->dayName);
+
         $copy = $now->copyWithAppTz(false, 'Europe/Paris');
 
+        $this->assertSame('Monday', $copy->copy()->startOfWeek()->dayName);
+
         $this->assertSame('Europe/Paris', $copy->format('e'));
         $this->assertSame('UTC', $now->format('e'));
 
diff --git a/tests/Jenssegers/DateTest.php b/tests/Jenssegers/DateTest.php
index 06137d03a6..42e87bf817 100644
--- a/tests/Jenssegers/DateTest.php
+++ b/tests/Jenssegers/DateTest.php
@@ -14,6 +14,7 @@
 namespace Tests\Jenssegers;
 
 use Carbon\Carbon;
+use DateTimeImmutable;
 
 class DateTest extends TestCaseBase
 {
@@ -24,19 +25,13 @@ public function testConstructFromString()
         $date = new Carbon('2013-01-31');
         $this->assertSame(1359590400, $date->getTimestamp());
 
-        $before = time();
+        $before = (new DateTimeImmutable())->getTimestamp();
         $date = new Carbon('1 day ago');
-        $after = time();
+        $after = (new DateTimeImmutable())->getTimestamp();
         $this->assertGreaterThanOrEqual($before - 86400, $date->getTimestamp());
         $this->assertLessThanOrEqual($after - 86400, $date->getTimestamp());
     }
 
-    public function testConstructTimestamp()
-    {
-        $date = new Carbon(1367186296);
-        $this->assertSame(1367186296, $date->getTimestamp());
-    }
-
     public function testMake()
     {
         $date1 = Carbon::make('Sunday 28 April 2013 21:58:16');