Working with bitcode - php

This is slightly OT for SO, because I'm not trying to solve a specific problem, instead just to understand how something might be implemented. But I am after code, so let's see how it goes...
Let's say we had a checkbox for each day of the week, and we decided to store any combination of those checkboxes as a single number, such that:
0 = no days
1 = Monday
2 = Tuesday
4 = Wednesday
8 = Thursday
16 = Friday
32 = Saturday
64 = Sunday
127 = everyday
How might one go about implementing that logic in PHP so that if I submitted say, "13", PHP would know to tick only the Monday, Wednesday and Thursday checkboxes?

Bitwise ANDs:
$input = 13;
if( $input & 1 ) {
echo 'Monday';
}
if( $input & 2 ) {
echo 'Tuesday';
}
if( $input & 4 ) {
echo 'Wednesday';
}
// etc
edit
You can avoid the ifs with something like:
$input = 13;
$days = array('mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun');
for( $i=0; $i<7; $i++ ) {
$daybit = pow(2,$i);
if( $input & $daybit ) {
echo $days[$i] . ' ';
}
}
//output: mon wed thu
There's more than these two ways to skin this particular cat, but the 'best' way depends on what your result/output needs to be.

As to avoid code structure duplication (lots of similar if clauses) and introducing extra "magic" numbers (2, 7), as shown Sammitch's working suggestions, I'd prefer the following.
$daymap = array(
1 => Monday,
2 => Tuesday,
4 => Wednesday,
8 => Thursday,
16 => Friday,
32 => Saturday,
64 => Sunday
);
$input = 13;
foreach ($daymap as $code => $name) {
if ($input & $code) {
echo $name.' ';
}
}

Related

How can I create an automatic update on a web page based on date/time?

I am managing an internet radio station webpage and I would like to add an auto entry for the station's programming based on the day of week / time of day. For example at 8.00am on a Monday to Friday the "Now Playing" title shows "The Breakfast Show", at 10.00am it changes to "The Fred and Lucy Hour", and on a Sunday at 6.00pm it shows "The Hymn Hour"" etc. etc.
I have worked out how to get the server date and time on the webpage using PHP, and I am guessing this should somehow be linked to an SQL Database which contains all the shows and their timings, but as a complete novice on all things PHP and SQL I have no idea how to link them together (if indeed it is possible) or whether any other additional programming is necessary.
I would appreciate a steer in the right direction from someone better qualified than me.
Thanks in advance.
UPDATE:-
For various reasons I chose to go with the coding based on an array of Weekdays / Times/ Shows and initially it seemed to work well until I realised that even though I set the "$hour = date('H:i');", the code seemed to ignore the minutes in the array list. Following further advice (see comments below) I have overcome the problem and the code immediately below has been updated and is now in use. (Note I have shown a shortened test version of the array which can be amended and added to as required.):-
$shows = [
3 => [
'20:00' => 'Test result A',
'20:30' => 'Test result B',
'21:00' => 'Test result C',
'21:10' => 'Test result D',
'21:30' => 'Test result E'
],
];
$weekday = date('N');
$hour = date('H:i');
$now_plaing = 'Default show';
foreach($shows[$weekday] as $h=>$show) {
if ($h <= $hour) $now_plaing = $show;
printf("On Air Now: %s", $now_plaing);
}
You can use simple code like this:
<?php
$weekday = date('N');
$hour = date('H');
if (1 <= $weekday && $weekday <= 5) {
// Monday to friday
if ( $hour > 8 ) {
$now_plaing = 'The Breakfast Show';
} elseif ( $hour >=10 ) {
$now_plaing = 'The Fred and Lucy Hour';
} else {
$now_plaing = 'Some good show';
}
} elseif ($weekday == 7) {
// Sunday
if ( $hour > 6 ) {
$now_plaing = 'The Hymn Hour';
} else {
$now_plaing = 'Sunday good show';
}
}
printf("Now Playing: %s", $now_plaing);
Test PHP code online
Another way is build shows array (or get it from Data Base) and use another code:
<?php
$shows = [
1 => [
0 => 'Morning show',
8 => 'The Breakfast Show',
10 => 'The Fred and Lucy Hour'
],
/*** each day shows array ***/
7 => [
0 => 'Sunday good show',
6 => 'The Hymn Hour'
]
];
$weekday = date('N');
$hour = date('H');
$now_plaing = 'Default show';
foreach($shows[$weekday] as $h=>$show) {
if ($h <= $hour) $now_plaing = $show;
}
printf("Now Playing: %s", $now_plaing);
PHP sandbox
Using DB:
<?php
$weekday = date('N');
$hour = date('H:i');
$now_plaing = 'Default show';
$query = "SELECT show_name FROM shows WHERE weekday = ? AND start_at <= ? ORDER BY start_at DESC LIMIT 1;";
$stmt = $pdo->prepare($query);
$stmt->execute([$weekday, $hour]);
$show = $stmt->fetch(PDO::FETCH_ASSOC);
printf("Now at %s playing: %s", $hour, $show['show_name']);
SQL + PHP test

