Spring schedule - last day of month not working - cron

I wanted to run a spring scheduler job at 'last day of every month at 10:15' and 'First Sunday of every month' -
I have tried below - but it is giving error while initializing spring context:
org.springframework.boot.SpringApplication:Application startup failed
java.lang.IllegalStateException: Encountered invalid #Scheduled method 'monthEndSchedule': For input string: "L"
#Override
#Scheduled(cron = "0 15 10 L * ?")
public void monthEndSchedule() {
//
}
Though below works which runs at 'every day 1 am'
#Override
#Scheduled(cron = "0 0 1 * * ?")
public void surveyDailySchedule() {
//
}
Cron expression reference I have used : http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html

Spring Scheduler does not support the "L" input string. So, you need to do a workaround.
First, call scheduler for each of the possible last days of months (28,29,30,31).
Then, inside the function block check with an if block whether this is the last date. If it is, then perform the expected task.
Code will be like this -
#Scheduled(cron = "0 15 10 28-31 * ?")
public void monthEndSchedule() {
final Calendar c = Calendar.getInstance();
if (c.get(Calendar.DATE) == c.getActualMaximum(Calendar.DATE)) {
// do your stuff
}
}

If someone prefers to do the check with JDK8+, here it is:
#Scheduled(cron = "0 15 10 28-31 * ?")
public void doStuff() {
LocalDate date = LocalDate.now();
LocalDate last = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
if (date.getDayOfMonth() == last.getDayOfMonth()) {
//TODO: your job
}
}
This will run at 6 pm on the last 4 days of every month.

Related

How do I get the output of the function in Groovy

static def StartMonth() {
def date = new Date().format('MM')
def month = date.toInteger()
if (month > 6) {
month = month - 6
} else if (month <= 6) {
month = (month + 12) - 6
}
}
static void main(String[] args) {
StartMonth();
}
}
I have this and the output will be 4 (right now in October) and I want to retrieve that value so that I can have a new variable newDate = *startDate output* + '25/2019' but I do not know how to get the value back. (I am very new to this, I usually program in Javascript and even then I am still a beginner)
Thank you
In groovy you can return a value using the return value (as you can do in javascript). If there is no return a method returns the last value assigned (month in your case).
So you can either add return month in your StartMonth method. Or you can keep it as it is and just print it:
static void main(String[] args) {
println StartMonth()
}

Selecting a date between certain range based on conditions using groovy

