PHP DateTime constructor - date string format based on DateTimeZone - php

I have a multi national system that uses two different types of date formats. One uses "d-m-Y" the other uses "m-d-Y". I have a Local class that is responsible for creating a DateTime object based on a date string passed into it.
The string being passed in is dynamic and can be either version. The problem is that even if you specify the DateTimeZone in the DateTime constructor you still have to pass in a string based on 'm-d-y'.
I need to be able to pass a string to the DateTime constructor based on the DateTimeZone that is passed in along with it. For example, if my TimeZone is set to Australia/Sydney
the DateTime constructor should accept a string like '31/11/2017' but it doesn't. The DateTime constructor doesn't take into account the TimeZone passed in with the string. I would have to use DateTime::createFromFormat, but this means I would have to manually specify a format for hundreds of time zones. It would be much easier if the DateTime constructor would take a string format based on the time zone passed in like this...
$dateTime = new DateTime('31/11/2017', new DateTimeZone('Australia/Sydney'))
This should work but doesn't in my case. Does anyone know what I am doing wrong? There must be a way to achieve this.

Maybe the format for your date isn't accepted by PHP's DateTime constructor. For a workaround try this:
$dateTime = DateTime::createFromFormat('d/m/Y', '31/11/2017')
->setTimeZone('Australia/Sydney');
or
$dateTime = DateTime::createFromFormat('d/m/Y', '31/11/2017', 'Australia/Sydney');

you can use the php-intl-extension to get default strings per locale-string
foreach (["en_US", "en_IE", "de_DE"] as $fmt) {
$formatter = datefmt_create($fmt, IntlDateFormatter::SHORT, IntlDateFormatter::NONE);
echo datefmt_get_pattern($formatter) . "\n";
}
see the documentation on datefmt_get_pattern for more details.

Related

Converting a date from local timezone to UTC

I have a Laravel-based app that is used by people from various parts of the US.
I am capturing a timestamp in Javascript when the user takes a specific action, and then I am submitting that timestamp as form data, for the Laravel/PHP to process.
The timestamp that I am capture in Javascript is in typical "YYYY-MM-DD HH:MM:SS" format.
I have the timezone the user is in stored in a database.
I basically want to take that timestamp, and convert it to UTC time, so that all timestamps in the database are UTC.
That is where I am struggling.
I have the following PHP code:
$defaultTime = request('submitted-time-stamp'); //In this case, we'll say 2022-12-21 12:01:01
$defaultTZ = $user->time_zone; //Translates to America/Denver
$utcTime = new DateTime($defaultTime);
$convertedTime = $utcTime1->setTimeZone(new DateTimeZone('UTC'));
$formattedTime = $convertedTime->format("Y-m-d H:i:s");
echo $formattedTime;
This code – it isn't producing any errors per sé... but it is showing the wrong time. It's showing the time that it went in as, not the time converted to UTC.
Basically, if I submit "2022-12-21 12:01:01" as the time, the converted time SHOULD be "2022-12-21 19:01:01", but it's still just echoing out "2022-12-21 12:01:01".
What am I missing here?
setTimezone() changes the timezone of the object from whatever default it was created with. I.e., it means, "convert from the existing timezone to this new timezone." It does not mean, "interpret the time as if it were in this timezone." If the original string didn't contain some sort of timezone identifier, then that default is whatever your PHP config says.
$when = new DateTime('2022-12-21 12:01:01');
echo $when->getTimeZone()->getName();
This will be the same as:
echo date_default_timezone_get();
Which is probably not what you want unless all your users are in the same timezone as your server.
In order to create a DateTime object in a specific known timezone that is not the same as your server's default, you'll need one of two things -- either a timezone representation in the input string:
$when = new DateTime('2022-12-21 12:01:01 America/New_York');
Or an explicit default timezone passed as a second parameter to the DateTime constructor:
$userDefaultTzStr = 'America/New_York'; // read this value from the database
$defaultTz = new DateTimeZone($userDefaultTzStr);
$when = new DateTime('2022-12-21 12:01:01', $defaultTz);
This latter method is (probably) preferred. If the input string contains any sort of timezone identifier, that will be used and the second parameter will be ignored. But if the input string does not contain any sort of timezone identifier, then the string will be interpreted as if it were in the indicated timezone.
Using Carbon it's very trivial.
use Carbon\Carbon;
$date = Carbon::create(request('submitted-time-stamp'), $user->time_zone);
$date->tz('UTC');
echo $date->format('Y-m-d H:i:s');
It should be the same thing with Laravel's Date facade.
use Illuminate\Support\Facades\Date;
$date = Date::create(request('submitted-time-stamp'), $user->time_zone);
$date->tz('UTC');
echo $date->format('Y-m-d H:i:s');

