Conditional display of start and end dates (PHP/Wordpress) - wordpress

(As you can tell from this post I am not a programmer, so please help me to see if this is even possible... )
I want to improve the Start / End date display for events in Events Manager (plugin for WordPress)
At the moment the the end times will only show up if different then the start date (good!) but will be in the format:
1 January 2014 - 31 January 2014.
I would like it to display as: 1 - 31 January 2014.
That isn't too hard, but it becomes a little more complicated when events wrap or extend past a month, or a year.
Here are the different cases I am trying to achieve:
Start date only:
1 January 2014
Start and end date in same month
1 – 12 January 2014
Start and end date in different month but same year.
28 January – 3 February 2014
Start and end date in different months and different years.
31 December 2014 – 3 January 2015
Can anyone tell me
a) if this is at all possible to do with a function in the WordPress functions file?
and
b) point me in the right direction on how to do the conditioning?
I don't even know what to google for, so even that would be a help. (I am not expecting a fully working code example, although you are more then welcome to include that if you want!)
Update: Here is an example of a function that does some of this, but only in the style of the last case in my list above.
add_filter('em_event_output_placeholder','my_em_placeholder_mod_eventdates',1,3);
function my_em_placeholder_mod_eventdates($replace, $EM_Event, $result){
if ( $result == '#_EVENTDATES' ) {
if( $EM_Event->event_start_date != $EM_Event->event_end_date){
$replace = date_i18n('d M Y', $EM_Event->start).' - '. date_i18n('d M Y', $EM_Event->end);
}else{
$replace = date_i18n('d M Y', $EM_Event->start);
}
}
return $replace;
}
Update 2, with working code:
This code works for me at least.
add_filter('em_event_output_placeholder','my_em_placeholder_mod_eventdates',1,3);
function my_em_placeholder_mod_eventdates($replace, $EM_Event, $result){
if ( $result == '#_EVENTDATES' ) :
$sd = $EM_Event->start;
$ed = $EM_Event->end;
if (!empty ($ed) && $sd != $ed ) {
//Event has an end date and end date is different than start date
if (date('Y', $sd) == date('Y', $ed)) {
// Start and end are in same year
if (date('n', $sd) == date('n', $ed)) {
//Start and end are in the same month
$replace = date_i18n('j', $sd).'-'.date_i18n('j F Y', $ed);
if (date('j', $sd) == date('j', $ed)) {
//Start and end are on the same day
$replace = date_i18n('j F Y', $sd);
}
} else {
//Start and end are in different months
$replace = date_i18n('j F', $sd).' - '.date_i18n('j F Y', $ed);
}
} else {
//Start and end are in different years
$replace = date_i18n('j F Y', $sd).' - '. date_i18n('j F Y', $ed);
}
} else {
// No end date, or start and end date are the same
$replace = date_i18n('j F Y', $sd);
}
endif;
return $replace;
}

