I need to add +1 to a value every week at Thursday for example..
Let's assume the value is 5.
Its the 1st of the month and its Thursday.
I want 5 to change to 6 by the 8th of the month.
How do I do that?
I started to come up with something, but since I've never really learned PHP properly I didn't really know what I was doing.
$value = 5;
$num = $value + 1;
BUT, then the $value stays the same and the $num won't change.
Thanks!
Easiest would be to store an initial date and a starting value. "On July 14th, the value is 5":
$initial_date = strtotime('2011-07-14');
$initial_value = 5;
$new_value = $initial_value + floor($initial_date / 86400 / 7);
This will dynamically caculate how many weeks have elapsed since the intial date, and add it to the initial value, giving you your new value.
yes, value stays the same.
If you want to change value, just do it like this
$value = 5;
$value += 1; //or $value++;
Without storing the updated value weekly (in a file or database), you'll have to hardcode the starting timestamp and calculate how many weeks (1 week = 604800 seconds) have passed since then every to determine what to add to $value = 5.
Related
A time attendance system can have many shifts.
For instance:
Shift a) 08:00 - 16:00,
Shift b) 16:00 - 00:00,
Shift c) 00:00 - 08:00,
A user starts working at 07:55 what is the best way to match this user with the correct shift which is shift a?
Keep in mind that the time attendance system may have many shifts much closer together, for instance a
shift that starts at 8:00 and a shift that starts at 9:00.
Important info:
What i have done is a foreach loop that compares all starting times of the shifts (in our example 09:00, 16:00, 00:00) with the time that user started working. In our example 7:55.
The one that is closer to the users start working time is the correct shift.
This looks like its ok but in reality its not. The reason is that when time is round 00:00:00 and since times of shifts do not have a date, when the comparison is 23:59:59 and 00:00:01 i get 86400 secs instead of just 2 secs.
Additional you never know which date is greater than the other, because a user may come earlier for work or late.
So any ideas must take these into consideration.
Thanks for efforts
I've updated the answer based on the comment, but there is not enough information in the question to show you how to query your database and convert your shifts into the array I'm using in this example.
This codeblock is reference, not code to use. This is the array of start times you need to convert your database table to.
$shift_starts = [
// 1 represents the ID of the shift in your database.
1 => [
// Shift ID 1 starts at midnight, hour 0, minute 0
[0, 0],
],
// 2 represents the ID of the shift in your database.
2 => [
// Shift ID 2 starts at 8am, hour 8, minute 0
[8, 0],
],
// 3 represents the ID of the shift in your database.
3 => [
// Shift ID 3 starts at 4pm, hour 16, minute 0
[16, 0],
],
];
Create a function, something like this. Again, I don't know how you are querying your database, nor the schema. I just know how you are storing the start times:
// Psudeo Code!!! Study and write your own function that returns
// the array as defined above.
function get_shift_start_array() {
$shift_starts = [];
$result = mysqli_query($db, "SELECT * FROM shifts ORDER BY start_time");
while ($row = mysqli_fetch_row($result)) {
// If the start_time is formatted h:m:s, then make it so you can get hours
// and minutes into their own variables:
$arr = explode(':', $row['start_time']);
$hour = $arr[0];
$minute = $arr[1];
$shift_starts[$row->id] = [$hour, $minute];
}
return $shift_starts;
}
Now that we have a way to get your shift data into a format we can code around, this function will take a unix timestamp and return the database ID of the shift. (Notice this function calls the function above)
Read the comments and study the PHP functions you might not understand.
/**
* Get the shift ID for a specific time.
*
* #param int $punchin_time Unix timestamp Default is the current time.
* #return int The shift id (the array key from $shift_starts)
*/
function findShift($punchin_time = null): int
{
if ($punchin_time === null) {
$punchin_time = time();
}
// Call the psudo code function to get an array of shift start times keyed by shift id.
$shift_starts = get_shift_start_array();
// Set $day to the unix timestamp of midnight yesterday.
$day = strtotime(date('Y-m-d', $punchin_time - 86400));
// We'll be checking the difference between punchin time and the shift time.
// $last_diff will be used to compare the diff of the current shift to the last shift.
// Initialize this with an arbitrarily high value beyond the 3 days we're looking at.
$last_diff = 86400 * 5; //
$last_index = null;
// Loop over 3 days starting with yesterday to accommodate punchin times before midnight.
// Return the shift ID when we find the smallest difference between punchin time and shift start.
for ($i = 0; $i <= 3; $i++) {
// Get the month, day, and year numbers for the day we are iterating on.
// We will use these in our calls to mktime()
$m = date('n', $day);
$d = date('j', $day);
$y = date('y', $day);
// Loop over each shift.
foreach ($shift_starts as $index => $start) {
// Create a unix timestamp of the shift start time.
// This is the date and time the shift starts based on the day iteration.
$time = mktime($start[0], $start[1], 0, $m, $d, $y);
// Get the difference in seconds between this shift start time and the punchin time.
$diff = abs($punchin_time - $time);
// $diff should be getting smaller as we get closer to the actual shift.
if ($diff > $last_diff) {
// If $diff got bigger than the last one, we've past the shift.
// Return the index of the last shift.
return $last_index;
}
$last_index = $index;
$last_diff = $diff;
}
$day = strtotime('+1 day', $day);
}
// Return null if no shift found.
return null;
}
Now that the functions are defined, you just need to call the last one to convert specific time, to a shift.
$punchin_time = mktime(15, 55, 0, 4, 15, 2020);
$shift_id = findShift($punchin_time);
Alternatively, don't pass a time in and the current time will be used.
$shift_id = findShift($punchin_time);
mktime
strtotime()
DateTime::getTimestamp()
I have a cron job that gets results from the DB to check it the interval set by user falls on today's date. I am currently thinking of doing it as below :
Get the time column for the row. Ex:2017-05-25 00:00:00
Get the frequency set. Ex:Every 2 weeks.
Get the current date in above format. Ex:2017-05-31 00:00:00
Get the difference in days. Ex:6 days.
Convert the frequency set to days. Ex:2 weeks = 14 days;
Divide (difference in time(days)) by (frequency in days). Ex:6/14
This way I will only get the result to be true when 2 weeks have passed since the time set. I.e., 14/14, 28/14, 42/14,...
If the frequency is in months, I can start dividing by 30. But somehow this feels like a hacky way of doing it. So my question is if there is better way of doing this calculation to check the difference.
This is what I have done as explained by above example.
` $frequency = ; // Get the relevant fields from db
$today = date(Y-m-d H:i:s);
foreach ($frequency as $key => $value) {
$frequency_in_days;
$frequency_type = $value->type;
$frequency_repeat = $value->repeat;
if($frequency_type == 1){
$frequency_in_days = $frequency_repeat;
} elseif($frequency_type == 2) {
$frequency_in_days = $frequency_repeat * 7;
} elseif($frequency_type == 3) {
$frequency_in_days = $frequency_repeat * 30;
} elseif($frequency_type == 4) {
$frequency_in_days = $frequency_repeat * 365;
}
// Get number of days spent between start_date and today in days.
$interval = date_diff($value->start_date, $today)->format('%a');
$result = $interval % $frequency_in_days;
if ($result == 0) {
// Frequency falls today! Do the job.
}
}`
Note: The cron job runs this script. The script again needs to check if the today falls under the frequency set.
Also for argument's sake, is this the best logic to calculate the difference?
Thank you.
This will work
Table "schedule"
`last_run` timestamp,
`frequency_seconds` int
example query for tasks that should go every two weeks:
SELECT *
FROM schedule
WHERE TIMESTAMPDIFF(last_run, NOW()) >= frequency_seconds
after fetching rows update last_run to NOW()
I have a date that goes into a loop that the user specifies. The date will always come from the database formatted as a 'Y-m-d' string. I am aware that I can compare the strings directly as long as they are in that format, however, I have also tried using strtotime to convert the dates to compare them with no luck. I am trying to determine how many paycheck a user has before a payment is due
Here is what I have
$due_date = '2016-12-13';
//count paychecks set to zero and added to by loop
$paychecks = 0;
//users next paycheck ('Y-m-d' ALWAYS)
$next_payday = $user['next_payday']; //equal to '2016-12-02'
//how often they get paid (int)
$frequency = 14;
while(strtotime($next_payday) <= strtotime($due_date)){
//next_payday equals 1480654800 when coming into the loop
//due_date equals 1481605200 when coming into the loop
//add 14 days to the date
$next_payday = date('Y-m-d', strtotime("+" .$frequency." days"));;
//add to paychecks
$paychecks++;
}
The problem is that the loop never stops. It keeps going and going.
Thanks for any help anyone can give me.
Ah, be sure to use strtotime to get integers (representing number of seconds since the epoch) for comparison and multiply your frequency of days by the number of seconds in a day (86400):
$due_date = strtotime('2016-12-25');
//count paychecks set to zero and added to by loop
$paychecks = 0;
//users next paycheck (unixtime for comparison)
$next_payday = strtotime($user['next_payday']);
//how often they get paid (int)
$frequency = 14;
while($next_payday <= $due_date){
//add 14 days to the date
$next_payday += ($frequency * 86400);
//add to paychecks
$paychecks++;
}
I am trying to populate a drop-down menu with time in 30 minute intervals (ability to change to different intervals would be nice too).
I am currently using the following code to populate the drop down (Scrounged this up online from searching around).
$sqlHours = "SELECT Open, Close FROM TimeTable";
$rsSQLHours = odbc_exec($conn, $sqlHours);
$strOpen = trim(odbc_result($rsSQLHours, "Open"));
$strClose = trim(odbc_result($rsSQLHours, "Close"));
$DeliHourOpen = substr($strOpen, 0, 2);
$DeliMinOpen = substr($strOpen, 3, 2);
$DeliHourClose = substr($strClose, 0, 2);
$DeliMinClose = substr($strClose, 3, 2);
for($hours=$DeliHourOpen; $hours<=$DeliHourClose; $hours++)
for($mins=$DeliMinOpen; $mins<60; $mins+=30)
echo '<option value='.$hours.':'.$mins.'>'.date('h:i A', strtotime($hours.':'.$mins)).'</option>'; ?>
Edit: I am storing the times in the database in 24h format, such as 08:00:00 or 22:00:00. I am using the date() just to format the displayed output in an AM/PM fashion for ease of use by users.
I am having issues when the Close Time is 20:00 it will go up to 8:30 PM in the drop-down. If I remove the = from <=$DeliHourClose then it will only display 7:30 PM. I need it to Display up to whatever the Close Time is.
The fields in the database are 'Time' in the in format 'H:i:s'.
Also, although the drop-down can be populated with a range of times from Open to Close, I need it to start at whatever the current time is + 30 minutes.
So if the Open Time is 8:00 AM, and it is 7:00 AM I want to see 8:00 AM as the first time in the drop-down. But if it is 9:00 AM, the first option in the drop-down needs to be 9:30 AM.
I have the general idea that it needs some sort of if/else to compare current time to the times in the drop-down, but I am not sure how to go about it, with the format I am using now for the drop-down.
I would prefer to have a more manageable format if possible.
Is there an easier/better way to generate a range of times with intervals that may be changed? And then populate the drop-down with the appropriate times?
Any help or suggestions would be greatly appreciated.
Using a Microsoft SQL Database.
Edit: There are multiple locations that will be stored in the table. I will add a WHERE Location = XXX clause once I get it working and add more locations to the table. Currently there is only one location, so no WHERE clause.
I am using time datatype instead of datetime as I do not want a y/m/d attached to the open/close times.
You need to generate your time stamp using time() so you can get the unix timestamp and then convert it as you wish, this way you'll be able to do time addition and add seconds straight to the given unix timestamp.
Ressource : http://fr.php.net/time
Edit : Just so we're clear and to explain it further : UNIX timestamp is the number of seconds since the 1st of january 1970, so echo time(); will return 1390934768, you just need to process it from there as the docs shows.
This code whille return this as an array : 8
8.5
9
9.5
10
10.5
11
11.5
12
12.5
13
13.5
14
14.5
15
15.5
16
16.5
17
17.5
18
18.5
19
<?php
//Function returning unix time from simple time stamp (8 or 17.5 or whatever)
function ttounix($t) {
$tunix = $t * 60 * 60;
return $tunix;
}
//Function returning simple timestamp from unix timestamp
function unixtot($u) {
$tt = $u / 60 / 60;
return $tt;
}
$gap = 30 * 60; //gap in seconds
$t1 = 8; //opening time from db
$t2 = 19; //closing time from db
//setting vars
$n = 0;
$count = array();
//Getting processed time stamps into vars
$o = ttounix($t1);
$c = ttounix($t2);
//Populating the array
while ( $o <= $c ) {
$count[$n] = $o;
$o += $gap;
$n++;
}
//Output
foreach ($count as $output) {
echo unixtot(intval($output)) . '<br />';
}
?>
This is my first time posting here so I'm sorry if I get something wrong. I'm trying to calculate how many hours overtime a worker has worked based on when they signed in. The problem is that we have different bands of overtime:
If the worker works between 5 and 7 then it's 25% extra per hour
If they worked between 7pm and 10pm then its 50% extran for each hour
If the worker works between 10 and 12 then it's 75% extra
If the worker works between 12am and 7am is 100% more
I need to count how many hours they worked at each of the overtime bands
$number_of_25_percent_hours=0;
$number_of_50_percent_hours=0;
$number_of_75_percent_hours=0;
$number_of_100_percent_hours=0;
$clockInTime=$arr['4'];
$clockOutTime=$arr['5'];
$startingPieces=explode(':',$clockInTime);
$startingHour=$startingPieces[0];
$finishingPieces=explode(':',$clockInTime);
$finishingHour=$finishingPieces[0];
//Regular hours are between 7am and and 5pm
//If the worker works between 5 and 7 then it's 25% extra per hour
if(($startingHour<=5)&&($finishingHour>=6)){$number_of_25_percent_hours++;}
if(($startingHour<=6)&&($finishingHour>=7)){$number_of_25_percent_hours++;}
The problem with using the lines above is that it does not work if for example they worked an hour from 6:30 to 7:30.
I'm interested in finding other ways to do this.
you need to store the data more exactly. From your script it looks as if you were only saving the starting hour - which propably is a full number (1,2,3,4 whatsoever)
You script however needs a exact time representation. There are surely many ways to do this but for the sake of a better Script (and as you will propably be able to use some of these more exact values later on) I'd recommend you to store it as a UNIX Timestamp, then get the hour of the Timestamp :
$startingHour = date('H' $timeStampStored)
and check if it's in any of your "bonus" segments. If the user started working at 6:30, the value will hold 6.
This code is completely off the top of my head, untested etc. It's intended as a suggestion of one method you might use to solve the problem, not as a robust example of working code. It uses integers instead of dates, relies on array data being entered in order etc, and probably wouldn't even run.
The basic idea is to set up the scales for each level of overtime multiplier, as well as the hours for non-overtime pay in an array, then loop through that array checking how many hours of each level of overtime have been worked between the inputted times, meanwhile keeping track of a total billable hours value.
$PayMultipliers = array();
$PayMultipliers[0] = array(17,19,1.25);
$PayMultipliers[1] = array(19,22,1.5);
$PayMultipliers[2] = array(22,24,1.75);
$PayMultipliers[3] = array(0,7,1.5);
$PayMultipliers[4] = array(7, 17, 1);
$Start = 3;
$End = 11;
$TotalHours = 0;
for($i = 0; $i <= count($PayMultipliers); $i++)
{
if($Start > $PayMultipliers[$i][0] && $Start < $PayMultipliers[$i][1])
{
$TotalHours += ($PayMultipliers[$i][1] - $Start) * $PayMultipliers[$i][2];
$Start = $PayMultipliers[$i][1];
}
}
echo $TotalHours;
If you want to calculate from 6:30 to 7:30 you'll have to caclulate in minutes, not hours. You can convert the hours and minutes to timestamps, check each time period, and then convert the seconds back to hours.
<?php
$number_of_overtime_hours = array();
$clockInTime = "18:30:00";
$clockOutTime = "19:30:00";
$startingPieces = explode(':',$clockInTime);
$finishingPieces = explode(':',$clockOutTime);
//Timestamps
$startTimestamp = mktime($startingPieces[0],$startingPieces[1],$startingPieces[2]);
$finishTimestamp = mktime($finishingPieces[0],$finishingPieces[1],$finishingPieces[2]);
//finish after 0h
if ($finishTimestamp < $startTimestamp){
$finishTimestamp += 3600 * 24;
}
//set starting and ending points
$overtimePeriods = array(
25 => array (17,19),
50 => array (19,22),
75 => array (22,24),
100 => array (24,31)
);
$overtimeWork = array();
foreach ($overtimePeriods as $key => $val){
//create Timestamps for overtime periods
$beginTimestamp = mktime($val[0],0,0);
$endTimestamp = mktime($val[1],0,0);
//calculate hours inside the given period
$overtimeWork[$key] = (min($finishTimestamp,$endTimestamp) - max($startTimestamp,$beginTimestamp)) / 3600;
//negative values mean zero work in this period
if ($overtimeWork[$key] < 0) $overtimeWork[$key] = 0;
}
var_dump($overtimeWork);