DateTime not working for dates before 1970 [duplicate] - php

This question already has an answer here:
Create Date object in PHP for dates before 1970 in certain format
(1 answer)
Closed 4 years ago.
PHP v 5.6.2
I need to convert dates such as 18-Jul-46 to give me 18/07/1946 and no amount of DateTime functions work correctly. (As strtotime wont work for dates before 1970). They all end up giving 18/07/2046 which is incorrect.
Codes I tried so far:
$date = new DateTime("18-Jul-46");
$date->format('d/m/Y');
Another one with DateTime
$date = DateTime::createFromFormat('d-M-y', "18-Jul-46");
$date->format('d/m/Y');
Earlier also tried,
$date = date('d/m/Y', strtotime('18-Jul-46'));
None of them gave me the correct format. Any pointers or help is appreciated.
Thanks in advance!

If you have a date such as '31-Dec-18", it is ambiguous since it may refer to a date in 1918 or else a date in 2018. However, if you know that all the dates refer to the 1900s, then code such as the following is feasible given a two-digit year:
<?php
$now = new DateTime();
$formatted = "";
$arrFormattedBDays = [];
$birthdays = ['18-Jul-46','19-Aug-47','1-Jan-19','31-Dec-18'];
foreach ($birthdays as $b){
list($d,$m,$y) = explode("-",$b);
$y = '19'.$y;
$dt = new DateTime("$d-$m-$y");
$formatted = $dt->format('d/m/Y');
$arrFormattedBDays[] = $formatted;
}
var_dump($arrFormattedBDays);
Output:
array(4) {
[0]=>
string(10) "18/07/1946"
[1]=>
string(10) "19/08/1947"
[2]=>
string(10) "01/01/1919"
[3]=>
string(10) "31/12/1918"
See live code
Otherwise, by default DateTime creates a date object based on the current year which you may format according to the truth you seek to perpetuate; see here. Note: if you know that the dates all occur in the 20th century, i.e. 1901-2000, then you may amend this code by adding in a little logic; see here.

The computer doesn't know whether you mean 2000 or 1900. You can just take the last 2 digits of the year and put "19" before like:
$date = new DateTime("18-Jul-46");
$date->format('d/m/19y');
If you want to use 2000 as well, this code will use the closest number to 1970
$date = new DateTime("18-Jul-20");
$date->format('d/m/Y');
$t1 = $date->format('19y');
$t2 = $date->format('20y');
if(abs(1970-$t1)<abs(1970-$t2))
echo $t1; //Take the 19.. one
else
echo $t2; //Take the 20.. one
But in the end, you can't be sure that even 2030 would be correct.

Related

How to get time difference of a datetime value and a time value in PHP

I have one DATETIME value 'D1' and one TIME value 'T1'. I need to find difference of D1 and T1 after comparing these two values.
D1:2020-12-07 18:21:47 and T1:19:30:00
My code to find time difference:
if(strtotime(T1) > strtotime(D1)){
$diff = date("H:i:s",(strtotime(T1) - strtotime(D1)));
}`
I am getting incorrect result.
use this method to add date to your t1 value
date('Y-m-d',strtotime('2020-12-07 18:21:47'));
and then use this method to get difference
$starttimestamp = strtotime($startdatetime);
$endtimestamp = strtotime($enddatetime);
$difference = abs($endtimestamp - $starttimestamp)/3600; in hours difference
2020-12-07 18:21:47 is not a full date time value. It is missing the time zone which can lead to unexpected or wrong results.
strtotime() is a very old function. The better approach is the DateTimeImmutable class. You can set the time with DateTimeImmutable::setTime() and get the difference with DateTimeImmutable::diff().
$dates = [
new DateTimeImmutable('2020-12-07T00:21:47Z'),
new DateTimeImmutable('2020-12-07T00:21:47-0800'),
new DateTimeImmutable('2020-12-07 00:21:47', new DateTimeZone('+02:00')),
new DateTimeImmutable('2020-03-29 00:21:47', new DateTimeZone('Europe/Berlin')),
];
$timeParts = explode(':', '19:30:00');
foreach ($dates as $date) {
// get a modified copy of the immutable date time
$other = $date->setTime(...$timeParts);
var_dump($other->format(DateTimeInterface::ATOM));
// differences as a DateInterval
$difference = $date->diff($other);
var_dump($difference->format('%h hour(s), %i minute(s)'));
}
Output:
string(25) "2020-12-07T19:30:00+00:00"
string(23) "19 hour(s), 8 minute(s)"
string(25) "2020-12-07T19:30:00-08:00"
string(23) "19 hour(s), 8 minute(s)"
string(25) "2020-12-07T19:30:00+02:00"
string(23) "19 hour(s), 8 minute(s)"
string(25) "2020-03-29T19:30:00+02:00"
string(23) "18 hour(s), 8 minute(s)"
Notice that the last result is 18 hours. This is because on March 29th is the clock change to daylight saving time in this time zone.
The difference between two times on the same day is being sought. With this solution with DateTime, the date from $d1 is set to the current day, the difference is calculated and formatted.
$d1 = '2020-12-07 18:21:47';
$t1 = '19:30:00';
$diffHis = date_create($d1)
->modify(date('Y-m-d'))
->diff(date_create($t1))
->format('%r%H:%I:%s')
;
echo $diffHis; //01:08:13
Another variant uses DateTime::createFromFormat with a format that hides the date from $d1. So the time from $d1 gets the current date.
$diffHis = DateTime::createFromFormat('????-??-?? H:i:s',$d1)
->diff(date_create($t1))
->format('%r%H:%I:%s')
;
$d1 = '2020-12-07 18:21:47';
$t1 = date('Y-m-d',strtotime('2020-12-07 18:21:47')).' 19:30:00'; // or $t1 = '2020-12-07 19:30:00';
if( strtotime($t1) > strtotime($d1)){
$diff = date("H:i:s",(strtotime($t1) - strtotime($d1)));
}
print_r( $diff );
//should return you correct result
01:08:13
Check that you are passing vars in correct way.

Calculate months diff between dates without days

is there a good way to calculate months diff between dates without days? I mean I have two not full dates for example:
2017-09 and 2018-11. I need to calculate how many months is between this two dates. I read something about this and I know I can for example use:
$firstDate = "2017-09";
$secondDate = "2018-11";
$firstDate = new DateTime($firstDate . "-01");
$secondDate = new DateTime($secondDate . "-01");
$interval = date_diff($firstDate, $secondDate);
var_dump($interval->format('%m months'));exit();
This show me 2 months.
How can I reach this? And is there a way to calculate this without adding days "-01" to end of my dates?
I want to calculate difference of months for dates without write "-01" in this dates. Only year and month.
You need the years also.
Also you had a parse error on the date 2017-0901 is not valid either 2017-09 or 2017-09-01.
$firstDate = "2017-09";
$secondDate = "2018-11";
$firstDate = new DateTime($firstDate);
$secondDate = new DateTime($secondDate);
$interval = date_diff($firstDate, $secondDate);
echo $interval->format('%y')*12+$interval->format('%m') . " months";
// 14 months
https://3v4l.org/XGdXg
Just use plain arithmetic. We're clearly not concerned about timezones, daylight saving, calendar changes, etc. so we're also not concerned about parsing the date "in some timezone, based on some calendar". What we're left with is just plain arithemtics, using months. A year is 12 months. And now we're almost done already.
function ym_as_months($v) {
$v = array_map("intval", explode("-", $v));
return $v[0]*12 + $v[1];
}
$firstDate = "2017-09";
$firstMonths = ym_as_months($firstDate);
$secondDate = "2018-11";
$secondMonths = ym_as_months($secondDate);
$diff = $secondMonths - $firstMonths;
echo "There are $diff months between $firstDate and $secondDate.";
And we get:
There are 14 months between 2017-09 and 2018-11.
Perfect.
Of course, depending on how you get those date stamps in your application, it might be far easier to not even pass them in as string, but simply as two numbers from the get go, in which case this becomes even less work.
Alternatively, do your conversion as the very last step, as per another answer here.
I will suggest using Carbon for dates related calculations in PHP as it really makes everything easy.
To calculate months between two dates with Carbon, you simply need to do this
//year & month
$startDate = Carbon::create('2017', '9');
$endDate = Carbon::create('2018','11');
$diff = $startDate->diffInMonths($endDate);
https://secure.php.net/manual/en/datetime.createfromformat.php
$a = DateTime::createFromFormat('Y-m', '2017-09');
$b = DateTime::createFromFormat('Y-m', '2018-11');
$diff = $a->diff($b);
var_dump(
$a, $b,
$diff->format("%y years, %m months"),
sprintf("%d months", $diff->y * 12 + $diff->m)
);
Output:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2017-09-06 18:33:58.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(16) "Europe/Amsterdam"
}
object(DateTime)#2 (3) {
["date"]=>
string(26) "2018-11-06 18:33:58.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(16) "Europe/Amsterdam"
}
string(17) "1 years, 2 months"
string(9) "14 months"

Convert String to date (european to american) [duplicate]

This question already has answers here:
Convert one date format into another in PHP
(17 answers)
Closed 6 years ago.
I have a String on the form: "dd/mm-yyyy", where dd is day of the month with two digits, mm is the month represented with two digits, and yyyy is the year with four digits.
I need to store this in my database. Ive tried
$dato = date('d/m-Y' ,strtotime($_POST['dag'] )
But that clearly doesnt work. In my database the date displays as yyyy-mm-dd. How do I properly convert the String to the correct format?
strtotime not accept your time string format, so it return false. You can use DateTime::createFromFormat or date_create_from_format, manual here.
DateTime::createFromFormat('d/m-Y', $_POST['dag']);
check the live demo
<?php
var_dump(DateTime::createFromFormat('d/m-Y', '11/01-2017'));
putput:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2017-01-11 14:34:53.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}
Try to replace the / with a - like so:
$date = "02/04-2016";
$dateNew = str_replace("/","-",$date);
You can use DateTime::createFromFormat:
$time = '12/3-1987';
$data = DateTime::createFromFormat('d/m-Y', $time);
echo $data->format('Y-m-d'); //1987-03-12
sandbox

How to determine if a date is more than three months past current date

I am getting a date back from a mysql query in the format YYYY-MM-DD.
I need to determine if that is more than three months in the past from the current month.
I currently have this code:
$passwordResetDate = $row['passwordReset'];
$today = date('Y-m-d');
$splitCurrentDate = explode('-',$today);
$currentMonth = $splitCurrentDate[1];
$splitResetDate = explode('-', $passwordResetDate);
$resetMonth = $splitResetDate[1];
$diferenceInMonths = $splitCurrentDate[1] - $splitResetDate[1];
if ($diferenceInMonths > 3) {
$log->lwrite('Need to reset password');
}
The problem with this is that, if the current month is in January, for instance, giving a month value of 01, and $resetMonth is November, giving a month value of 11, then $differenceInMonths will be -10, which won't pass the if() statement.
How do I fix this to allow for months in the previous year(s)?
Or is there a better way to do this entire routine?
Use strtotime(), like so:
$today = time(); //todays date
$twoMonthsLater = strtotime("+3 months", $today); //3 months later
Now, you can easily compare them and determine.
I’d use PHP’s built-in DateTime and DateInterval classes for this.
<?php
// create a DateTime representation of your start date
// where $date is date in database
$resetDate = new DateTime($date);
// create a DateIntveral representation of 3 months
$passwordExpiry = new DateInterval('3M');
// add DateInterval to DateTime
$resetDate->add($passwordExpiry);
// compare $resetDate to today’s date
$difference = $resetDate->diff(new DateTime());
if ($difference->m > 3) {
// date is more than three months apart
}
I would do the date comparison in your SQL expression.
Otherwise, PHP has a host of functions that allow easy manipulation of date strings:
PHP: Date/Time Functions - Manual

PHP convert 2 digit year to a 4 digit year

I have data coming from the database in a 2 digit year format 13 I am looking to convert this to 2013 I tried the following code below...
$result = '13';
$year = date("Y", strtotime($result));
But it returned 1969
How can I fix this?
$dt = DateTime::createFromFormat('y', '13');
echo $dt->format('Y'); // output: 2013
69 will result in 2069. 70 will result in 1970. If you're ok with such a rule then leave as is, otherwise, prepend your own century data according to your own rule.
One important piece of information you haven't included is: how do you think a 2-digit year should be converted to a 4-digit year?
For example, I'm guessing you believe 01/01/13 is in 2013. What about 01/01/23? Is that 2023? Or 1923? Or even 1623?
Most implementations will choose a 100-year period and assume the 2-digits refer to a year within that period.
Simplest example: year is in range 2000-2099.
// $shortyear is guaranteed to be in range 00-99
$year = 2000 + $shortyear;
What if we want a different range?
$baseyear = 1963; // range is 1963-2062
// this is, of course, years of Doctor Who!
$shortyear = 81;
$year = 100 + $baseyear + ($shortyear - $baseyear) % 100;
Try it out. This uses the modulo function (the bit with %) to calculate the offset from your base year.
$result = '13';
$year = '20'.$result;
if($year > date('Y')) {
$year = $year - 100;
}
//80 will be changed to 1980
//12 -> 2012
Use the DateTime class, especially DateTime::createFromFormat(), for this:
$result = '13';
// parsing the year as year in YY format
$dt = DateTime::createFromFormat('y', $result);
// echo it in YYYY format
echo $dt->format('Y');
The issue is with strtotime. Try the same thing with strtotime("now").
Simply prepend (add to the front) the string "20" manually:
$result = '13';
$year = "20".$result;
echo $year; //returns 2013
This might be dumbest, but a quick fix would be:
$result = '13';
$result = '1/1/20' . $result;
$year = date("Y", strtotime($result)); // Returns 2013
Or you can use something like this:
date_create_from_format('y', $result);
You can create a date object given a format with date_create_from_format()
http://www.php.net/manual/en/datetime.createfromformat.php
$year = date_create_from_format('y', $result);
echo $year->format('Y')
I'm just a newbie hack and I know this code is quite long. I stumbled across your question when I was looking for a solution to my problem. I'm entering data into an HTML form (too lazy to type the 4 digit year) and then writing to a DB and I (for reasons I won't bore you with) want to store the date in a 4 digit year format. Just the reverse of your issue.
The form returns $date (I know I shouldn't use that word but I did) as 01/01/01. I determine the current year ($yn) and compare it. No matter what year entered is if the date is this century it will become 20XX. But if it's less than 100 (this century) like 89 it will come out 1989. And it will continue to work in the future as the year changes. Always good for 100 years. Hope this helps you.
// break $date into two strings
$datebegin = substr($date, 0,6);
$dateend = substr($date, 6,2);
// get last two digits of current year
$yn=date("y");
// determine century
if ($dateend > $yn && $dateend < 100)
{
$year2=19;
}
elseif ($dateend <= $yn)
{
$year2=20;
}
// bring both strings back into one
$date = $datebegin . $year2 . $dateend;
I had similar issues importing excel (CSV) DOB fields, with antiquated n.american style date format with 2 digit year. I needed to write proper yyyy-mm-dd to the db. while not perfect, this is what I did:
//$col contains the old date stamp with 2 digit year such as 2/10/66 or 5/18/00
$yr = \DateTime::createFromFormat('m/d/y', $col)->format('Y');
if ($yr > date('Y')) $yr = $yr - 100;
$md = \DateTime::createFromFormat('m/d/y', $col)->format('m-d');
$col = $yr . "-" . $md;
//$col now contains a new date stamp, 1966-2-10, or 2000-5-18 resp.
If you are certain the year is always 20 something then the first answer works, otherwise, there is really no way to do what is being asked period. You have no idea if the year is past, current or future century.
Granted, there is not enough information in the question to determine if these dates are always <= now, but even then, you would not know if 01 was 1901 or 2001. Its just not possible.
None of us will live past 2099, so you can effectively use this piece of code for 77 years.
This will print 19-10-2022 instead of 19-10-22.
$date1 = date('d-m-20y h:i:s');

Categories