PHP Wrong time after setting timezone - php

I stumbled onto a really weird problem:
For my task I wrote a method that would give me the current date in a specific format,
another method would then extract the date so I could compare it with dates in the database.
public static function getCurrentDate()
{
return date("Y-m-d H:i:s a");
}
public static function extractDate($date)
{
return date("Y-m-d", strtotime($date));
}
Because I've noticed that the time wasn't right, I've set the default timezone at the beginning of the script like this:
date_default_timezone_set('Europe/Berlin');
Running this script, I've noticed that it gives the wrong output, maybe you could already help me here.
$currentDate = getCurrentDate();
echo $currentDate."\n";
$extractedDate = extractDate($currentDate );
echo $extractedDate."\n";
Output:
2020-08-25 21:58:13 pm
1970-01-01
Then I tried it in another way with DateTime, where it still produced the wrong output
public static function extractDate($date)
{
$timezone = new DateTimeZone('Europe/Berlin');
$dt = DateTime::createFromFormat("Y-m-d H:i:s a", $date, $timezone);
return $dt->format("Y-m-d");
}
Output:
2020-08-25 21:58:13 pm
2020-08-26
I would understand if there was an error so it would lead to the Unix epoch again, but this time it somehow added a day.
It would be nice if you knew where my error at the first approach was and I'm also really interested to hear why PHP behaves like that in the second approach