Try this:
add_filter('em_event_output_placeholder','my_em_placeholder_mod_eventdates',1,3);
function my_em_placeholder_mod_eventdates($replace, $EM_Event, $result){
if ( $result == '#_EVENTDATES' ) :
$sd = $EM_Event->event_start_date;
$ed = $EM_Event->event_end_date;
if (!empty ($ed) && $sd != $ed ) {
//Event has an end date and end date is different than start date
if (date('Y', $sd) == date('Y'. $ed) {
// Start and end are in same year
if (date('n', $sd) == date('n', $ed) {
//Start and end are in the same month
$replace = date_i18n('j', $sd).'-'.date_i18n('j F Y', $ed);
} else {
//Start and end are in different months
$replace = date_i18n('j F', $sd).' - '.date_i18n('j F Y', $ed);
}
} else {
//Start and end are in different years
$replace = date_i18n('j F Y', $sd).' - '. date_i18n('j F Y', $ed);
}
} else {
// No end date, or start and end date are the same
$replace = date_i18n('j F Y', $sd);
}
endif;
return $replace;
}

Related

Display date range from 2 custom date-picker fields

I've created two custom datepicker fields with ACF (beginning_date and completion_date) and need to output/display these as a date range.
For example, if beginning_date Year and completion_date Year are equal, I need to output beginning_date day/month - completion day/month/year.
The display and return format these fields use is: l, F j, Y
I've searched everywhere! And tried to implement this: Create display date range from two dates in ACF in Wordpress
I also attempted to convert the fields to datetime objects but comparing these as dates seems to be the wrong way! I do not know where else I'm failing at...
I'm beginning again as nothing has worked so far, so I have no code to publish here because I ended up with a Frankenstein code snippet which I deleted and then came here for desperate help!
in your functions.php
function date_compare($id){
$start_date = get_field('beginning_date', $id);
$end_date = get_field('completion_date', $id);
$start_year = wp_date("Y", strtotime( $start_date ) );
$end_year = wp_date("Y", strtotime( $start_date ) );
$start_month = wp_date("n", strtotime( $start_date ) );
$end_month = wp_date("n", strtotime( $start_date ) );
$date_output = '';
$start_date_format = "l, F j, Y";
if( $start_date && $end_date ){
if( $start_year == $end_year && $start_month == $end_month ){
$start_date_format = "l j";
}
elseif( $start_year == $end_year){
$start_date_format = "l, F j";
}
}
if( $start_date ){
$date_output .= wp_date($start_date_format, strtotime( $start_date ) );
}
if( $end_date ){
$date_output .= ' - ' . wp_date("l, F j, Y", strtotime( $end_date ) );
}
return $date_output;
}
and in your theme:
echo date_compare($post->ID);

PHP: Calculating Monthly/Yearly Billing Dates - Same day next month

I've been looking for a way to accurately calculate the next/future billing date in a way that a month will not be skipped. For example for Jun 31 I want the next billing date to be Feb 28 (or 29 when applicable).
I found this great solution.
Here is an update of that code to support more than 1 month in the future.
Hope that helps.
Code:
function calculateBillingDate($startDate, $numberOfCycles = 1) {
$currentMonth = date('n', $startDate);
$nextMonth = (($currentMonth + $numberOfCycles) % 12);
if ($nextMonth === 0) {
$nextMonth = 12;
}
$targetDate = new \DateTime();
$targetDate->setTimestamp($startDate);
$targetDate->add(new \DateInterval('P' . $numberOfCycles . 'M'));
while ((int)$targetDate->format('m') !== $nextMonth) {
$targetDate->sub(new \DateInterval('P1D'));
}
return $targetDate;
}

Symfony 2 Bizarre behavior in the controller

Symfony 2.3
I have two fields on the form with dates: the date_from and date_to.
The controller after submit performs its own validation. After automatic validatin is OK make my own validation of dates. Before adding the code below the form and submit displays after validation:
date_from 2015-10-01 and date_to 2015-10-02
and after adding the code form displays before submit:
date_from 2015-10-01 and date_to 2015-10-02
after submit:
date_from 2015-10-02 and date_to 2015-10-01
Dates are switched. So it writes to the database.
$date_from = $entity->getDatefrom();
$date_to = $entity->getDateto();
$workdays = 0;
for ( $i = $date_from; $i <= $date_to; $i->setTimestamp(strtotime($i->format('Y-m-d') . " +1 day") ) )
{
if ( !in_array($i, $freedays))
{
if ( date('N', strtotime($i->format('Y-m-d') ) ) < 6 )
{
$workdays++ ;
}
}
}
When i remove this code dates are not switched. But ofcourse i don't have count of working days.
You need to dereference the DateTime Object $date_from using clone before assigning it to $i.
http://php.net/manual/en/language.oop5.references.php
$date_from = $entity->getDatefrom();
$date_to = $entity->getDateto();
$workdays = 0;
for ( $i = clone $date_from; $i <= $date_to; $i->setTimestamp(strtotime($i->format('Y-m-d') . " +1 day") ) )
{
if ( !in_array($i, $freedays))
{
if ( date('N', strtotime($i->format('Y-m-d') ) ) < 6 )
{
$workdays++ ;
}
}
}
PHP doesn't copy objects when assigning them to a new variable it just creates a reference.
$i = $date_from
In this for loop it updates the $i for each iteration
$i->setTimestamp(strtotime($i->format('Y-m-d') . " +1 day") )
Because it's only a reference its this same as
$date_from->setTimestamp(strtotime($i->format('Y-m-d') . " +1 day") )
// OR even
$entity->getDatefrom()->setTimestamp(strtotime($i->format('Y-m-d') . " +1 day") )
Using clone make a copy of the original so $i->setTimestamp(...) won't actually apply to $date_from

Month conversion to words

I have dates stored in array for completion status of projects like below
The first two letters are months and other four letters are years
052012(mmyyyy)
$arrDates = array('052012', '042013', '082013', '122013', '022014');
I want this array To get converted to wordings as below
$arrDates = array('Completed', 'Next Six Months', 'Next Year', 'Next Year', 'After 2 Years');
I used a for loop like below for checking completed as below
for($i=0;$i<count($arrDates);$i++)
{
if((date('m') > substr($arrDates[$i], 0,2)) && (date('y') == substr($arrDates[$i], 2,6)))
$strStatus = ' Completed';
}
and I messed up in finding for next year and other two.
Could some one help me in fixing this?
I think you can use DateTime and dateInterval for this :
$currentDate = DateTime::createFromFormat('mY',$arrDates[0]);
$interval = $currentDate->diff(new DateTime('now'),true);
if($interval->invert){
echo 'Completed';
else if($interval->y >= 2 ){
echo 'After 2 Years';
}
else if($interval->y == 1){
echo 'Next Year';
}
else if($interval->m > 6){
echo 'what you want here';
}
else {
echo 'Next six months';
}
I think artragis was on the right track with his answer (+1 for that), but the whole thing should be encapsulated in a function for re-use.
/**
* #param string $expectedDate
* #return string Text summary of time to completion
*/
function completionTimeInWords($expectedDate)
{
$now = new DateTime();
$date = new DateTime();
$date->setTimestamp(strtotime('+1 year'));
$oneYear = $date->diff($now)->days;
$sixMonths = round($oneYear/2);
$date->setTimestamp(strtotime('+2 years'));
$twoYears = $date->diff($now)->days;
$date = DateTime::createFromFormat('mY', $expectedDate);
$interval = $now->diff($date);
$completed = (bool)$interval->invert;
$days = $interval->days;
if($completed){
return 'Completed';
} elseif($days <= $sixMonths){
return 'Next Six Months';
} elseif($days > $sixMonths && $days <= $oneYear){
return 'Within a year';
} elseif($days > $oneYear && $days <= $twoYears){
return 'Next Year';
} elseif($days > $twoYears){
return 'After Two Years';
}
}
I tested this with the following code:-
$date = new DateTime();
$date->setTimestamp(strtotime('two weeks ago'));
$arrDates[] = $date->format('mY');
$date->setTimestamp(strtotime('+ 5 months 27 days'));
$arrDates[] = $date->format('mY');
$date->setTimestamp(strtotime('+ 6 months 4 days'));
$arrDates[] = $date->format('mY');
$date->setTimestamp(strtotime('+ 12 months 4 days'));
$arrDates[] = $date->format('mY');
$date->setTimestamp(strtotime('+ 24 months 4 days'));
$arrDates[] = $date->format('mY');
foreach($arrDates as $date){
var_dump(completionTimeInWords($date));
}
and got the following output:-
string(9) "Completed"
string(15) "Next Six Months"
string(13) "Within a year"
string(9) "Next Year"
string(15) "After Two Years"
You may need to do some more testing with edge cases as these can be problematic. For example, most of us would agree that 6 months is 183 days, but PHP may disagree on occasion depending on how many days are in each month between now and 6 months hence (if that makes sense). That is why I have divided a year by 2 to get 6 months, rather than using strtotime().

Compare Groovy dates ignoring days

How can I compare dates in Groovy ignoring days? Something like this: *MM-yyyy_1 > MM-yyyy_2*
You could do this:
int compareIgnoringDays( Date a, Date b ) {
new Date( a.time ).with { newa ->
new Date( b.time ).with { newb ->
newa.set( date:1 )
newb.set( date:1 )
newa.compareTo( newb )
}
}
}
Which you can test like:
Date a = Date.parse( 'yyyy/MM/dd', '2012/05/23' )
Date b = Date.parse( 'yyyy/MM/dd', '2012/05/24' )
Date c = Date.parse( 'yyyy/MM/dd', '2012/06/01' )
assert compareIgnoringDays( a, b ) == 0
assert compareIgnoringDays( b, a ) == 0
assert compareIgnoringDays( a, c ) == -1
assert compareIgnoringDays( c, a ) == 1
A different way of writing the same functionality is:
int compareIgnoringDays( Date a, Date b ) {
[ a, b ].collect { new Date( it.time ) } // Clone original dates
.collect { it.set( date:1 ) ; it } // Set clones to 1st of the month
.with { newa, newb ->
newa.compareTo( newb ) // Compare them (this gets returned)
}
}
You can compare two dates like this:
def myFormat = 'MM/dd/yyyy'
if(Date.parse(myFormat, '02/03/2012') >= Date.parse(myFormat, '03/02/2012))
{...}

Resources