I am having a little issue with a date generator code below. The list of the code below is to ensure that a random date is selected within the summer months (May, June, July August) for availability.
So what I did is that I say if the current month is less than 5 (less than May), then select a random date between 1st May this year till 31st August this year, else if the current month is past 7 (past July), then select a random date between 1st May next year till 31st August next year.
Now I notice a little glitch in my code I require help with. As I ran the code below today (8th May), it is possible that the date the random generator selects could be in May before today's date. Actually the issue is I don't have anything to handle when I am in the current months. So I think I require a little refactoring.
What i would like is that it checks the current date and if it between May to July (so not less than May or more than July), then check today's date and pick a date between today till the 31st August this year.
My brain has been fried and for some strange reason I am struggling on something which logically makes sense, but I've just been having issues programming it.
import groovy.time.TimeCategory
//def dataSet = testRunner.testCase.getTestStepByName("Properties")
// Select the current test data line
def dateFormat = 'yyyy-MM-dd'
def getNumberInRange = { min, max -> new Random().nextInt(max + 1 - min) + min }
def isTodayBeforeMay = { Calendar.MONTH < 5 }
def isTodayAfterJuly = { Calendar.MONTH > 7 }
//Get the number of days between today and given date
def getDifferenceDays = { targetDate, closure ->
def strDate = closure (targetDate)
def futureDate = new Date().parse(dateFormat, strDate)
TimeCategory.minus(futureDate, new Date()).days
}
//Get the offset between today and max date i.e.,31 august
def getOffSetDays = { date ->
//Need to change the date range if needed.
//As per OP, May to August is mentioned below
def max = getDifferenceDays(date) { "${it[Calendar.YEAR]}-08-31" }
def min = getDifferenceDays(date) { "${it[Calendar.YEAR]}-05-01" }
getNumberInRange(min, max)
}
def now = new Date()
def nextYearNow = now.updated(year: now[Calendar.YEAR] + 1)
def selected
def finalDate
log.info "Today : $now"
log.info "Next year same date : $nextYearNow"
if (isTodayBeforeMay()) {
selected = now
} else if (isTodayAfterJuly()) {
selected = nextYearNow
} else {
throw new Error("Not implemented for the days between 1st May to 30th July")
}
def offset = getOffSetDays(selected)
//Add the offset days to now
use(TimeCategory) {
finalDate = now + offset.days
}
All you need is to implement the else condition instead of throw new Error(..) below (code excerpt from the question):
If you read the code, it is crystal clear each condition and error message as place holder for the unknown data range in below and which is now you wanted it to be handled.
if (isTodayBeforeMay()) {
selected = now
} else if (isTodayAfterJuly()) {
selected = nextYearNow
} else {
throw new Error("Not implemented for the days between 1st May to 30th July")
}
Just add the below statement in the last else in place of threw new Error
selected = getOffSetDays(now)
EDIT:
You can try quickly online Demo
EDIT 2: Looks the above is not working at times randomly, so updating the answer:
import groovy.time.TimeCategory
def dateFormat = 'yyyy-MM-dd'
def getNumberInRange = { max, min = 1 -> new Random().nextInt(max + 1 - min) + min }
def isTodayBeforeMay = { Calendar.MONTH < 5 }
def isTodayAfterJune = { Calendar.MONTH > 6 }
//Get the number of days between today and given date
def getDifferenceDays = { targetDate, closure ->
def strDate = closure (targetDate)
def futureDate = new Date().parse(dateFormat, strDate)
TimeCategory.minus(futureDate, new Date()).days
}
def getPaddedString = { num, len = 2, padwith = '0' ->
num.toString().padLeft(len, padwith)
}
//Get the offset between today and max date i.e.,31 august
def getOffSetDays = { date, minMonth = 5, minDay = 1 ->
//Need to change the date range if needed.
//As per OP, May to August is mentioned below
def max = getDifferenceDays(date) { "${it[Calendar.YEAR]}-08-31" }
def min = getDifferenceDays(date) { "${it[Calendar.YEAR]}-${getPaddedString(minMonth)}-${getPaddedString(minDay)}" }
getNumberInRange(max, min)
}
def now = new Date()
def nextYearNow = now.updated(year: now[Calendar.YEAR] + 1)
def selected
def finalDate
println "Today : $now"
println "Next year same date : $nextYearNow"
if (isTodayBeforeMay()) {
selected = now
} else if (isTodayAfterJune()) {
selected = nextYearNow
}
def dayz = getNumberInRange(getDifferenceDays(now) { "${it[Calendar.YEAR]}-08-31" })
def offset = selected ? getOffSetDays(selected) : dayz
offset = offset > 0 ? offset : now[Calendar.DAY_OF_MONTH]+1
//Add the offset days to now
use(TimeCategory) {
finalDate = now + offset.days
}
println "Final future date is : $finalDate"
println "Final future date is(formatted) : ${finalDate.format(dateFormat)}"
assert now <= finalDate
This Demo generate the date 1000 times just to make sure the date is ok.

Calendar.set error or infinite loop

the following does not seem to work, it seems to cause an infinite loop:
import java.text.SimpleDateFormat;
SimpleDateFormat out=new SimpleDateFormat('yyyy-MM-dd');
def from = Calendar.instance
from.set(year: 2017, month: Calendar.JANUARY, date: 3)
def to = Calendar.instance
to.set(year: 2017, month: Calendar.FEBRUARY, date: 3)
from.upto(to) {
cal=it;
prev=cal;
prev.set(Calendar.DAY_OF_MONTH, 1);
println out.format(prev.getTime());
}
can somebody please explain why this should not work? I don't get it. My goal is to get the first day of month within the upto loop.
Inside the loop, you are constantly setting the calendar back to the first day of the month...
It's similar to if you did:
for (int i = 0; i < 10; i++) {
i = 0
println i
}
(that will never finish either)
Also, you code will run for every day between the two dates... which I don't think is what you are looking for either
It's easier if you use immutable things over Calendar, and as you're on Java 8, you can do:
import java.time.*
import java.time.format.*
// Add a next method, so you can do ranges of LocalDates
LocalDate.metaClass.next = { delegate.plusDays(1) }
LocalDate from = LocalDate.of(2017, 1, 3)
LocalDate to = LocalDate.of(2017, 2, 3)
(from..to).each {
println it.format(DateTimeFormatter.ISO_DATE) + " : " + it.withDayOfMonth(1).format(DateTimeFormatter.ISO_DATE)
}

Groovy way to find dates in range by the day of the week