PHP DateTime class accepts #{$timestamp} as a timestamp. why?

I'm wondered why PHP DateTime class accepts a strange value to represent the timestamp?
The stranger value is #{$timestamp}:
Example:
$timestamp = time();
$date = new DateTime("#{$timestamp}");
PHP's Manual does not show any information related to #{$timestamp}!!
Please note that it's not possible to do something like this:
$date = new DateTime(time());
I know the easiest way to set a timestamp for DateTime class is: $date->setTimeStamp(time()); but I'm asking about #{$timestamp}
Does anyone know what is the magic behind #{$timestamp}?
Use of #timestamp is documented under Date/Time>Supported Date and Time Formats>Compound Formats>Localized Notations
Description Format Examples
Unix Timestamp "#" "-"? [0-9]+ "#1215282385"

How to format an UTC date to use the Z (Zulu) zone designator in php?

I need to display and handle UTC dates in the following format:
2013-06-28T22:15:00Z
As this format is part of the ISO8601 standard I have no trouble creating DateTime objects from strings like the one above. However I can't find a clean way (meaning no string manipulations like substr and replace, etc.) to present my DateTime object in the desired format. I tried to tweak the server and php datetime settings, with little success. I always get:
$date->format(DateTime::ISO8601); // gives 2013-06-28T22:15:00+00:00
Is there any date format or configuration setting that will give me the desired string? Or I'll have to append the 'Z' manually to a custom time format?
No, there is no special constant for the desired format. I would use:
$date->format('Y-m-d\TH:i:s\Z');
But you will have to make sure that the times you are using are really UTC to avoid interpretation errors in your application.
If you are using Carbon then the method is:
echo $dt->toIso8601ZuluString();
// 2019-02-01T03:45:27Z
In PHP 8 the format character p was added:
$timestamp = new DateTimeImmutable('2013-06-28T22:15:00Z');
echo $timestamp->format('Y-m-d\TH:i:sp');
// 2013-06-28T22:15:00Z
In order to get the UTC date in the desired format, you can use something like this:
gmdate('Y-m-d\TH:i:s\Z', $date->format('U'));
To do this with the object-oriented style date object you need to first set the timezone to UTC, and then output the date:
function dateTo8601Zulu(\DateTimeInterface $date):string {
return (clone $date)
->setTimezone(new \DateTimeZone('UTC'))
->format('Y-m-d\TH:i:s\Z');
}
Edit: clone object before changing timezone.
Since PHP 7.2 DateTimeInterface::ATOM was introduced in favor of DateTimeInterface::ISO8601, although it still lives on for backward compatability reasons.
Usage
$dateTimeObject->format(DateTimeInterface::ATOM)

make date() return a timezone-specific date/time without using date_default_timezone_set()