Change:
public static function getCurrentDate()
{
return date("Y-m-d H:i:s a");
}
to
public static function getCurrentDate()
{
return date("Y-m-d H:i:s");
}
and you are all set.
In 24h time you do not need the a or am/pm, which makes the datetime unrecognizable via strtotime, it cannot convert it , and it returns false, thus the invalid date 1970-01-01which is qeuivalent tounixtime = 0`

Related

php , convert to date from excel

I am importing a excel , it seems from source the date is coming like this :
"2021-04-08T12:36:12+03:00"
i used the function
public function transformDate($value)
try {
return \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value);
} catch (\ErrorException $e) {
return '-1';
}
this function did a exception ,
if i used strtotime(2021-04-08T12:36:12+03:00) , it return bad date like : 0616-05-07 00:05:00
i can't find the correct function
The date string "2021-04-08T12:36:12+03:00" contains a time zone +03:00.
The best way is to use DateTime to keep the correct time zone.
$dateTime = new DateTime("2021-04-08T12:36:12+03:00");
echo $dateTime->format('Y-m-d H:i:s O');
//2021-04-08 12:36:12 +0300
If the date is required for a different time zone, this can be done with setTimeZone().
$dateTime->setTimeZone(new DateTimeZone("Europe/Berlin"));
echo $dateTime->format('Y-m-d H:i:s e');
//2021-04-08 11:36:12 Europe/Berlin
If we use strtotime and Date then we get a date and a time according to the setting of our server (My time zone is "Europe/Berlin").
echo date('Y-m-d H:i:s e',strtotime("2021-04-08T12:36:12+03:00"));
//2021-04-08 11:36:12 Europe/Berlin

How can I set the internal time of the PHP interpreter?

I have written a function in PHP which will print the third Monday of every month.
I now want to test the function if the function will work next month, without having to wait till next month.
My idea is that I could test how the function would work in the future by internally setting PHP's time to next month and running the function.
I was hoping there would be a Date Time ini setting which I could insert before my function to shift the time into the future, something like
<?php
$one_month_from_now = time() + 2592000;
ini_set('php_internal_time', $one_month_from_now);
function print_third_monday() {
// ....
}
print_third_monday();
Is is possible to change PHP's internal time like this? if so, how?
echo date("y-m-d H:i:s D");//17-03-16 10:43:38 Thu
echo PHP_EOL;
echo date("y-m-d H:i:s D",strtotime("+1 month"));//17-04-16 10:43:38 Sun
How about a better function that does the same functionality & you can cross check with ease:
<?php
echo getThirdTuesdayofMonth(3,2017);
function getThirdTuesdayofMonth($month, $year) {
$thirdTuesday='';
$no_of_days = cal_days_in_month(CAL_GREGORIAN, $month, $year);
$tue_iter=0;
for($i=1;$i<=$no_of_days;$i++) {
if(date('l',strtotime($i.'-'.$month.'-'.$year))=='Tuesday') {
if($tue_iter==3) {
$thirdTuesday = date('dS F Y', strtotime($i.'-'.$month.'-'.$year));
}
$tue_iter++;
}
}
return $thirdTuesday;
}

Convert User Submitted Date To UTC

I'm trying to figure out how to accept a date/time from a form, which is consequently in the user's timezone, and change it to UTC before inserting it into the database. For some reason, no amount of searching has netted me an answer.
My form will POST whatever date is selected by the user to my code, so I expect to be able to do something like this. Note: the $userDate may be relative to any number of timezones based on user's location
$userDate = $_POST['user_date'] // 2014-05-15 16:37:23
I anticipate using Date().getTimezoneOffset() on my form to also submit the users UTC offset (as detailed here).
$userOffset = $_POST['user_offset']
Then before inserting the date into my database, I would like to convert it to UTC -- but I am stumped on how to do that with PHP (I'm actually using Laravel so if you know of a way using Carbon, that would be even easier, but I couldn't find it in their docs).
I've been half tempted to manually parse the offset and convert it to number of seconds and add or subtract it to strtotime() output of the $userDate and then convert it back into a date format using date() -- but there has to be a better way!
What am I missing here? Does PHP have a function I just don't know about that lets me do something like:
$userDate = '2014-05-15 16:37:23';
$userOffset = '+04:00';
$utcDate = date_apply_offset($userDate, $userOffset);
echo $utcDate; // Outputs: 2014-05-15 20:37:23
Or am I making this harder than it has to be?
EDIT
Based on the solution provided by #vascowhite, I went with the following (added into question to improve answers for those seeking guidance)
I ended up using a function from moment.js since I was already using it to convert UTC to user's timezone on display.
HTML:
<input id="user_offset" type="hidden" name="user_offset" value="">
Javascript:
var offset = moment().format('ZZ');
$('#user_offset').val(offset);
PHP (in a custom date class):
class MyDate {
/**
* Convert Date to UTC
*
* #param string $date Any date parsable with strtotime()
* #param string $offset UTC offset of date
*/
public static function toUTC($date, $offset = '+0:00')
{
if ($timestamp = strtotime($date) && ! empty($offset) )
{
$newDate = date('Y-m-d H:i:s', $timestamp);
$newDate = new \DateTime($date . ' ' . $offset);
$newDate->setTimezone(new DateTimeZone('UTC'));
$date = $newDate->format('Y-m-d H:i:s');
}
return $date;
}
}
// To convert
$userDate = trim($_POST['user_offset']);
$userOffset = trim($_POST['user_date']);
$utc = MyDate::toUTC($userDate, $userOffset)
That class method isn't perfect, and in the event something goes wrong, it just returns the date back -- when really it should throw an exception.
This is a simple task with the DateTime classes:-
$userDate = '2014-05-15 16:37:23';
$userOffset = '+04:00';
$date = new \DateTime($userDate . ' ' . $userOffset);
var_dump($date);
$date->setTimezone(new \DateTimeZone('UTC'));
var_dump($date);
You can then format the date as you wish for output eg:-
echo $date->format('Y-m-d H:i:s');
or:-
$utcDate = $date->format('Y-m-d H:i:s');
echo $utcDate; // Outputs: 2014-05-15 20:37:23
See it working.
If you are doing any work with dates and times in PHP it is worth taking the time to become familiar with these extremely useful classes.
For all sorts of date/time manipulations you can make use of moment.php
For your example all what is needed are two lines of code:
$m = new \Moment\Moment('2014-05-15 16:37:23', '+0400');
echo $m->setTimezone('UTC')->format(); // 2014-05-15T12:37:23+0000
There is much more which helps to deal with date/time issues: https://github.com/fightbulc/moment.php
Cheers

Converting UTC to a different time zone in php

I'm using the below method to convert the UTC time to an other time zone. But the below method seems to returning back the UTC time. Will any of you be kind enough to point out whats wrong in the method I'm using?
static function formatDateMerchantTimeZone($t, $tz) {
if (isset($t)) {
return date('Y-m-d H:i:s', strtotime($t , $tz));
} else {
return null;
}
}
$t is the datetime I pass
$tz is the time zone such as America/Los_Angeles
It surprises me that many people are unaware of, or do not use the DateTime classes. They make tasks like this almost trivial.
I have assumed that the date string you pass to the function is in the UTC timezone.
function formatDateMerchantTimeZone($t, $tz)
{
$date = new \DateTime($t, new \DateTimeZone('UTC'));
$date->setTimezone(new \DateTimeZone($tz));
return $date->format('Y-m-d H:i:s');
}
See it working
Strtotime converts a timestamp in string format to a valid date time like '09-29-2013 07:00:00' as second parameter, it does not convert a timezone to a time. php has numerous functions for timezones such as timezone_offset that does calculate the difference between two timezones. take a look in the documentation for more info:
http://php.net/manual/en/function.timezone-offset-get.php
static function formatDateMerchantTimeZone($t, $tz) {
if (isset($t)) {
date_default_timezone_set($tz);
return date('Y-m-d H:i:s', strtotime($t));
} else {
return null;
}
}
From php.net first comment.
To avoid frustrating confusion I recommend always calling
date_default_timezone_set('UTC') before using strtotime().
Because the UNIX Epoch is always in UTC; you will most likely output the wrong time if you do not do this.
try this:
<?php
/** Returns the offset from the origin timezone to the remote timezone, in seconds.
* #param $remote_tz;
* #param $origin_tz; If null the servers current timezone is used as the origin.
* #return int;
*/
function get_timezone_offset($remote_tz, $origin_tz = null) {
if($origin_tz === null) {
if(!is_string($origin_tz = date_default_timezone_get())) {
return false; // A UTC timestamp was returned -- bail out!
}
}
$origin_dtz = new DateTimeZone($origin_tz);
$remote_dtz = new DateTimeZone($remote_tz);
$origin_dt = new DateTime("now", $origin_dtz);
$remote_dt = new DateTime("now", $remote_dtz);
$offset = $origin_dtz->getOffset($origin_dt) - $remote_dtz->getOffset($remote_dt);
return $offset;
}
?>
Examples:
<?php
// This will return 10800 (3 hours) ...
$offset = get_timezone_offset('America/Los_Angeles','America/New_York');
// or, if your server time is already set to 'America/New_York'...
$offset = get_timezone_offset('America/Los_Angeles');
// You can then take $offset and adjust your timestamp.
$offset_time = time() + $offset;
?>

Using Date & StrToTime

I've been using the following bit of code without any issues till it finally landed on a windows server and decided to produce an error:
$date = date('F d, Y', $data->e_date)
date($time_format, strtotime($date.' '.$data->e_time))
*(e_date is stored like this: "1293559200", and e_time is stored like this: "18:00")*
The error is as such:
date() [function.date]: Windows does not support dates prior to midnight (00:00:00), January 1, 1970 in ...
To my understanding this is because I am using strtotime within the date function. So what I'm wondering is what is an elegant method of solving or rewriting this?
Should I be feeding the entire strtotime in a new variable, i.e. $newdate and then back to date in that form, or otherwise?
Thank you!
You are using UNIX TIMESTAMP it will not work properly in windows os systems.
Try to convert it using this function.
convert 20031230233029 to 30/12/2003 23:30:59
function mysql_timestamp_para_humano($dt) {
$yr=strval(substr($dt,0,4));
$mo=strval(substr($dt,4,2));
$da=strval(substr($dt,6,2));
$hr=strval(substr($dt,8,2));
$mi=strval(substr($dt,10,2));
$se=strval(substr($dt,12,2));
return date("d/m/Y H:i:s", mktime ($hr,$mi,$se,$mo,$da,$yr));
}
or this one
function timestamp_para_humano($ts) {
$d=getdate($ts);
$yr=$d["year"];
$mo=$d["mon"];
$da=$d["mday"];
$hr=$d["hours"];
$mi=$d["minutes"];
$se=$d["seconds"];
return date("d/m/Y", mktime($hr,$mi,$se,$mo,$da,$yr));
}
or you can try to convert the unix timestamp to mysql timestamp wth this another function
function timestamp_para_mysql_timestamp($ts) {
$d=getdate($ts);
$yr=$d["year"];
$mo=$d["mon"];
$da=$d["mday"];
$hr=$d["hours"];
$mi=$d["minutes"];
$se=$d["seconds"];
return sprintf("%04d%02d%02d%02d%02d%02d",$yr,$mo,$da,$hr,$mi,$se);
}

Categories