Trying to match actual date with days

My mission is to display the correct day to the correct date for every month. I am so stuck, i would really appreciate some help or pointers in the right way. So far i get out all the days in October since it is october, but i also want to match the days in the loop to the correct date. Am i going this the wrong way?
All i manage to do is to display the same day on every date.
$months = date("n");
$monthsDays = array (
1 => 31,
2 => 28,
3 => 31,
4 => 30,
5 => 31,
6 => 30,
7 => 31,
8 => 31,
9 => 30,
10 => 31,
11 => 30,
12 => 31
);
$day_of_the_week = array (
1 => "Måndag",
2 => "Tisdag",
3 => "Onsdag",
4 => "Torsdag",
5 => "Fredag",
6 => "Lördag",
7 => "Söndag"
);
$dayInteger = date('N', time());
echo $day_of_the_week[$dayInteger];
$day_of_the_week = date("D");
$weekNumber = date("W");
$year = date("Y");
foreach($monthsDays as $key=>$value) {
if($key == $months) {
echo date("M")."<br>";
for($i = 1; $i <= $value; $i++) {
echo '<div class="displayDate">'.$i.'</div>';
}
}
}
Edit
I have deleted the previous answer for the sake of this, more elegant answer:
setlocale(LC_TIME, array('da_DA.UTF-8','da_DA#euro','da_DA','danish'));
$curYear = strftime('%Y');
?>
<h1><?= $curYear; ?></h1>
<?php
for ($month = 1; $month <= 12; $month++) {
$curMonth = strftime('%B', strtotime("01-{$month}-{$curYear}"));
$curMonth = ucfirst($curMonth);
$curMonth = utf8_encode($curMonth);
$totalDays = cal_days_in_month(CAL_GREGORIAN, $month, $curYear);
?>
<h2><?= $curMonth; ?></h2>
<?php for ($day = 1; $day <= $totalDays; $day++) { ?>
<?php
$monthName = ucfirst(strftime('%A', strtotime("{$day}-{$month}-{$curYear}")));
$monthName = ucfirst($monthName);
$monthName = utf8_encode($monthName);
?>
<div class="displayDate"><?= $day; ?> <?= $monthName; ?></div>
<?php } ?>
<?php } ?>
Explanation
There's a lot going on here so I will divulge:
setlocale is a function that will set the locale language to whatever is specified.
The first parameter is what functions are to be affected, the second parameter is the locale to change to. In your case that was Danish.
strftime is very similar to the date function, with the exception that it will return the date in the language set by the locale.
After that it's really just iterating over days and months.
When setting $curMonth, I use strtotime so that I can manipulate it to extract that date in the specified language. Originally, I used DateTime::createFromFormat, but that doesn't respect the locale that is set via setlocale, which is why I used this hack.
$totalDays will return the total number of days in the given month, these means we don't have to hardcode them. The advantages being leap years are accounted for, and if the days of the year change, you don't have to change anything! See cal_days_in_month for how to use this function.
<?= is the equivalent of <?php echo which is a lot easier to write and read - IMO!
The only other interesting things I used are utf8_encode and ucfirst.
The former will convert the string to UTF-8 which is almost a standard these days. The latter will just set the first letter of string to a capital letter.
Note: it might be a good idea to use this solution for setting a capital letter:
$curMonth = mb_convert_case($curMonth, MB_CASE_TITLE);
Thanks to #julp for this answer.
For an explanation of what it does see the documentation for mb_convert_case; but in essence it will simply convert the first letter to a capital regardless of the locale.
try this
echo cal_days_in_month(CAL_GREGORIAN, 8, 2018)
// 8 is month number
// 2018 is year

