Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

lat4732's avatar
Level 12

Carbon format date to YYYY-MM-DDThh:mm:ssTZD

I'm really confused. How can I format a created_at value to YYYY-MM-DDThh:mm:ssTZD format?

This is obviously not working

\Carbon\Carbon::parse($created_at)->format('YYYY-MM-DDThh:mm:ssTZD')

Any ideas?

0 likes
20 replies
click's avatar

I assume you are trying to get one of the standard times? What should "TZD" be? Did you take a look at the documentation?

now()->format('c')
now()->toIso8601String(); 
// 2022-08-12T16:20:19+00:00 
tykus's avatar

Your formatter string is not PHP compatible, try Y-m-d\Th:i:sT - for Year, month, day, literal T, hour, minute, second, Timezone (what does D represent?)

\Carbon\Carbon::parse($created_at)->format('Y-m-d\Th:i:sT');
lat4732's avatar
Level 12

@tykus Here's an example output of what I expect

2021-09-10T10:42:33.440Z

It's from the Google News Sitemap docs. Scroll down to <publication_date>. And yes, I know that there are other formats that I can use but I'm requested to do it as I described.

kokoshneta's avatar

@tykus Z is the timezone offset in seconds relative to UTC, and D is the three-letter textual representation of the day. No idea why anyone would want that at the end of their datetime string, though.

2 likes
kokoshneta's avatar

@Laralex Those are Google’s (actually, W3C’s) abbreviations – they’re completely unrelated to the ones used to format PHP/Carbon dates.

tykus's avatar

@kokoshneta I know what D is as a PHP datetime format; I didn't know what the OP meant by D in their custom format

kokoshneta's avatar
Level 27

That format doesn’t make any sense, so it’s probably not what you want. As @tykus has pointed out, the literal T between the date and the time needs a backslash to be escaped. Going by the example output you posted in your comment, the format you gave in the question is definitely not what you want.

Given the time 18:08:04 on 12 August 2022 in Paris, the format you give in the question will yield:

2022202220222022-AugAug-FriFriCST0606:0808:0404CST3600Fri

Not really understandable. You want this:

Carbon::parse($created_at)->format('Y-m-d\TH:i:s.vp');

If you don’t absolutely need the milliseconds (Google doesn’t require them), you can also use this Carbon shortcut, which is easier:

Carbon::parse($created_at)->toW3cString();
lat4732's avatar
Level 12

@kokoshneta But .v\Z in my case always return .000Z..Why? I can see in the database all the records are with created_at field like this 2022-08-12 01:39:04. Is that because when I insert a record I'm setting the created_at like this

'created_at' => now()
kokoshneta's avatar

@Laralex That would be because your created_at column doesn’t have milli- or microseconds, only seconds. In which case you definitely don’t need the milliseconds for Google either. This StackOverflow answer describes how your datetime columns would have to be set up if you want it to include milliseconds.

(I edited the answer to fix the time zone designator and add a shorter Carbon syntax.)

lat4732's avatar
Level 12

@kokoshneta The columns are created like this

$table->timestamps();
$table->timestamp('published_at')->nullable()->default(null);

I'll settle for this 1997-07-16T19:20:30+01:00 format (->toW3cString()). What should I edit in order to save the correct data and have the expected output? Thanks for your time tho.

kokoshneta's avatar

@snapey Or just use $model->created_at->toIso8601ZuluString(), which does the same. ;-)

@Laralex If you just use ->toW3cString(), you will get the time in the timezone set in your database; Snapey’s way gets you the Zulu time. Either should be fine for sending to Google.

You shouldn’t need to change anything to get the expected output. If your created_at column contains the correct dates and times, it should just work.

Snapey's avatar

@kokoshneta Nice. Thats a new one on me. I find the Carbon docs really bad to navigate

lat4732's avatar
Level 12

@kokoshneta That's what I've actually asked. How to insert a correct dates and times so I can get my expected output. Because currently, I'm inserting into created_at just simply now() when creating a new record.

Snapey's avatar

@Laralex Thats correct. Its when you get the value out you need to care about the format. It can only be in one format in the database.

1 like
kokoshneta's avatar

@Laralex Yeah, I just meant that of course the value in the database needs to be the actual time of updating, which you get with now().

In fact, if your datetime columns where created using ->timestamps() in your migration and your model doesn’t do anything to disable them, you don’t need to explicitly set them using now() or anything at all – Laravel will automatically set the created_at column when inserting a record and update the updated_at column when updating a record.

1 like
gizmojo's avatar

@Snapey way but slightly shorter $model->published_at->toIso8601ZuluString('µ')

Under the hood does the same thing

    /**
     * Convert the instance to UTC and return as Zulu ISO8601
     * @param string $unitPrecision
     *
     * @return string
     */
    public function toIso8601ZuluString($unitPrecision = 'second')
    {
        return $this->avoidMutation()
            ->utc()
            ->rawFormat('Y-m-d\T'.static::getTimeFormatByPrecision($unitPrecision).'\Z');
    }
Snapey's avatar

@gizmojo same answer as one posted a year ago, thus adding nothing to the topic.

Please or to participate in this conversation.