In the project I'm working on I have a daily command that basically checks the date of the last record in the database and tries to fetch data from an API from the day after and then each month after that (the data is published monthly).
Basically, the last record's date is 2019-08-30. I'm mocking as if I were running the task on 2019-09-01 with
$test = Carbon::create(2019,9,1,4);
Carbon::setTestNow($test);
I then create a monthly period between the next day of the last record's date and the last day of the current month like so:
$period = CarbonPeriod::create($last_record_date->addDay(), '1 month', $last_day_of_current_month);
Successfully generating a period with start_date = 2019-08-31 and end_date = 2019-09-30. Which I use in a simple foreach.
What I expected to happen is that it runs twice, once for August and once for September, but it's running only once for the start date. It's probably adding a month and going past the end date, but I don't know how to force the behaviour I'm looking for.
TL;DR:
$period = CarbonPeriod::create('2019-08-31', '1 month', '2019-09-30');
foreach ($period as $dt) {
echo $dt->format("Y-m") . "<br>\n";
}
This will print just 2019-08, while I expect 2019-08 and 2019-09. What's the best way to achieve that?
Solution :-
You can store actual date in $actual_day and current date for occurring monthly in $current_day. Put a check on comparing both dates, if not matched then make it on the same day it will skip 30,31 case in case of February month.
$current_date = $current_date->addMonths(1);
if($current_date->day != $actual_day){
$date = Carbon::parse($date->year."-".$date->month."-".$actual_day);
}
Your start date is 2019-08-31. Adding a month takes you to 2019-09-31. 2019-09-31 doesn't exist so instead you get 2019-10-01, which is after your end date. To avoid this I'd suggest you use a more regular interval such as 30 days.
Otherwise you're going to have to rigorously define what you mean by "a month later". If the start date is 31st Jan is the next date 28th February? Is the month after 28th or 31st March? How do leap years affect things?
Related
I want to get the timestamp in milliseconds for first day of last month and last day of last month using Carbon in laravel.
I have tried to do it with carbon::parse, which is achieved. But I want to instantiate the Carbon class simply to achieve the same.
This is the code that works fine with Carbon::parse
Carbon::parse('first day of last month',$timezone)->timestamp
But I want to achieve the same using something like below.
$start = new Carbon('first day of last month');
$end = new Carbon('last day of last month');
The output should be timestamp in milliseconds. Like 1555704794000
You may try the below code
$previous_month_start = Carbon::now()->subMonth()->startOfMonth()->format('x');
$previous_month_end = Carbon::now()->subMonth()->endOfMonth()->format('x');
I'm using Laravel 5.4 and Carbon to find dates that are exactly one day and three days prior to a laravel job (to the hour) to send notifications. So for example if the date was 2019-03-10 18:00:03 or 2019-03-10 18:15:34, I'd like to send a notification tomorrow at 2019-03-07 18:00:00 and another at 2019-03-09 18:00:00. I'd like to do this in an eloquent query, but not really sure how to "lazy match" by day and hour. If I have an Appointment model with a start_date timestamp, I know I can do exact matches by day or date, but I want to find matches that disregard the hours/seconds. I was considering something along these lines:
$oneDayAppointments = Appointment::whereDay(
'start_date',
Carbon::now()->addDay()->day
)->get();
...would get me any appointments where the start_date is a day from now. Now how would I hone it to the day and hour. If I were to just use a where clause:
$oneDayAppointments = Appointment::where(
'start_date',
Carbon::now()->addHours(24)
)->get();
...I could get exact matches, but only if the minutes/seconds were a match as well. Thanks!
Working on my comment above, this should do it
$tomorrowStart = Carbon::createFromFormat('Y-m-d H:i:s', Carbon::now()->addDay()->format('Y-m-d H:00:00'));
$tomorrowEnd = $tomorrowStart->copy()->addHour()->subSecond();
//whereBetween('start_date', [$tomorrowStart, $tomorrowEnd])
https://laravel.com/docs/5.8/queries
I am trying to implement a delivery process that occurs at specific days of week for each region. So, in a Region that delivers on Tuesdays and Thursdays I need to be able to get next eligible date based on the date the product will be available. So, if I will have it read on the 5th, O need to get the date for the next Tuesday or Thursday.
I started implementing it on Carbon, but I and creating a lot of loops through dates, testing dates and checking if its valid. something of getting product availability date and checking each day after it if its a monday Tuesday or Thursday ... etc ///I am sure, using Carbon, will have a better way to do it.
Any hint on how to do that ?
Thanks for any help!
Define a date:
$date = Carbon::now();
Now you have to get the day:
$day = $date->dayOfWeekIso
If $date is monday, then you will get a integer and that would be 1. That is because: 1 (monday), 2 (Tuesday), ..., 7 (sunday).
Now that you have this number you just need to apply some simple logic.
If the number you get is a 2 (Tuesday) then you will need to add two days to your $date in order to get the delivery date:
$delivery_date = $date->addDays(2);
If your day is equal 4 (Thursday), then you need to add 6 days to your $date so that would give you the next Tuesday:
$delivery_date = $date->addDays(6);
I think that's what you want! I hope it helps!
I have a jquery calendar for the start date of a project.
Using Watir (automated browser driver, a gem for ruby), I have a set date that I would like to enter in.
The calendar start date is always today's date, whatever that may be for the day it is used. I was wondering if there was a way that ruby can process what today's date is, and use the specified date provided by the user, to calculate the difference of months between them.
Here is an example of the Calendar plugin: http://jqueryui.com/datepicker/
example:
today's date is 30/10/2012, if there was a project that were to start on the 20/12/2012, that would be 2 months from now, so 2 clicks on the next month button.
Is there a way I could do this?
Here is how I approached a similar situation with JSdatepicker:
$today = Time.now.strftime("%e").gsub(" ", "") #one digit day of month without leading space
#browser.text_field(:id => /dateAvailable/).click
Watir::Wait.until(60) {#browser.div(:id => /dateAvailable_popup_cal/).td(:text => $today).exists?}
#browser.div(:id => /dateAvailable_popup_cal/).td(:text => $today).click
Set or grab the date.
Click the text_field that fires the JSDatePicker object
Wait until the calendar actually pops up
The current month is shown, so choose today's date number.
In your case, you also need to set the month. Whether prompting the user for this, or choosing "today", the theory is the same:
$month = Date::MONTHNAMES[Date.today.month] #etc
Pseudo-code making lots of assumptions (only future dates, month name shown on calendar as text, etc):
while !#jquerytablewindow.text.include?($month)
next_month_button.click
end
I don't see a specific advantage to my method versus counting each month, unless of course we add a month to the calendar one day and you still want your code to work!
You could do:
#End date converted to date object
specified_date = '20/12/2012'
end_date = Date.parse(specified_date)
#Start date (today - 30/10/2012)
today = Date.today
#Determine difference in months
number_of_months_up_to_today = (today.month + today.year * 12)
number_of_months_up_to_end = (end_date.month + end_date.year * 12)
clicks_required = number_of_months_up_to_end - number_of_months_up_to_today
#=> 2
Basically it is counting the number of months since the year 0 and then finding the difference.
I have an object which contains a list of due dates, I am trying to build a system which returns the due date when a specified date is 1 month or less before the due date. It should return the due date in this format "1st Feb 2009". Let me clarify, using my current code
#Build array of estate objects
estate.due_dates = "1st Feb, 3rd May, 1st Aug, 5th Nov"
estate2.due_dates = "28th Feb, 31st May, 31st Aug, 30th Nov"
estates = [estate,estate2]
set_due_date_on_estates("1st Jan 2009",estates) #Run function - should return "1st Feb 2009,28th Feb 2009"
def set_due_date_on_estates(date,estates)
estates.each{|estate|
estate.due_dates.split(",").each{|due_date|
((date)..(date >> 1)).each{|current_date|
estate.set_reminder(due_date + current_date.strftime("%Y")) if current_date.strftime('%d %m') ==
Date.parse(due_date).strftime('%d %m')
}
}
end
}
The issue I am having, is that my list of due dates doesnt have a Year, so I am looping through my range and checking if the dates are equal using the format "%d %m". If so I am setting the reminder in the estate object by using the current "due date" in the loop concatenated with the Year of the "current date" in the loop.
Am not too happy with the code, in particular the nested loops and wondered if there was a better way I could deal with checking that the due_dates where in the date range, even though the due_dates dont have a year. Thanks
You could use date parsers: Kronos, chronic
Example for kronos:
def parse_date(date)
Kronos.parse(date.sub(/\d{4}$/, ''))
end
This function gives you a Kronos object without year which is more easily to compare, build range and so on.
Yes you can use Chronic and also you can write a worker which will keep checking if the specified date is 1 month or less before the due date at regular interval. And ask that worker to do something if result is true (say send you an email or anything if date is within due date) you can find more information about worker by googling Resque and Redis. Another option would be to convert both dates on some base reference and then do the calculations.