I'm using the PHP DateTime class to generate a date for a custom licensing system. While I'm debugging it, I've noted that the date time are always wrong, it will be 5-dec-2018 but now we are in November, and this date will be the same also for the expiration_date.
How i can fix this issue? I need to add 30 days to the start date of the trial period.
Here is the code.
class Activator {
private $uuid;
private $keygen;
private $licence_code;
public static function generateLicence($uuid) {
if (!file_exists(ABSPATH.'/DataStorage/.licence')) {
$start_date = new DateTime();
$time_zone = $start_date->setTimezone(new DateTimeZone('Europe/Rome'));
$trial_date = $start_date->add(new DateInterval('P30D'));
$end_date = $trial_date->format('d-M-Y');
$machine_uuid = bin2hex($uuid);
$licence_code = base64_encode($machine_uuid);
$licence_file = array(
'uuid' => $machine_uuid,
'activation_date' => $time_zone->format('d-M-Y'),
#'trial_version' => true,
#'expire_date' => $end_date,
#'licence_code' => $licence_code
);
$w = file_put_contents(ABSPATH.'/DataStorage/.licence', json_encode($licence_file));
echo $w;
}
}
This is the expected behavior, as you add() to the date (by doing $start_date->add(...) - this modifies the original object $start_date.
You can solve this a few different ways, although the easiest way is just to create a new instance entirely with the 30 days added directly in the construct. You can also set the timezone as the second parameter of new DateTime().
$timezone = new DateTimeZone('Europe/Rome');
$start_date = new DateTime("now", $timezone);
$trial_date = new DateTime("+30 days", $timezone);
PHP.net on new DateTime()
PHP.net on DateTime::add()
See this live demo.
Related
There's something ugly about this way of producing 2 date strings a year apart
$obj_now = new DateTime();
$obj_year_ago = new DateTime();
$obj_year_ago->modify( '- 1 year');
$string_now = $obj_now->format('Y-m-d') ;
$string_year_ago = $obj_year_ago->format('Y-m-d') ;
It works but seems a clunky to me (and therefore probably inefficient).
To frame the question; if I have to produce dates based on a reference date (these are used in different ways in different forms). Do I need one object to each date or can I perform calculations to produce my strings from one DateTime object?
The difficulty I see is if I use $obj_now->modify()` it's no longer 'now'
Modify changes the DateTime object, but not the format method. Here's how you can do the following:
$curDate = new DateTime('Now');
$dates = [];
for($i=0;$i<3;$i++){
$dates[] = $curDate->format('Y-m-d');
$curDate->modify('-1 year');
}
var_dump($dates);
//array(3) { [0]=> string(10) "2021-11-04" [1]=> string(10) "2020-11-04" [2]=> string(10) "2019-11-04" }
If you don't want the modify to change the original object, you can use DateTimeImmutable. To get the same result as above, the code for DateTimeImmutable is like this:
$date = new DateTimeImmutable('Now');
$dates = [];
for($i=0;$i<3;$i++){
$curDate = $date->modify('-'.$i.' year');
$dates[] = $curDate->format('Y-m-d');
}
var_dump($dates);
For more information see DateTimeImmutable vs DateTime
Obviously, after modify() the datetime has changed and it's no longer 'now'.
But you can do your job using just one object simply changing your instructions order:
$obj = new DateTime();
$string_now = $obj->format('Y-m-d');
$obj->modify('- 1 year');
$string_year_ago = $obj->format('Y-m-d');
Edit: As mentioned by the user IMSoP (Thank you!) the date object parameter gets modified. Therefore I changed the function to use a copy of the object to prevent this.
I would prefere to use a function for it.
First of all you can, but not have to declare an date object. Second, the object you declared before the function calls doesn't get modified only to get the information you need.
<?php
/**
* #param DateTime $dt_date
* #param String $s_format
* #param String $s_modifier
* #return String
*/
function dateGetFormatedStringModified($dt_date, $s_format, $s_modifier = ''){
$dt_temp = clone $dt_date;
if(!empty($s_modifier)){
$dt_temp->modify($s_modifier);
}
return $dt_temp->format($s_format);
}
$string_year_ago = dateGetFormatedStringModified(new DateTime(), 'Y-m-d', '- 1 year');
$string_now = dateGetFormatedStringModified(new DateTime(), 'Y-m-d');
echo $string_now; // 2021-11-04
echo $string_year_ago; // 2020-11-04
?>
Different approach would be DateTimeImmutable. This prevents the date getting changed if modify is used.
$date = new DateTimeImmutable();
$date_last_year = $date->modify('-1 year');
echo $date->format('Y-m-d');
echo $date_last_year->format('Y-m-d');
You also can combine modify with format within one line
$date = new DateTimeImmutable();
echo $date->format('Y-m-d');
echo $date->modify('-1 year')->format('Y-m-d');
this is what I have got:
$_SESSION["chosen_exam_start_time"] = new DateTime();
$schedule_date = $_SESSION["chosen_exam_start_time"];
$schedule_date->setTimeZone(new DateTimeZone('Europe/London'));
$triggerOn = $schedule_date->format('Y-m-d H:i:s');
so I have a date passed within the session called "chosen_exam_start_time".
Now what I am struggling to do is add on $triggerOn.
So currently if I do
die(var_dump($triggerOn));
I get :
string(19) "2016-03-28 17:17:57"
What I want to do is if I have another variable which tells me a value like 10, how would I be able to add that value on to the $triggerOn. So that it will be:
string(19) "2016-03-28 17:27:57"
What I have done up to now is :
$_SESSION["chosen_exam_start_time"] = new DateTime();
$schedule_date = $_SESSION["chosen_exam_start_time"];
$schedule_date->setTimeZone(new DateTimeZone('Europe/London'));
$triggerOn = $schedule_date->format('Y-m-d H:i:s');
$value = 10;
$triggerOn->modify((int) $value.' minute');
die(var_dump($triggerOn));
However this die is not printing anything out now
I doesn't make sense to make any sort of calculation using strings. Just imagine you had this:
$price = 'Thirty five point nine';
$discount = 'Twenty percent';
... and you wanted to apply the discount ;-)
If your current architecture makes it impossible to keep the original DateTime object (I don't know, I don't have enough information for that) you'd better create a new one:
<?php
$triggerOn = '2016-03-28 17:17:57';
$minutes_to_add = 10;
$triggerOnDateTime = new DateTime($triggerOn, new DateTimeZone('Europe/London'));
$triggerOnDateTime->modify( sprintf('%d minutes', $minutes_to_add) );
$triggerOn = $triggerOnDateTime->format('Y-m-d H:i:s');
You are looking for the modify function on a datetime object.
$trigger->modify((int) $value.' minute');
Note I just pulled this from the Carbon Library, which is a very useful wrapper for DateTime giving you a good bit of syntactic sugar such as:
$trigger->addMinutes(10);
I want to get the date of yesterday of the current date in a specifc time zone.
I tried like this, but it is not working:
$date = new DateTime(NULL, new DateTimeZone('Pacific/Wake'));
$yesterday = $date->modify( '-1 day' );
$yesterday = $yesterday->format('Y-m-d');
I am still getting today's date.
This problem, according to the documentation for the modify() method, seems to entirely depend on which version of php you're using. In this case, method chaining(which is what you're attempting to do is called), is only available on php version 5.3.0 and up, according to the changelog on the previously linked docs.
That in mind, it explains why your code didn't work, and #Deryck's did. If you ever do upgrade your php version, or get your host to upgrade it, you could likely reduce those three lines to two:
$date = new DateTime(NULL, new DateTimeZone('Pacific/Wake'));
$date = $date->modify( '-1 day' )->format('Y-m-d');
Not much of an improvement, I realize, but there's your reason for why it failed to work.
Below are two of the methods I see of getting around this; one is creation of a class.. which seems like overkill to me unless this is apart of something grander... the other is a creation of a function. Both shove the extra lines into something that takes up less space, in a sense.
class DT {
private $now; //can be null
private $timezone; //DateTimeZone object
public function __construct($tz_str, $now = NULL) {
$this->now = $now;
$this->timezone = new DateTimeZone($tz_str);;
}
public function mod($mod,$format) {
$dt = new DateTime($this->now, $this->timezone);
$dt->modify($mod);
return $dt->format($format);
}
}
function mod_formatted_zone($tz_str, $mod, $format, $now = NULL) {
$timezone = new DateTimeZone($tz_str);
$dt = new DateTime($now,$timezone);
$dt->modify($mod);
return $dt->format($format);
}
The use of either is simple; in the case of the class, it'd be something like..
$dt = new DT('Pacific/Wake');
echo $dt->mod('-1 day', 'Y-m-d');
While in the case of the function, it'd simply be..
echo mod_formatted_zone('Pacific/Wake', '-1 day', 'Y-m-d');
Seems to work once you don't re-assign the $date variable unnecessarily. See below:
<?php
$date = new DateTime(NULL, new DateTimeZone('Pacific/Wake'));
$date->modify("-1 day");
$date = $date->format("Y-m-d");
// echo $date; // just in case you wanna echo - ya dig
?>
View demo
FYI:
Wake Island Time Zone (UTC+12:00)
Which means 1 day before is actually today (for me at least, on the western hemisphere).
I want to get the date of yesterday of the current date in a specifc time zone.
You can specify relative dates in the DateTime constructor. This will work for you:-
$yesterday = new DateTime('- 1 day', new DateTimeZone('Pacific/Wake'));
var_dump($yesterday);
Proof!.
I had this construction error when trying to creating a new DateTime object using a timestamp:
Exception: DateTime::_construct(): Failed to parse time string (1372622987) at position 8 (8): Unexpected character in DateTime->_construct()
The object creation code is:
$start_date = new DateTime( "#{$dbResult->db_timestamp}" );
Where $dbResult->db_timestamp is a valid unix timestamp taken from a database. The timestamp in question was:
1372622987
I would understand this error for invalid formats being passed, but this is a genuine timestamp.
The reason this is very strange: I since ran a script to create a new DateTime object with the timestamp passed in as a hard coded value, and it reported no errors.
This seems to have been a one off, but I need an explanation if there is one, as I can't afford for this to happen again.
You should use setTimestamp instead, if you hardcode it:
$start_date = new DateTime();
$start_date->setTimestamp(1372622987);
in your case
$start_date = new DateTime();
$start_date->setTimestamp($dbResult->db_timestamp);
Use the createFromFormat method:
$start_date = DateTime::createFromFormat("U", $dbResult->db_timestamp);
UPDATE
I now recommend the use of Carbon
change your code to this
$start_date = new DateTime( "#" . $dbResult->db_timestamp );
and it will work fine
This worked for me.
/**
* return date in specific format, given a timestamp.
*
* #param timestamp $datetime
* #return string
*/
public static function showDateString($timestamp)
{
if ($timestamp !== NULL) {
$date = new DateTime();
$date->setTimestamp(intval($timestamp));
return $date->format("d-m-Y");
}
return '';
}
$start_date = new DateTime();
$start_date->setTimestamp($dbResult->db_timestamp);
I am trying to return month difference as integer and call if to table column. My code:
function ETA($ArrivalDate, $pattern = 'mysql'){
$patterns = array(
'eu' => 'd/m/Y',
'mysql' => 'Y-m-d',
'us' => 'm/d/Y',
);
$CurrentDate = date("Y-m-d");
$ArrivalDate = $variants_data['ArrivalDate'];
$diff = $ArrivalDate->diff($CurrentDate);
return $diff->y;
}
The I call it with
<td>'.$_GET['ETA'].'</td>
But there is nothing returned, what am I doing wrong here?
You can get what you want in a simpler approach using the DateTime object in PHP:
function ETA($ArrivalDate){
$currentDate = new DateTime();
$arrivalDate = new DateTime($ArrivalDate);
$interval = $currentDate->diff($arrivalDate);
return $interval->format('%m');
}
See working example: http://3v4l.org/UlPQo
If you don't pass in an appropriate format $ArrivalDate you will get an exception thrown, so you need to wrap the call in a Try/Catch.
See DateTime Interval Format for more on the return value.
Try this simple one
<?php
//for months
$monthdiff=floor((abs(strtotime(date("d/m/Y")) - strtotime($ArrivalDate))/(60*60*24*30)));
//for days
$daydiff=floor((abs(strtotime(date("d/m/Y")) - strtotime($ArrivalDate))/(60*60*24)));
?>