PHP convert 2 digit year to a 4 digit year - php

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');

Related

Date format in float from Persavise db

I got data from a Persavive V12 Db. The dates are in a weird format.
They are like float :
Example of date in table : 39787.0
Do someone know this kind of format ? It seems to be the number of days from 1901-01-01.
Since the dates are float, is it possible to add days from a date in PHP ? Like :
$from = '1901-01-01';
$date = date('Y-m-d', strtotime($from .' +'. $float .' days'));
I got always 1970-01-01. Is there another way ?
My first answer so don't hurt me much.
I'm not quite sure what you want to do (put back in the database or perform further operations so I only posted one solution)
The number you posted 39787.0 is a unix timestamp. You need to use mktime to convert what you want to a number (And you need date to convert it to a readable form). Since mktime uses 1901-01-01 as a starting date as well you have to make a couple of changes.
I was a biz lazy and didn't include all the code for all fields but this should allow you modify to add whatever you want (and possibly clean it up to a single line if you want).
I made it in long form so it's easy to read.
<?
$olddate = 39787.0;
$hour = 0;
$min = 0;
$sec = 0;
$month = 0;
$year = 0;
$day = 12;
$month += date("m",$olddate);
$day += date("d",$olddate);
$year += date("Y",$olddate);
$x = date("Ymd",mktime($hour,$min,$sec,$month,$day,$year));
echo $x;
?>
If 39787.0 is in the database, what value is that in a real date (using the application)? If it's 2008-12-05, the it's a VB Date. Do you know what the application was written in? I've seen people use the VB Date data type and store it in an 8 byte float in Btrieve (back in 2003). If it's a VB Date, 1 is 1899-12-31. You should be able to add the number to 1899-12-30 to get the correct date value. Something like:
<?php
$date = new DateTime('1899-12-30');
$date->add(new DateInterval('P39787D'));
echo $date->format('Y-m-d') . "\n";
?>

PHP DateTime credit card expiration

I'm trying to use DateTime to check if a credit card expiry date has expired but I'm a bit lost.
I only want to compare the mm/yy date.
Here is my code so far
$expmonth = $_POST['expMonth']; //e.g 08
$expyear = $_POST['expYear']; //e.g 15
$rawExpiry = $expmonth . $expyear;
$expiryDateTime = \DateTime::createFromFormat('my', $rawExpiry);
$expiryDate = $expiryDateTime->format('m y');
$currentDateTime = new \DateTime();
$currentDate = $currentDateTime->format('m y');
if ($expiryDate < $currentDate) {
echo 'Expired';
} else {
echo 'Valid';
}
I feel i'm almost there but the if statement is producing incorrect results. Any help would be appreciated.
It's simpler than you think. The format of the datess you are working with is not important as PHP does the comparison internally.
$expires = \DateTime::createFromFormat('my', $_POST['expMonth'].$_POST['expYear']);
$now = new \DateTime();
if ($expires < $now) {
// expired
}
You can use the DateTime class to generate a DateTime object matching the format of your given date string using the DateTime::createFromFormat() constructor.
The format ('my') would match any date string with the string pattern 'mmyy', e.g. '0620'. Or for dates with 4 digit years use the format 'mY' which will match dates with the following string pattern 'mmyyyy', e.g. '062020'. It's also sensible to specify the timezone using the DateTimeZone class.
$expiryMonth = 06;
$expiryYear = 20;
$timezone = new DateTimeZone('Europe/London');
$expiryTime = \DateTime::createFromFormat('my', $expiryMonth.$expiryYear, $timezone);
See the DateTime::createFromFormat page for more formats.
However - for credit/debit card expiry dates you will also need to take into account the full expiry DATE and TIME - not just the month and year.
DateTime::createFromFormat will by default use todays day of the month (e.g. 17) if it is not specified. This means that a credit card could appear expired when it still has several days to go. If a card expires 06/20 (i.e. June 2020) then it actually stops working at 00:00:00 on 1st July 2020. The modify method fixes this. E.g.
$expiryTime = \DateTime::createFromFormat('my', $expiryMonth.$expiryYear, $timezone)->modify('+1 month first day of midnight');
The string '+1 month first day of midnight' does three things.
'+1 month' - add one month.
'first day of' - switch to the first day of the month
'midnight' - change the time to 00:00:00
The modify method is really useful for many date manipulations!
So to answer the op, this is what you need — with a slight adjustment to format to cater for single digit months:
$expiryMonth = 6;
$expiryYear = 20;
$timezone = new DateTimeZone('Europe/London');
$expiryTime = \DateTime::createFromFormat(
'm-y',
$expiryMonth.'-'.$expiryYear,
$timezone
)->modify('+1 month first day of midnight');
$currentTime = new \DateTime('now', $timezone);
if ($expiryTime < $currentTime) {
// Card has expired.
}
An addition to the above answers.
Be aware that by default the days will also be in the calculation.
For example today is 2019-10-31 and if you run this:
\DateTime::createFromFormat('Ym', '202111');
It will output 2021-12-01, because day 31 does not exist in November and it will add 1 extra day to your DateTime object with a side effect that you will be in the month December instead of the expected November.
My suggestion is always use the day in your code.
For op's question:
$y=15;
$m=05;
if(strtotime( substr(date('Y'), 0, 2)."{$y}-{$m}" ) < strtotime( date("Y-m") ))
{
echo 'card is expired';
}
For others with full year:
$y=2015;
$m=5;
if(strtotime("{$y}-{$m}") < strtotime( date("Y-m") ))
{
echo 'card is expired';
}
Would it not be simpler to just compare the string "201709" to the current year-month? Creating datetime objects will cost php some effort, I suppose.
if($_POST['expYear']. str_pad($_POST['expMonth'],2,'0', STR_PAD_LEFT ) < date('Ym')) {
echo 'expired';
}
edited as Adam states
The best answer is provided by John Conde above. It it does the minimum amount of processing: creates two correct DateTime objects, compares them and that's all it needs.
It could work also as you started but you must format the dates in a way that puts the year first.
Think a bit about it: as dates, 08/15 (August 2015) is after 12/14 (December 2014) but as strings, '08 15' is before '12 14'.
When the year is in front, even as strings the years are compared first and then, only when the years are equal the months are compared:
$expiryDate = $expiryDateTime->format('y m');
$currentDate = $currentDateTime->format('y m');
if ($expiryDate < $currentDate) {
echo 'Expired';
} else {
echo 'Valid';
}
Keep it simple, as the answer above me says except you need to string pad to the left:
isCardExpired($month, $year)
{
$expires = $year.str_pad($month, 2, '0', STR_PAD_LEFT);
$now = date('Ym');
return $expires < $now;
}
No need to add extra PHP load using DateTime
If you are using Carbon, which is a very popular Datetime extension library. Then this should be:
$expMonth = $_POST['month'];
$expYear = $_POST['year'];
$format_m_y = str_pad($expMonth,2,'0', STR_PAD_LEFT).'-'.substr($expYear, 2);
$date = \Carbon\Carbon::createFromFormat('m-y', $format_m_y)
->endOfMonth()
->startOfDay();
if ($date->isPast()) {
// this card is expired
}
Also take into consideration the exact date and time expiration:
Credit cards expire at the end of the month printed as its expiration date, not at the beginning. Many cards actually technically expire one day after the end of that month. In any case, unless they list a specific day of expiration along with month and year, they should work all the way through the end of their expiration month. Cardholders should not wait until the last moment to secure a replacement card. Source

