I`m using quartz cron expression to build n schedule events, i have a start date and end date, but, when a crate a expression, the second event (getNextValidTimeAfter) its wrong...
08-03-19 08:00:00 -- first date
05-04-19 08:00:00 -- wrong date...
05-07-19 08:00:00
04-10-19 08:00:00
Follow the expression
0 0 8 ? 1/3 FRI#1 *
org.quartz.CronExpression expression = new org.quartz.CronExpression(cronExpression.getExpression());
List<Schedule> scheduleList = new ArrayList<>();
Date nextExecutionDate = cronExpression.getStartDate();
boolean first = true;
while (true) {
Schedule schedule = new Schedule();
schedule.setStatus(Enums.StatusSchedule.PROGRAMADO);
schedule.setCronExpression(cronExpression);
schedule.setServiceOrderType(cronExpression.getServiceOrderType());
schedule.setEstimatedTime(cronExpression.getEstimatedTime());
if (first == false)
nextExecutionDate = expression.getNextValidTimeAfter(nextExecutionDate);
else
first = false;
if (cronExpression.getEndDate().compareTo(nextExecutionDate) <= 0)
break;
schedule.setScheduleDate(nextExecutionDate);
if (CollectionUtils.isEmpty(schedule.getScheduleItems()))
schedule.setScheduleItems(new ArrayList<>());
for (GenericShelfData genericShelfData : genericShelfDataList) {
ScheduleItem scheduleItem = new ScheduleItem();
scheduleItem.setStatus(Enums.StatusSchedule.PROGRAMADO);
scheduleItem.setSchedule(schedule);
scheduleItem.setGenericShelfData(genericShelfData);
scheduleItem.setScheduleSeparate(Enums.YesOrNo.NAO);
schedule.getScheduleItems().add(scheduleItem);
}
scheduleList.add(schedule);
}
My expression was wrong... The correct is.. 0 0 8 ? 3/3 FRI#2 *
I use this site for build a expression: https://www.freeformatter.com/cron-expression-generator-quartz.html
Related
I'm using mpxj 4.5 to export ms project. When i open mpx file by ms project, I'm getting incorrect start date and finish date, but it's calculating duration correctly. What am i doing wrong, please tell.
To create mpx task I use following parametrs of mpxj:
public ProjectFile exportToMSProject(Integer projectID){
file.setAutoTaskID(true);
...........
}
private void createMSProjectTask(ProjectFile file, EUser user, ETask eTask)
Task task = file.addTask();
task.setUniqueID(eTask.getObjectID());
task.setName(eTask.getName());
task.setNotes(eTask.getDescription());
task.setType(TaskType.FIXED_DURATION);
long workTime = 0;
if(eTask.getDueDate() != null && eTask.getStartDate() != null){
workTime = (eTask.getDueDate().getTime() - eTask.getStartDate().getTime()) / (1000 * 60 * 60);
}
if(eTask.isAllDay()){
task.setDuration(Duration.getInstance(workTime / 24, TimeUnit.DAYS));
}else {
task.setDuration(Duration.getInstance(workTime, TimeUnit.HOURS));
}
if(eTask.getStartDate() != null)
task.setStart(user.getUserDate(eTask.getStartDate())); //get time from user time zone
if(eTask.getDueDate() != null)
task.setFinish(user.getUserDate(eTask.getDueDate()));
task.setPercentageComplete(eTask.getPercent() != null ? eTask.getPercent() : new Float(0.0));
if(eTask.getActualStartDate() != null)
task.setActualStart(eTask.getActualStartDate());
}
I'm getting repeatedly startdate and incorrect enddate. What is the problem here? Any suggestion will be appreciated.
I had the same issue. From my point of view, if you not have any predecessor or actual start date of your tasks, mpxj sets startdate automatically, I mean, it gets startdate from your project header or first task's start date of your project. That's why you got repeated startdate.
Here is the simple example (I'm using mpxj 4,5 and creating .mpx file):
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
ProjectFile file = new ProjectFile();
ProjectHeader header = file.getProjectHeader();
header.setStartDate(df.parse("01/05/2014"));
Task task1 = file.addTask();
task1.setName("Summary Task");
Task task2 = task1.addTask();
task2.setName("First Sub Task");
task2.setDuration(Duration.getInstance(10.5, TimeUnit.HOURS));
task2.setStart(df.parse("01/05/2014"));
task2.setPercentageComplete(NumberUtility.getDouble(50.0));
Task task3 = task1.addTask();
task3.setName("Second Sub Task");
task3.setStart(df.parse("11/05/2014"));
task3.setDuration(Duration.getInstance(10, TimeUnit.HOURS));
Task milestone1 = task1.addTask();
milestone1.setName("Milestone");
milestone1.setStart(df.parse("21/05/2014"));
milestone1.setDuration(Duration.getInstance(0, TimeUnit.HOURS));
Task task4 = file.addTask();
task4.setName("Last Task");
task4.setDuration(Duration.getInstance(8, TimeUnit.HOURS));
task4.setStart(df.parse("02/05/2014"));
task4.setPercentageComplete(NumberUtility.getDouble(70.0));
ProjectWriter writer = getWriter(filename);
writer.write(file, filename);
As you have seen, I'm not giving any predecessor or actual start date. If you run this you will get following result.
In order to get start date correctly, i gave an actual startdate not a startdate, and it worked. In addition if you have predecessor, you will get parent task's due date as a startdate.
task.setActualStart(df.parse("02/05/2014"));
By the way, ms project sets due date based on your duration.
What I've used as guidelines:
http://developer.android.com/guide/topics/providers/calendar-provider.html#events
http://developer.android.com/reference/android/provider/CalendarContract.Events.html
https://www.rfc-editor.org/rfc/rfc5545#section-3.8.5.3 (for RRULE)
What I have about the Event:
start date
recurring end date
frequency (every day/week/month/year)
What I need, considering:
start date: 11.06.2014 13:00
recurring frequency: "daily"
recurring end date: 14.06.2014 10:00
I need to add an Android event which lasts 1h every day from 11.06 to 14.06 (not inclusive - because start hour is higher than recurring end hour):
11.06 13:00-14:00
12.06 13:00-14:00
13.06 13:00-14:00
What I have until now (ignore non-recurring events - everything works as expected in those cases):
...
ContentValues values = new ContentValues();
values.put(Events.DTSTART, event.getDate().getTime());
if (!event.isRecurring()) { // ignore
values.put(Events.DTEND, event.getEndDate().getTime());
values.putNull(Events.DURATION);
values.putNull(Events.RRULE);
values.putNull(Events.RDATE);
} else {
values.putNull(Events.DTEND);
values.put(Events.DURATION, "PT1H"); // set event duration as 1H - this is ok hardcoded
values.put(Events.RDATE, event.getRecurringEnd().getTime()); // when the event should stop recurring
values.put(Events.RRULE,
Utils.getRRuleForRecurring(event.getRecurring()) + ";UNTIL=" + event.getRecurringEnd().getTime());
}
values.put(Events.TITLE, event.getName());
values.put(Events.DESCRIPTION, event.getDescription() == null ? ""
: event.getDescription());
values.put(Events.CALENDAR_ID, calendarId);
values.put(Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());
...
RRule generate method:
public static String getRRuleForRecurring(String recurring) {
recurring = recurring.toLowerCase();
if (recurring.equals("every day")) {
return "FREQ=DAILY";
}
if (recurring.equals("every month")) {
return "FREQ=MONTHLY";
}
if (recurring.equals("every week")) {
return "FREQ=WEEKLY";
}
if (recurring.equals("every year")) {
return "FREQ=YEARLY";
}
return "FREQ=DAILY";
}
What happens: nothing, no errors. But the events doesn't show in the calendar. Again, for the non-recurring ones it works as expected
I am trying to convert given number of minutes into milliseconds.
For eg: 15mins or 20mins or 44mins should be converted to milliseconds programmatically.
I tried the below:
Calendar alarmCalendar = Calendar.getInstance();
alarmCalendar.set(Calendar.MINUTE,15);
long alarmTime = alarmCalendar.getTimeInMillis();
Log.e("Milli", "seconds"+alarmTime);
This doesn't give the right value? What is the best way to convert this?
TimeUnit.MINUTES.toMillis(yourMinutes)
see TimeUnit javadoc (android)
int minutes = 42;
long millis = minutes * 60 * 1000;
1 minute = 60000 millisecs.
int minutes = 1;
long milliseconds = minutes * 60000;
In Java 8+, use java.time.
java.time.Duration.ofMinutes(15).toMillis();
This answer is in reference to Android using Kotlin-
So if you are using MaterialTimePicker or TimePicker then you can get the hours and minutes values stored in the picker. Then use TimeUnit.HOURS.toMillis(picker.hour.toLong()) and TimeUnit.MINUTES.toMillis(picker.minutes.toLong()) to convert the received time to milliseconds and then add both the values to get the total time in Milliseconds which you can further use to store in Room Database for entering time and fetching when required.
Code for reference :
binding.timeStart.setOnClickListener {
openTimePicker()
picker.addOnPositiveButtonClickListener {
val h = picker.hour
val m = picker.minute
binding.timeStart.text = "$h:$m"
Timber.d("Start Time - $h: $m")
try {
val hour = TimeUnit.HOURS.toMillis(h.toLong())
val minute = TimeUnit.MINUTES.toMillis(m.toLong())
val totalTime = hour + minute
Timber.d("Hour - $hour, Minute - $minute, Total = $totalTime")
timeStart = totalTime
} catch (e: Exception) {
Timber.d("$e")
}
}
}
private fun openTimePicker() {
picker = MaterialTimePicker.Builder()
.setTimeFormat(TimeFormat.CLOCK_12H)
.setHour(12)
.setMinute(10)
.setTitleText("Set Start Time")
.build()
picker.show(childFragmentManager, "TAG")
}
This gives you the time in milli.
long currentTime = System.currentTimeMillis()
Handler handler = new Handler();
long waitTime = currentTime + (15*60*1000);
handler.postDelayed(new Runnable() {
public void run() {
// Alert or do something here.
}
}, waitTime);
This piece of code sleeps for 15 minutes and then executes the handler's run method. This way you can raise an alarm etc...
I am writing a Java program that is required to copy files and folders between the following hours:
Mon - 18:00 to 06:30
Tue - 18:00 to 06:30
Wed - 18:00 to 06:30
Thu - 18:00 to 06:30
Fri - 18:00 to 06:30
Sat - all day
Sun - all day
The program will run continuously until it has finished copying all files and folders. However, outside of the above hours the program should just sleep.
I am using a properties file to store the above settings.
UPDATE
I am looking for the simplest possible implementation including the format of the properties in the properties file as well as the code that will make the checks.
I would do it like this
final Map<Integer, String> schedule = new HashMap<>();
// parse your settings and fill schedule
schedule.put(Calendar.MONDAY, "18:00 to 06:30");
// ...
// create timer to fire e.g. every hour
new Timer().scheduleAtFixedRate(new TimerTask() {
public void run() {
Calendar c = Calendar.getInstance();
String s = schedule.get(c.get(Calendar.DAY_OF_WEEK));
if (withinTimeRange(c, s)) { // implement withinTimeRange func
// copy files
}
}}, 0, 1000 * 3600);
Since your program is going to run continuously, the simplest solution is to check the day and time before copying a file. If the time is during off hours, go ahead and copy the next file, otherwise Thread.sleep.
If this is an internal, one-off kind of program, I would go ahead and hard-code the business hours instead of reading the properties file. No need to add complexity.
whenever your program is launched, get the current time, and check day today's day.
check whether it lies in permissible time if yes let it continue. If not, find the time at 00:00am of that 'day'. and find the time at xx:yyZZ (start of permissible time). calculate the difference, and let the program sleep for that much of time.
Thank you for your suggestions.
I came up with a working solution in the end which if it gets enough points I will mark as the answer. The way I attempted to solve this problem was by thinking about non-working hours rather than working hours. This code is just for illustration
# Properties
Mon = 06:30-18:00
Tue = 06:30-18:00
Wed = 06:30-18:00
Thu = 06:30-18:00
Fri = 06:30-18:00
Loop over the properties to get their values
String[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
Map<Integer, Integer[]> nonWorkingHours = new HashMap<Integer, Integer[]>();
for( int i = 0; i < days.length; i++ ) // for each property in file
{
// excluded implementation of getConfig
String prop = getConfig( days[ i ] ); // e.g. "06:00-19:00"
// +1 to match CALENDAR.DAY_OF_WEEK
nonWorkingHours.put( i + 1, getHours( prop );
}
My function to parse property excluding error handling
// e.g. if prop = "06:00-19:00" then { 6, 0, 19, 0 } is returned
public Integer[] getHours( String prop )
{
String times = prop.split( "(:|-)" );
Integer[] t = new Integer[4];
for( int i = 0; i < times.length; i++ )
{
t[i] = Integer.parseInt( times[i] );
}
return t;
}
And finally the function that implements the halt
private void sleepIfOutsideWorkingHours()
{
Integer[] data = nonWorkingHours.get( currentDay );
if( data != null )
{
Calendar c = Calendar.getInstance();
Integer currentSeconds = ( Calendar.HOUR_OF_DAY * 3600 ) + ( Calendar.MINUTE * 60 );
Integer stopFrom = ( data[ 0 ] * 3600 ) + ( data[ 1 ] * 60 );
Integer stopTill = ( data[ 2 ] * 3600 ) + ( data[ 3 ] * 60 );
if( currentSeconds > stopFrom && currentSeconds < stopTill )
{
Integer secondsDiff = stopTill - currentSeconds;
if( secondsDiff > 0 )
{
try
{
Thread.sleep( secondsDiff * 1000 ); // turn seconds to milliseconds
}
catch( InterruptedException e )
{
// error handling
}
}
}
}
}
And finally just call the function below just before copying each file and if it is being run outside working hours it will stop the program.
sleepIfOutsideWorkingHours();
I am sure there is a simpler way of doing it :-) but there it is.
You should try using a Continuous Integration system. That scenario can be easily set up using Jenkins CI for example.
The reason i advise doing it so in a ambient like that is that you can keep a better control on the history of your program runs.
Can anyone tell me why the following code is causing an error on the last line with the command "execute" with the error message:
The method execute(Object, Object, Object) in the type Query is not applicable for the arguments (Long, Long, Date, Date)
Query q = pm.newQuery(Appointment.class,"AdminID == AID"+
" && EmployeeID == CEID"+
" && Time > STime"+
" && Time < ETime");
q.declareImports("import java.util.Date");
q.declareParameters("Long AID, Long CEID, Date STime, Date ETime");
q.setOrdering("Time");
Appointments = (List<Appointment>) q.execute(AdminID, CurrentEmployeeID, Time1, Time2);
As far as I can tell (implied by the error message, the execute function can only take a maximum of 3 arguements, if this is the case, can anyone advise on how to achieve what I want to do? I have tried the following code, but I get a parsing error every time it runs!
Query q = pm.newQuery(Appointment.class,"AdminID == "+AdminID+
" && EmployeeID == "+CurrentEmployeeID+
" && Time > "+Time1+
" && Time < "+Time2);
q.declareImports("import java.util.Date");
q.setOrdering("Time");
Appointments = (List<Appointment>) q.execute();
The Parsing error I get is:
org.datanucleus.store.query.QueryCompilerSyntaxException: Portion of expression could not be parsed: Aug 13 11:44:55 BST 2012 && Time < Mon Aug 13 11:45:05 BST 2012
Try executeWithArray or executeWithMap.
HashMap<String, Object> params = new HashMap<String, Object>();
params.put( "AID", adminId );
params.put( "CEID", currentEmployeeId );
params.put( "STime", startTime );
params.put( "ETime", endTime );
query.executeWithMap( params );
Notes:
variables should be lowerCamelCase
startTime and endTime are more descriptive than Time1, Time2
"Id" is generally preferred over "ID" - What is correct Java naming convention for id?
your second attempt won't work because it's implicitly calling ..." && Time > " + Time1.toString() + ...