Is there a way to use the date() function and have it return the a specific Timezone's current date, and not the server date?
I understand I can use:
date_default_timezone_set('Asia/Tokyo');
date('j F Y');
however, I am doing this in the context of a large application, and doing the date_default_timezone_set() might make the other date operations in the rest of the script behave differently.
Use DateTime::createFromFormat (>= 5.3.0), which allows you to set the timezone for the given date. This will allow you to modify the timezone for only a given date, and not dates that may appear elsewhere in your script.
Returns new DateTime object formatted according to the specified
format.
Object oriented style
public static DateTime DateTime::createFromFormat ( string $format , string $time [, DateTimeZone timezone ] )
Procedural style:
DateTime date_create_from_format ( string $format , string $time [, DateTimeZone $timezone ] )
The docs do a good job of providing the details of each parameter if you are unfamiliar with them so I will refrain from posting it all.
Another alternative would be to modify the timezone in the date format. The timezone identifier was (added in PHP 5.1.0).
Use the DateTime class instead, it allows you to specify the timezone on creation (default is UTC), or by using setTimezone() to change the rendering timezone.

PHP Zend date format

I want to input a timestamp in below format to the database.
yyyy-mm-dd hh:mm:ss
How can I get in above format?
When I use
$date = new Zend_Date();
it returns month dd, yyyy hh:mm:ss PM
I also use a JavaScript calender to insert a selected date and it returns in dd-mm-yyyy format
Now, I want to convert these both format into yyyy-mm-dd hh:mm:ss so can be inserted in database. Because date format not matching the database field format the date is not inserted and only filled with *00-00-00 00:00:00*
Thanks for answer
Not sure if this will help you, but try using:
// to show both date and time,
$date->get('YYYY-MM-dd HH:mm:ss');
// or, to show date only
$date->get('YYYY-MM-dd')
Technically, #stefgosselin gave the correct answer for Zend_Date, but Zend_Date is completely overkill for just getting the current time in a common format. Zend_Date is incredibly slow and cumbersome to use compared to PHP's native date related extensions. If you don't need translation or localisation in your Zend_Date output (and you apparently dont), stay away from it.
Use PHP's native date function for that, e.g.
echo date('Y-m-d H:i:s');
or DateTime procedural API
echo date_format(date_create(), 'Y-m-d H:i:s');
or DateTime Object API
$dateTime = new DateTime;
echo $dateTime->format('Y-m-d H:i:s');
Don't do the common mistake of using each and every component Zend Frameworks offers just because it offers it. There is absolutely no need to do that and in fact, if you can use a native PHP extension to achieve the same result with less or comparable effort, you are better off with the native solution.
Also, if you are going to save a date in your database, did you use any of the DateTime related columns in your database? Assuming you are using MySql, you could use a Timestamp column or an ISO8601 Date column.
This is how i did it:
abstract class App_Model_ModelAbstract extends Zend_Db_Table_Abstract
{
const DATE_FORMAT = 'yyyy-MM-dd';
public static function formatDate($date, $format = App_Model_ModelAbstract::DATE_FORMAT)
{
if (!$date instanceof Zend_Date && Zend_Date::isDate($date)) {
$date = new Zend_Date($date);
}
if ($date instanceof Zend_Date) {
return $date->get($format);
}
return $date;
}
}
this way you don't need to be concerned with whether or not its actually an instance of zend date, you can pass in a string or anything else that is a date.
a simple way to use Zend Date is to make specific function in its business objects that allows to parameter this function the date format. You can find a good example to this address http://www.pylejeune.fr/framework/utiliser-les-date-avec-zend_date/
this is i did it :
Zend_Date::now->toString('dd-MM-yyyy HH:mm:ss')
output from this format is "24-03-2012 13:02:01"
and you can modified your date format
I've always use $date->__toString('YYYY-MM-dd HH-mm-ss'); method in the past but today didn't work. I was getting the default output of 'Nov 1, 2013 12:19:23 PM'
So today I used $date->get('YYYY-MM-dd HH-mm-ss'); as mentioned above. Seems to have solved my problem.
You can find more information on this on output formats here: http://framework.zend.com/manual/1.12/en/zend.date.constants.html

Categories