This works (note the single digit ".3")
$date = DateTime::createFromFormat("*-*-*.*.*-Y-m-d-H?i.*", "backup-bla-3.3.3-2019-08-23-21h16.7z");
This fails (note the double digit ".33" :
$date = DateTime::createFromFormat("*-*-*.*.*-Y-m-d-H?i.*", "backup-bla-3.3.33-2019-08-23-21h16.7z");
This makes no sense to me. Why doesn't the * succeed in this case ?
The following also works on this specific example but I cannot make use of it as the version numbers may have double digits.
$date = DateTime::createFromFormat("*-*-*.*.??-Y-m-d-H?i.*", "backup-bla-3.3.33-2019-08-23-21h16.7z");
Why it fails when using * is clear from the manual:
Random bytes until the next separator or digit
You have two digits in a row 3 and 3 so when it reaches the second 3 your provided format is incorrect and causes an error.
The inverse is true with ** and ?? because when you have a single digit number there is no second character for the second * and ? to match.
I don't see any way around this using the available format characters. Your solution seems to be modifying that value to remove anything before the year and then using Datetime:createFromFormat().
$parts = preg_split('/(?=\d{4})/', 'backup-bla-3.3.3-2019-08-23-21h16.7z', -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$date = DateTime::createFromFormat("Y-m-d-H?i.*", $parts[1]);
echo $date->format('c');
Demo
Related
We are designing a new sensor that sends some data to a webapplication. We use similar sensors, but they use data channels to divide the value send to the application into different data types.
However, this new sensor will send either data or a 32 bit time, with miliseconds. It doesn't send a identifier bit to see whether the value is data or a timestamp.
Because both the data and timestamp are integer value's, How can i check which one it is?
The timestamp will be
YYYY/MM/DD HH:MI:SS:vv
I already found preg_match, like this:
if (preg_match('/[0-9]{4}-[0-9]{2}-[0-9]{2}/', $value))
But how do i include the miliseconds? Or is there a better way than a simple if else?
Update
I expect that the date recieved by the application will be in int16.
So it might be easier to count the values recieved and handle value 9 and 10 like datetimes..
You could use the createFromFormat() method from the PHP DateTime object.
You would create a function that checks the method errors :
function is_valid_date($date, $format = 'Y/m/d H:i:s.u')
{
$d = DateTime::createFromFormat($format, $date);
$errors = DateTime::getLastErrors();
return (
$errors['warning_count'] == 0 &&
$errors['error_count'] == 0 &&
$d !== false
);
}
Hope it helps.
EDIT :
Added the u (for microseconds) on the default format.
You could use this regular expression:
With preg_match_all:
preg_match_all("/(\d{4})\/(\d{2})\/(\d{2})\s(\d{2})\:(\d{2})\:(\d{2})\:(\d{2})/", $input_lines, $output_array);
With preg_match:
preg_match("/(\d{4})\/(\d{2})\/(\d{2})\s(\d{2})\:(\d{2})\:(\d{2})\:(\d{2})/", $input_line, $output_array);
Beware, it only checks for the numbers, the backslashes and the ':' character. It doesn't check if the given numbers are valid.
Once you've run the regular expression, you can then check the output array and see if it's empty or not (if it isn't empty it matched the format)
The regular expression matches this range:
0000/00/00 00:00:00:00
9999/99/99 99:99:99:99
I fixed it in a different way:
we determined that the first 2 16bit values in a message are always the timestamps, so i just made a valuecounter and used a if $value is 1 or 2 then do this, else do that.
This was a lot easier for me then to check each value.
I have 3 distinct lists of strings. First one contains names of people(from 10 chars to 80 chars long). Second one - room numbers(903, 231 and so on). Last one - group numbers(ABCD-1312, CXVZ-123).
I have a query which is given by a user. Firstly, I tried to search using Levenshtein distance, it didn't work, because whenever user types 3 chars, it gives some room number, even though there is no any digit in query. Then, I tried similar_text(), it worked better, but because people names all have different length, it mostly gives results with shorter names.
Now, the best I come up with is using similar_text() and str_pad() to make each string equal length. Still doesn't work properly.
I want to somehow give extra weight to strings, if they have several matches in a row, or if query and my string starts with the same letter and so on.
$search_min_heap = new SearchMinHeap();
$query = strtolower($query); // similar_text is case sensitive, so make everything lowercase
foreach ($res["result"] as &$item) {
similar_text($query, str_pad(strtolower($item["name_en"]), 100, " "), $cur_distance_en);
similar_text($query, str_pad(strtolower($item["name_ru"]), 100, " "), $cur_distance_ru);
similar_text($query, str_pad(strtolower($item["name_kk"]), 100, " "), $cur_distance_kk);
$cur_max_distance = max($cur_distance_en, $cur_distance_ru, $cur_distance_kk);
$item["matching"] = $cur_max_distance;
$search_min_heap->insert($item);
}
$first_elements = $search_min_heap->getFirstElements($count);
I have time stored in my database. Here is an example of a time:
800 or 1000
the first one is 8:00 and the second one is 10:00. I want to add a semicolon : after the second character starting to count from the right to left. how can i do this in php?
here is what i tried:
$realTime = substr_replace($oldtime,":", 2, -strlen($oldtime));
but it started from the left but i need it to start counting from the right. thanks.
Per the docs:
If start is negative, the replacing will begin at the start'th character from the end of string.
So use a negative number:
$realTime = substr_replace($oldtime,":", -2, -strlen($oldtime));
Do it with a regex
$newtime = preg_replace('#^(.*)([0-9]{2})$#','$1:$2',$oldtime);
Another approach is to have different formulas based on the length and use a case statement.
Update foo
set oldtime= case when length(oldtime) = 4 then
concat(substr(oldtime,1,2),':',substr(oldtime,3,2))
when length(oldtime) = 3 then
concat(substr(oldtime,1,1),':',substr(oldtime,2,2))
end
Working Fiddle
Let's take this line for instance
$amount = $_POST["priceFinal"];
which is essentially equivilant to
$amount = 5000;
I would like to add two zero at the end so if the amount if 5000 its actually 5000000
Now its important to note that it must remain has an integer, where if i do
$amount = "".$_POST["priceFinal"]."00";
it does the work but its a string and needs to remain an integer
just times you amount by how many 0's you need. for example times by 10 gives you 1 extra 0. so just times by 100 to get two extra 0, this keeps it as an interger as opposed to converting it to a sting as php will always try to assume a variable type.
$amount = $_POST["priceFinal"] * 100;
see this link for more information on definition type. Type Juggling
You could use this assuming you are not calculating anything with it.
// see php.net str_pad for more examples.
$amount = str_pad($_POST['priceFinal'], 2 , '0');
I have used this code :
$result = number_format(round(15.5, 1), 2);
Written in my old post :
PHP - Commercial round
I have now problems with the values like : 1,597.30
I get the price as 1.00
How can I do to get the make the round and get the good price format with the prices that have number with thousands.
Never store a formatted number.
Always store it in its original format: 1597.30 This is the only format that works for calculations and formatting.
Use number_format() only for outputting the number.
You could solve this issue using the following code:
$price = '1,597.30';
$new_price = floatval(str_replace(',', '', $price));
$result = number_format(round($new_price, 1), 2);
Remove comma and all other formating (except the dot) from your numbers, otherwise comma will be used as decimal separator.