Add 12 months to a date string and return in same format 201301 (Ym)

How can I add months to a date string such as 201308 (for August 2013) and return it in the same format, ie 201408 (for August 2014)? I've tried:
$dateToDflt = "201308";
$dateToDflt = strtotime(date("Ym", strtotime($dateToDflt)) . " +12 months");
$dateToDflt = date("Ym",$dateToDflt);
This just brings back 12 months ahead of the today's date so I think I'm getting my time and date formats confused
$date = DateTime::createFromFormat('Ym', $dateToDflt);
$date->modify('+12 months')
$dateToDflt = $date->format('Ym');
Or simple string manipulation including casting
$dateToDflt[3] = $dateToDflt[3] + 1;
Of course works only for years 2010 to 2018. To extend to range to 2098, add this ;)
$dateToDflt[2] += (int) ($dateToDflt[3] == 0);
http://codepad.org/43LACMoZ ;)

Can't get previous month from DateTime in PHP- Is this a (pretty big) bug?

I need to create functions in PHP that let me step up/down given datetime units. Specifically, I need to be able to move to the next/previous month from the current one.
I thought I could do this using DateTime::add/sub(P1M). However, when trying to get the previous month, it messes up if the date value = 31- looks like it's actually trying to count back 30 days instead of decrementing the month value!:
$prevMonth = new DateTime('2010-12-31');
Try to decrement the month:
$prevMonth->sub(new DateInterval('P1M')); // = '2010-12-01'
$prevMonth->add(DateInterval::createFromDateString('-1 month')); // = '2010-12-01'
$prevMonth->sub(DateInterval::createFromDateString('+1 month')); // = '2010-12-01'
$prevMonth->add(DateInterval::createFromDateString('previous month')); // = '2010-12-01'
This certainly seems like the wrong behavior. Anyone have any insight?
Thanks-
NOTE: PHP version 5.3.3
(Credit actually belongs to Alex for pointing this out in the comments)
The problem is not a PHP one but a GNU one, as outlined here:
Relative items in date strings
The key here is differentiating between the concept of 'this date last month', which, because months are 'fuzzy units' with different numbers of dates, is impossible to define for a date like Dec 31 (because Nov 31 doesn't exist), and the concept of 'last month, irrespective of date'.
If all we're interested in is the previous month, the only way to gaurantee a proper DateInterval calculation is to reset the date value to the 1st, or some other number that every month will have.
What really strikes me is how undocumented this issue is, in PHP and elsewhere- considering how much date-dependent software it's probably affecting.
Here's a safe way to handle it:
/*
Handles month/year increment calculations in a safe way,
avoiding the pitfall of 'fuzzy' month units.
Returns a DateTime object with incremented month/year values, and a date value == 1.
*/
function incrementDate($startDate, $monthIncrement = 0, $yearIncrement = 0) {
$startingTimeStamp = $startDate->getTimestamp();
// Get the month value of the given date:
$monthString = date('Y-m', $startingTimeStamp);
// Create a date string corresponding to the 1st of the give month,
// making it safe for monthly/yearly calculations:
$safeDateString = "first day of $monthString";
// Increment date by given month/year increments:
$incrementedDateString = "$safeDateString $monthIncrement month $yearIncrement year";
$newTimeStamp = strtotime($incrementedDateString);
$newDate = DateTime::createFromFormat('U', $newTimeStamp);
return $newDate;
}
Easiest way to achieve this in my opinion is using mktime.
Like this:
$date = mktime(0,0,0,date('m')-1,date('d'),date('Y'));
echo date('d-m-Y', $date);
Greetz Michael
p.s mktime documentation can be found here: http://nl2.php.net/mktime
You could go old school on it and just use the date and strtotime functions.
$date = '2010-12-31';
$monthOnly = date('Y-m', strtotime($date));
$previousMonth = date('Y-m-d', strtotime($monthOnly . ' -1 month'));
(This maybe should be a comment but it's to long for one)
Here is how it works on windows 7 Apache 2.2.15 with PHP 5.3.3:
<?php $dt = new DateTime('2010-12-31');
$dt->sub(new DateInterval('P1M'));
print $dt->format('Y-m-d').'<br>';
$dt->add(DateInterval::createFromDateString('-1 month'));
print $dt->format('Y-m-d').'<br>';
$dt->sub(DateInterval::createFromDateString('+1 month'));
print $dt->format('Y-m-d').'<br>';
$dt->add(DateInterval::createFromDateString('previous month'));
print $dt->format('Y-m-d').'<br>'; ?>
2010-12-01
2010-11-01
2010-10-01
2010-09-01
So this does seem to confirm it's related to the GNU above.
Note: IMO the code below works as expected.
$dt->sub(new DateInterval('P1M'));
Current month: 12
Last month: 11
Number of Days in 12th month: 31
Number of Days in 11th month: 30
Dec 31st - 31 days = Nov 31st
Nov 31st = Nov 1 + 31 Days = 1st of Dec (30+1)

Reformat Custom Date in PHP

So I know how to format a date in PHP, but not from a custom format. I have a date that is a string "YYMMDD" and I want to make it "MMDDYYYY'. strtotime doesn't seem like it would do a good job of this when the MM and DD are both low digits.
Use str_split:
$date1 = "YYMMDD";
list($yy, $mm, $dd) = str_split($date1, 2);
// MMDDYYYY format, assuming they are all > 2000
$date2 = $mm . $dd . "20" . $yy;
If you're running PHP >= 5.3, have a look at DateTime::createFromFormat. Otherwise, if you don't want to use pure string manipulation techniques, use the more primitive strptime together with mktime to parse the time into a UNIX timestamp, which you can then format using date.
Maybe I am under-thinking this, but couldn't you just:
$oldDate='040220'; // February 20th, 2004
$year = substr($oldDate, 0,2);
$year += $year &lt 50 ? 2000 : 1900;
$date = preg_replace('/\d{2}(\d{2})(\d{2})/', '$1/$3/'.$year, $oldDate);
And you'd have the string you were looking for, or something close enough to it that you could modify from what I wrote here.
Have many dates prior to 1910? If not, you could check your YY for <=10, and if true, prepend "20" else prepend "19"... Kinda similar approach to MM and DD check for <10 and prepend a "0" if true... (This is all after exploding, or substring... Assign each part to its own variable, i.e. $M=$MM; $D=$DD; $Y=$YYYY; then concatenate/arrange in whatever order you want... Just another potential way to skin the proverbial cat...
Ended up doing:
$expiration_date_year = substr($matches['expiration_date'],0,2);
$expiration_date_month = substr($matches['expiration_date'],2,2);
$expiration_date_day = substr($matches['expiration_date'],4,2);
$expiration_date = date('m/d/Y', mktime(0,0,0,$expiration_date_month, $expiration_date_day, $expiration_date_year));

Categories