I wan't to get a PHP date() from specified weekday in a given week.
For example:
Weekday: Thursday - in week:8 - year:13 (means 2013).
I would like to return a date from these specified values. The phpdate will in this case return: "21 Feb 2013", which is a Thursday in week 8 of 2013.
Please fill in this php-method:
function getDateWithSpecifiedValues($weekDayStr,$week,$year) {
//return date();
}
Where the example:
getDateWithSpecifiedValues("Tuesday",8,13);
will return a phpdate of "19 Feb 2013"
First, you have to define what you mean by "week of the year". There are several different definitions. Does the first week start on Jan 1? On the first Sunday or Monday? Is it number 1 or 0?
There is a standard definition, codified in ISO 8601, which says that weeks run from Monday through Sunday, the first one of the year is the one with at least 4 days of the new year in it, and that week is number 1. Your example expected output is consistent with that definition.
So you can convert the values by putting them into a string and passing that string to strptime, along with a custom format string telling it what the fields in the string are. For example, the the week number itself should be indicated in the format string by %V.
For the weekday, the format depends on how you want to provide it as input to your function. If you have the full name (e.g. "Thursday"), that's %A. If you have the abbreviated name (e.g. "Thu"), that's %a. If you have a number (e.g. 4), that's either %w (if Sundays are 0) or %u (if Sundays are 7). (If you're not sure, you can always just use %w and pass the number % 7.)
Now, the year should be %G (full year) or %g (just the last two digits). It's different from the normal calendar year fields (%Y for 2014 and %y for 13) because, for example, week 1 of 2014 actually started on December 30, 2013, which obviously has a '%Y' of 2013 where we want 2014. However, the G fields don't work properly with strptime, so you'll have to use the Y's.
For example:
$date_array = strptime("$weekDayStr $week $year", '%A %V %y');
That's a good start, but the return value of strptime is an array:
array('tm_sec' => seconds, 'tm_min' => minutes, tm_hour => hour,
tm_mday => day of month, tm_mon => month number (0..11), tm_year => year - 1900)
And that array is not the input expected by any of the other common date or time functions, as far as I can tell. You have to pull the values out yourself and modify them in some cases and pass the result to something to get what you want. For instance:
$time_t = mktime($date_array['tm_hour'], $date_array['tm_min'],
$date_array['tm_sec'], $date_array['tm_mon']+1,
$date_array['tm_mday'], $date_array['tm_year']+1900);
And then you can return that in whatever form you need. Here I'm returning it as a string:
function getDateWithSpecifiedValues($weekDayStr,$week,$year) {
$date_array = strptime("$weekDayStr $week $year", '%A %V %y');
$time_t = mktime($date_array['tm_hour'], $date_array['tm_min'],
$date_array['tm_sec'], $date_array['tm_mon']+1,
$date_array['tm_mday'], $date_array['tm_year']+1900);
return strftime('%d %b %Y', $time_t);
}
For example,
php > print(getDateWithSpecifiedValues('Thursday',8,13)."\n");
21 Feb 2013
Try this function:
function getDateWithSpecifiedValues($weekDayStr, $week, $year) {
$dt = DateTime::createFromFormat('y, l', "$year, $weekDayStr");
return $dt->setISODate($dt->format('o'), $week, $dt->format('N'))->format('j M Y');
}
demo
I'm fairly certain neither 21st of January or the 19th of January is in week 8.
You can however use strptime to parse custom formats:
var_dump(strptime("Thursday 8 13", "%A %V %y"));
array(9) {
["tm_sec"]=>
int(0)
["tm_min"]=>
int(0)
["tm_hour"]=>
int(0)
["tm_mday"]=>
int(21)
["tm_mon"]=>
int(1)
["tm_year"]=>
int(113)
["tm_wday"]=>
int(4)
["tm_yday"]=>
int(58)
["unparsed"]=>
string(0) ""
}
See the documentation for strptime for the meaning of each value in the returned array.
Related
I have laravel project
part of my code adds months and year in a database for generated cards
the expiration month should be +6 months after generating the card
I have this code
"year" => now()->format("Y"),
"month" => now()->addMonths(6)->format("m"),
the problem is for the current month august
I get the year 2022 and month 02 because this code gets month aug=8+6 =14
how to fix this?
for example for the august 2022 sample, I should get 02/2023
The solution is pretty simple in this case :D
$date = now()->addMonths(6);
"year" => $date->format('Y'),
"month" => $date->format("m"),
If the month you are creating it is January 2022, the date will hold July and 2022.
If the month you are creating it is September 2022,the date will hold the March and 2023
Not sure where the now() function comes from, but I would recommend you use the DateTime/DateTimeImmutable object in PHP. You could do something like this to add 6 months to the current time:
<?php
var_dump((new DateTime())->add(new DateInterval('P6M'))->format('m/y'));
// Output: string(5) "02/23"
Or use the DateTime constructor to set a different point in time
<?php
var_dump((new DateTime('#1654072523'))->add(new DateInterval('P6M'))->format('m/y'));
// Output: string(5) "12/22"
If you'd like the values separately you can do something like the following:
<?php
// Create an instance of DateTime
$date = new DateTime('#1654072523');
// Add an interval of 6 months to the date time object
$futureDate = $date->add(new DateInterval('P6M'));
var_dump($futureDate->format('m'));
var_dump($futureDate->format('y'));
// Output: string(2) "12"
// string(2) "22"
Or for your example:
"year" => now()->addMonths(6)->format("Y"),
"month" => now()->addMonths(6)->format("m"),
You can use all kinds of formatting options and variations, a list is available at the PHP docs, https://www.php.net/manual/en/datetime.format.php.
I hope this helps! If not, please clarify your question
I have two times saved in database as
DayTime1 = "Wed 09:00"
DayTime2 = "Wed 13:00"
I want to get the difference between these two dates in minutes.
TIMESTAMPDIFF(MINUTES,DayTime1,DayTime2) return null
I'm not able to get through it. Is there any way to get difference?
Please note, that SELECT STR_TO_DATE("Wed 09:00", "%a %H:%i") returns 0000-00-00 09:00:00 (at least on my local MySql 5.5.16). So if comparing different days, you won't get the correct result.
If given a year and week, the day name will be interpreted to a real date, so comparisons may also span days. For example (though not really elegant, I admit):
SELECT TIMESTAMPDIFF(MINUTE,
STR_TO_DATE(CONCAT(YEAR(CURDATE()), WEEKOFYEAR(CURDATE()), ' Tue 09:00'), '%x%v %a %H:%i'),
STR_TO_DATE(CONCAT(YEAR(CURDATE()), WEEKOFYEAR(CURDATE()), ' Wed 13:00'), '%x%v %a %H:%i')
)
Since you also included the php-tag, I'm assuming a PHP solution is valid as well:
$daytime1 = "Wed 09:00";
$daytime2 = "Wed 13:00";
$diff = abs(strtotime($daytime1) - strtotime($daytime2)); //absolute diff in seconds
$diff = $diff / 60; //Difference in minutes
EDIT:
And here is a pure MySQL solution:
SELECT ABS(
TIME_TO_SEC(
TIMEDIFF(
STR_TO_DATE("Wed 09:00", "%a %H:%i"),
STR_TO_DATE("Wed 13:00", "%a %H:%i")
)
)
) / 60
The second parameter, "%a %H:%i"is the date format. If it's always in the format of "First three letters of weekday, space, hour with leading zero, :, minutes" then you can use this format.
I have a table, called schedules. It has three columns day, month, year, the the day/month/year that schedule is for. There is no timestamp here. I chose this format so that I could for instance retrieve all the schedules for October, or for the year 2014.
However, is it possible to retrieve the schedules for given range, say from Sept 10, 2014 to Oct 09, 2014? The problem is that if I use
WHERE 'day' > 10 AND 'day' < 9 ...
will not return anything since even though the month October (10) is larger than September (9), the days of the month will miss this up!
Is there a way or do I need to also include a fourth date column with a timestamp?
You can use parenthesis and an or clause:
WHERE ('month' = '9' AND 'day' > 10) OR ('month' = '10' AND 'day' < 9)
However, using a datetime field would be much better, as you can still get month/day/year easily:
WHERE MONTH(field) = 10
WHERE DAY(field) = 3
WHERE YEAR(field) = 2014
and then you also can do
WHERE field >= '2014-09-10' AND field <= '2014-10-09'
See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html for documentation on all the date/time functions in mysql.
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)
I have a simple situation where I have a user supplied week number X, and I need to find out that week's monday's date (e.g. 12 December). How would I achieve this? I know year and week.
Some code based mainly on previous proposals:
$predefinedYear = 2009;
$predefinedWeeks = 47;
// find first mоnday of the year
$firstMon = strtotime("mon jan {$predefinedYear}");
// calculate how much weeks to add
$weeksOffset = $predefinedWeeks - date('W', $firstMon);
// calculate searched monday
$searchedMon = strtotime("+{$weeksOffset} week " . date('Y-m-d', $firstMon));
An idea to get you started:
take first day of year
add 7 * X days
use strtodate, passing in "last Monday" and the date calculated above.
May need to add one day to the above.
Depending on the way you are calculating week numbers and the start of the week this may sometimes be out. (i.e. if the monday in the first week of the year was actually in the previous year!)
TEST THIS THOROUGHLY - but I've used a similar approach for similar calcualtions in the past.
This will solve the problem for you. It mainly derives from Mihail Dimitrov's answer, but simplifies and condenses this somewhat. It can be a one-line solution if you really want it to be.
function getMondaysDate($year, $week) {
if (!is_numeric($year) || !is_numeric($week)) {
return null;
// or throw Exception, etc.
}
$timestamp = strtotime("+$week weeks Monday January $year");
$prettyDate = date('d M Y');
return $prettyDate;
}
A couple of notes:
As above, strtotime("Monday January $year") will give you the timestamp of the first Monday of the year.
As above +X weeks will increment a specified date by that many weeks.
You can validate this by trying:
date('c',strtotime('Sunday Jan 2018'));
// "2018-01-07T00:00:00+11:00" (or whatever your timezone is)
date('c',strtotime('+1 weeks Sunday Jan 2018'));
// "2018-01-14T00:00:00+11:00" (or whatever your timezone is)
date('c',strtotime('+52 weeks Sunday Jan 2018'));
// "2019-01-06T00:00:00+11:00"
Due to reputation restriction i can't post multiple links
for details check
http://php.net/manual/en/function.date.php and http://php.net/manual/en/function.mktime.php
you can use something like this :
use mktime to get a timestamp of the week : $stamp = mktime(0,0,0,0,<7*x>,) {used something similar a few years back, so i'm not sure it works like this}
and then use $wDay = date('N',$stamp). You now have the day of the week, the timestamp of the monday should be
mktime(0,0,0,0,<7*x>-$wDay+1,) {the 'N' parameter returns 1 for monday, 6 for sunday}
hope this helps
//To calculate 12 th Monday from this Monday(2014-04-07)
$n_monday=12;
$cur_mon=strtotime("next Monday");
for($i=1;$i<=$n_monday;$i++){
echo date('Y-m-d', $cur_mon);
$cur_mon=strtotime(date('Y-m-d', strtotime("next Monday",$cur_mon)));
}
Out Put
2014-04-07
2014-04-14
2014-04-21
2014-04-28
2014-05-05
2014-05-12
2014-05-19
2014-05-26
2014-06-02
2014-06-09
2014-06-16
2014-06-23