Carbon: No support for setting microseconds

Created on 31 Mar 2016  路  9Comments  路  Source: briannesbitt/Carbon

There is a getter property for returning the microseconds in a date, but no setter to set microseconds, like there are for all other units of time.

So I can get the seconds and microseconds for a carbon date:

echo $carbon->second;
echo $carbon->micro;

I can set the seconds too:

$carbon->second = 45;

But I cannot set the microseconds:

$carbon->micro = 123400; // No setter

My main use-case is setting it to zero to remove microseconds, in order to truncate a time down to a whole number of seconds.

Most helpful comment

lucky these days Carbon has it

$now = Carbon::now()->micro(0);

"name": "nesbot/carbon", "version": "2.25.3",

All 9 comments

Strangely enough, this does not work:

$carbon->setTime($carbon->hour, $carbon->minute, $carbon->second);

Even though the seconds are an integer, and the setTime only accepts integers, the microseconds already set for the time are preserved unchanged. That's a little crazy. Here is the result of a print_r() after the above setTime:

Carbon\Carbon Object
(
    [date] => 2016-03-30 23:13:16.420000
    [timezone_type] => 3
    [timezone] => UTC
)

The only way I have found to manipulate the microseconds on a Datetime (and by extension Carbon) is to create a new instance from a formatted string. For example:

    $new_instance = Carbon::createFromFormat(
        Carbon::ISO8601, $old_instance->format(Carbon::ISO8601)
    )->tz($old_instance->getTimezone());

This gives me a new instance of a Carbon object $old_instance with the microseconds stripped off. It feels pretty ugly though, and I'm unsure if there are any edge cases where it will fail. It is also more at home for an immutable object, since it does not alter the original time, but Carbon does not work that way, with its setters and getters.

The timezone ends up a s a numeric offset if you don't explicitly set the timezone on the created Carbon object.

How this is implemented in PHP is frustrating:

$time = new DateTime('t12:15:10.123');
var_dump($time->format('H:i:s.u'));

$time->modify('t13:30:20.456');
var_dump($time->format('H:i:s.u'));

Gives:

string(15) "12:15:10.123000"
string(15) "13:30:20.123000" // NOT "13:30:20.456000"

The microseconds can be set when creating a DateTime, and the time can be changed in an exaisting DateTime except the microseconds - they just remain unchanged. That's an inexcusable inconsistency IMO. I can see how it has happened, by internally passing modify through the strtotime() functionality (haven't checked the PHP source, but the docs hint at this) that only deals with integer unix timestamps. But still :-(

A tested PR would be great

I think it needs some discussion first. Is Carbon going immutable? Unlike the rest of the DateTime object, it looks like the microseconds are immutable (I suspect by implementation rather than any PHP internals plan). So changing the microseconds requires the creation of a new instance. How does that fit into Carbon as it currently stands and is planned?

There are setters that use the magic setter method:

$dt->minute = 32;
$dt->second = 5;
// etc.

Since microseconds are immutable, it would look more like this:

$dt = $dt->withMicroSecond(123000);

That would certainly be handy, but takes a totally different approach to the setters. I am wondering if the end game here would be an entire immutable version of Carbon, or an immutable wrapper for Carbon? I'm not even sure if that would be possible if it still extended DateTime, so I guess it wouldn't be a direct extension, which moves it so far from the current implementation of Carbon that it's a separate project.

Unless, there is some little trick in PHP for setting the microtime that we are all missing...?

Oh, there's an immutable fork - didn't spot that. Perhaps that is where I should be dealing with microtime? Not sure how that fork works though - seems to use the mutable trait on the immutable object, so all the setters are still there.

lucky these days Carbon has it

$now = Carbon::now()->micro(0);

"name": "nesbot/carbon", "version": "2.25.3",

Was this page helpful?
0 / 5 - 0 ratings