Efficient way to check if current date is between 2 dates (years dont matter)

My mind seems to be going blank on this one.
I have to write something to figure out which date range todays day/month combination fits into.
I have a set amount of date ranges, which are:
$dateRanges = array(
1 => "16 January to 30 April",
2 => "1 May to 30 June",
3 => "1 July to 15 August",
4 => "16 August to 15 September",
5 => "15 September to 15 October",
6 => "16 October to 15 January"
);
All I'm trying to return is the array key of the range the current date fits into.
At the moment all thats going through my head is I'll have to set up a large if statement to look at the current date('j') and date('n') and match the results up. But surely thats pretty messy and not very efficient?
Any ideas of a better way to approach this problem would be much appreciated!
$today = time();
foreach ($dateRanges as $key => $range) {
list($start, $end) = explode(' to ', $range);
$start .= ' ' . date('Y'); // add 2011 to the string
$end .= ' ' . date('Y');
if ((strtotime($start) <= $today) && (strtotime($end) >= $today)) {
break;
}
}
$key will be either the index of the matching date range, or null/false.
This is a variation on Mark B's answer, but made more efficient by turning this into pure numeric comparisons:
function get_today () {
$dateRanges = array(
0 => 116, // 16th Jan
1 => 501, // 1st May
2 => 701, // 1st July ..etc..
3 => 816,
4 => 916,
5 => 1016
);
$today = (int) date('nd');
foreach ($dateRanges as $key => $date) {
if ($today < $date) {
$result = $key;
break;
}
}
return (empty($result)) ? 6 : $result;
}
Returns an integer matching the keys in your sample array
Create DateTime instances for the values in the array und use simple comparison operators like > and <
Just use strtotime to create a UNIX epoch, then use the inbuilt < and > operators.
http://www.php.net/manual/en/function.strtotime.php
$time_min = strtotime("17 January 2011");
$time_max = strtotime("30 April 2011");
if ($time >= $time_min && $time < $time_max)
{
echo "Time is within range!";
}
You can then just expand this to use the array of ranges you specified.

Giving a two dates (or two months) detect in what season we are in PHP