What would be the Groovy way to accomplish Joda Time example below:
LocalDate startDate = new LocalDate(2016, 11, 8);
LocalDate endDate = new LocalDate(2017, 5, 1);
LocalDate thisMonday = startDate.withDayOfWeek(DateTimeConstants.MONDAY);
if (startDate.isAfter(thisMonday)) {
startDate = thisMonday.plusWeeks(1); // start on next monday
} else {
startDate = thisMonday; // start on this monday
}
while (startDate.isBefore(endDate)) {
System.out.println(startDate);
startDate = startDate.plusWeeks(1);
}
And what about by more than 1 day of the week: MONDAY and TUESDAY, for example
Given your start and end date parameters, the following Groovy code (using Groovy Date.parse() and Date.format() mix-in functions, Groovy Date + int addition, Groovy String to int coercion, and a bit of algebra) seems to do the trick:
Date startDate = Date.parse("yyyy-MM-dd","2016-11-08")
Date endDate = Date.parse("yyyy-MM-dd","2017-05-01")
Date mondayStart = startDate + 6 - ((5 + (startDate.format("u") as int)) % 7)
while (mondayStart < endDate) {
println mondayStart
mondayStart += 7
}
Having said that, the while loop at the bottom is sort of... "open-ended". You can get a more analytical equivalent using Groovy's Range literal syntax and List.step() mix-in function. The following replaces only the while loop above:
(mondayStart..<endDate).step(7) { stepDate ->
println stepDate
}
Part 2: More than Monday
In order to work with other days of the week we need to replace the constant 5 in the mondayStart assignment with a suitable sub-expression based on the day of the week. Fortunately the following expression works quite nicely:
7 - Calendar."${weekDay.toUpperCase()}"
Putting the whole thing together and massaging a bit, it looks something like this:
def weekDaysInDateRange(Date startDate, Date endDate, String weekDay = "monday") {
startDate = startDate.clearTime()
endDate = endDate.clearTime()
def offset = 7 - Calendar."${weekDay.toUpperCase()}"
def startDOW = startDate.format("u") as int
def weekDayStartDate = startDate + 6 - (offset + startDOW) % 7
(weekDayStartDate..<endDate).step(7) { stepDate ->
println (stepDate.format("yyyy-MM-dd"))
}
}
With that function defined, the following test code:
def now = new Date()
def nextMonthIsh = new Date() + 30
println "$now --> $nextMonthIsh"
println "============================================================="
["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]
.each { weekDay ->
println """
$weekDay
=========="""
weekDaysInDateRange(now, nextMonthIsh, weekDay)
}
Gives the following result:
Mon Sep 19 09:29:24 CDT 2016 --> Wed Oct 19 09:29:24 CDT 2016
=============================================================
sunday
==========
2016-09-25
2016-10-02
2016-10-09
2016-10-16
monday
==========
2016-09-19
2016-09-26
2016-10-03
2016-10-10
2016-10-17
tuesday
==========
2016-09-20
2016-09-27
2016-10-04
2016-10-11
2016-10-18
wednesday
==========
2016-09-21
2016-09-28
2016-10-05
2016-10-12
thursday
==========
2016-09-22
2016-09-29
2016-10-06
2016-10-13
friday
==========
2016-09-23
2016-09-30
2016-10-07
2016-10-14
saturday
==========
2016-09-24
2016-10-01
2016-10-08
2016-10-15

From Date and To Date From Previous Weeks

I am working in C#.Net. I need the From Date and To Date.
For Ex : If i selected "Last Week" means, i should get 15th April - 21st April.
" 2 Weeks Ago " means, 8th April - 14th April. Same as for 3 Weeks ago, 4 Weeks ago etc..
How to get the From Date and To Date..
i made a console program..itz working fine.. chek it out
static void Main(string[] args)
{
Console.WriteLine("Enter week number");
int week = int.Parse(Console.ReadLine());
var weekStartDay = DayOfWeek.Monday;
int daysInAWeek = 7;
DateTime thisWeekStarttingDate = DateTime.Now.Subtract(new TimeSpan((int)DateTime.Now.DayOfWeek - (int)weekStartDay, 0, 0, 0)).Date;
DateTime fromDate = thisWeekStarttingDate.Subtract(new TimeSpan(daysInAWeek * week, 0, 0, 0));
DateTime toDate = fromDate.AddDays(daysInAWeek-1);
Console.WriteLine("from date:" + fromDate.ToShortDateString());
Console.WriteLine("to date:" + toDate.ToShortDateString());
Console.ReadKey();
}
var currentWeek_StartDate = GetStartWeekDate_By_Date(DateTime.Now.Date);
var lastWeek_StartDate = GetStartWeekDate_By_WeekIndex(currentWeek_StartDate, -1);
var lastWeek_EndDate = GetEndWeekDate_By_StartWeekDate(lastWeek_StartDate);
public static DateTime GetStartWeekDate_By_Date(DateTime date)
{
return date.AddDays(-(int)date.DayOfWeek);
}
public static DateTime GetEndWeekDate_By_StartWeekDate(DateTime date)
{
return date.AddDays(6);
}
public static DateTime GetStartWeekDate_By_WeekIndex(DateTime date, int weekIndex)
{
return date.AddDays(weekIndex * 7);
}

Resources