I would like to know if there is some easy way to identify seasons: spring, summer, autumn or winter. I'm have to generate a 'resume' and I'd like that if a period of working roughly fits a season (not exactly but with a +/-10 days error for example) it returns spring, summer, autumn or winter.
Like:
input: 25/06/2010, 30/09/2010
output: Summer 2010
(In Spain summer is between 21 July and 20 September)
input: 02/02/2009, 30/04/2010
output: 2009-2010
Any idea how to do this?
As you are looking for a season for a period I quickly wrote this function, it can be improve and may have some bugs but you have somewhere to start.
function season($period)
{
$seasons = array(
'spring' => array('March 21' , 'June 20'),
'summer' => array('June 21' , 'September 22'),
'fall' => array('September 23' , 'December 20'),
'winter' => array('December 21' , 'March 20')
);
$seasonsYear = array();
$start = strtotime($period[0]);
$end = strtotime($period[1]);
$seasonsYear[date('Y', $start)] = array();
if (key(current($seasonsYear)) != date('Y', $end))
$seasonsYear[date('Y', $end)] = array();
foreach ($seasonsYear as $year => &$seasonYear)
foreach ($seasons as $season => $period)
$seasonYear[$season] = array(strtotime($period[0].' '.$year), strtotime($period[1].' '.($season != 'winter' ? $year : ($year+1))));
foreach ($seasonsYear as $year => &$seasons) {
foreach ($seasons as $season => &$period) {
if ($start >= $period[0] && $end <= $period[1])
return ucFirst($season).' '.$year;
if ($start >= $period[0] && $start <= $period[1]) {
if (date('Y', $end) != $year)
$seasons = $seasonsYear[date('Y', $end)];
$year = date('Y', $end);
$nextSeason = key($seasons);
$nextPeriod = current($seasons);
do {
$findNext = ($end >= $nextPeriod[0] && $end <= $nextPeriod[1]);
$nextSeason = key($seasons);
$nextPeriod = current($seasons);
} while ($findNext = False);
$diffCurr = $period[1]-$start;
$diffNext = $end-$nextPeriod[0];
if ($diffCurr > $diffNext)
return ucFirst($season).' '.$year;
else {
return ucFirst($nextSeason).' '.$year;
}
}
}
}
}
echo season(array('07/20/2010', '08/20/2010'));
echo "\n";
echo season(array('06/25/2010', '09/30/2010'));
echo "\n";
echo season(array('08/25/2010', '11/30/2010'));
echo "\n";
echo season(array('12/21/2010', '01/01/2011'));
echo "\n";
echo season(array('12/21/2010', '03/25/2011'));
Result:
/*
Summer 2010
Summer 2010
Fall 2010
Winter 2010
Winter 2011
*/
And the except you want for "season year overflow":
if (date('Y', $end) != $year)
return $year.'-'.date('Y', $end);
Instead of:
if (date('Y', $end) != $year)
$seasons = $seasonsYear[date('Y', $end)];
$year = date('Y', $end);
Note: Winter is coming.
Looks like this guy got that function written already : http://biostall.com/get-the-current-season-using-php
Even has hemisphere support !
But this should do the trick :
<?php
function getSeason($date) {
$season_names = array('Winter', 'Spring', 'Summer', 'Fall');
if (strtotime($date) < strtotime($date_year.'-03-21') || strtotime($date) >= strtotime($date_year.'-12-21')) {
return $season_names[0]; // Must be in Winter
} elseif (strtotime($date) >= strtotime($date_year.'-09-23')) {
return $season_names[3]; // Must be in Fall
} elseif (strtotime($date) >= strtotime($date_year.'-06-21')) {
return $season_names[2]; // Must be in Summer
} elseif (strtotime($date) >= strtotime($date_year.'-03-21')) {
return $season_names[1]; // Must be in Spring
}
}
Here's a rough overview of what you need to do:
Work out when your season boundarys are going to be. This is a big, big job if you're going to do this for an international scope!
When presented with a date range, first work out exactly how many days of that range are in each season.
You want output like:
Range | Days | complete?
Su10 | 12 | 0
A10 | 90 | 1
W10 | 02 | 0
Once this is done you'll need to identify if a single season is 'complete', which should be 1 if the whole season is worked, within 10 days. If it is, choose that season. If more are complete, or none, return false.

Splitting an Amount over X days

I have a small script that splits out an amount of revenue over a span of days. I can't seem to wrap my head around allowing for any number of days. Currently I can only get it to work if I hard-set an array of %s for each amount of days, which obviously isn't going to work for large sets of day combinations.
If anyone has an idea as to how to accomplish this, I'd be ever grateful.
My Code:
<?php
//define variables
$ammount = 11320.00;
$start_date = "12/30/2011";
$days = 5;
//setup array of percents
$percent_array = array(3=>array(0 => 45, 1 => 30, 2 => 25), 4=>array(0 => 40, 1 => 30, 2 => 20, 3 => 10),4=>array(0 => 35, 1 => 25, 2 => 20, 3 => 10, 4 => 10));
//handle formatting the date for use in loop
$format = 'D m/d/Y';
$sDate = strtotime($start_date);
if ($usersTS !== false) {
for ($i = 0; $i < $days; $i++) {
echo date($format, strtotime('+' . $i . ' day', $sDate));
echo " : ";
echo number_format($ammount * ($percent_array[$days][$i] / 100), 2, ".", ",");
echo "<br />";
}
} else {
echo "No valid date supplied";
};
?>
Output:
Fri 12/30/2011 : 3,962.00
Sat 12/31/2011 : 2,830.00
Sun 01/01/2012 : 2,264.00
Mon 01/02/2012 : 1,132.00
Tue 01/03/2012 : 1,132.00
So you want to distribute the amount over X number of days such that the earlier days are higher weighted?
Sounds like you just need to find the right function. You can try y=1/(x+1) for example. Then solve for x number of days, and use each day as a percent sum of the y values.
well, I'm not quite sure by what amount you want to split for each day, but I think you are over thinking this problem? Couldn't you just divide the amount by the days? Or am I missing something... If you could post more info about your objective that would be helpful :)

Categories