How to run a cron job the day before the 1st Wednesday of every month?

Hello,

in our city, the special garbage is collected every first Wednesday of every month. So I run a cron job at 18:30 the day before (every first Tuesday of every month) to play an audio message saying as “you need to take the special garbage out” with: Time cron “0 30 18 ? * 3#1 *”

But this approach is not perfect. For example, the first Wednesday of this month was on Wednesday August 1st 2018, so the audio message should have been played on Tuesday July 31st but it wasn’t played as July 31st is not the first Tuesday of this month

Could you advise me a way to run this cron job the day before the 1st wednesday of every month?

Thanks for any help

1 Like

I’m absolutely not an expert on this, but I like your question :wink:

Maybe the easiest approach would be to run a cron job every day and then check internally if today is the first Tuesday of the month. If so, send audio message. If not, do nothing.

I would use the persistence to flag if the day has already been found, plus in which month.
Some incomplete dummy code:

Cron job runs today (8th August):
read persistence “last_check_month” value = August
compare current_month with last_check_month (August / August)
if equal then
check persistence “first_tuesday_already_found” value = true (yesterday 7th August)
if value = true, ignore
else check if today is tuesday and send voice message, else do nothing

Cron job runs on 1st September:
read persistence “last_check_month” value = August
compare current_month with last_check_month (September / August)
if NOT equal then
set persistence “first_tuesday_already_found” value to: false
set last_check_month value to: current_month (September)
check if today is tuesday and send voice message, else do nothing

I wonder if recasting the question as “is tomorrow the 1st Wednesday?” helps. I do not know anything about cron to know if that can be formed directly, but it should certainly be do-able in an every-Tuesday job as suggested.

Thanks guys. By crossing both of your ideas, I could just run a daily cron job asking if “tomorrow is the 1st Wednesday of the month”. Does anyone know how I could code that in openhab?

A daily cron job is not needed, because you definitely want the message only on a Tuesday.
Just check on every Tuesday wether tomorrows day in month is less or equal to 7. No persistence needed for that.
But what if the calculated Wednesday is a holiday?

3 Likes

@opus, I think the holidays is not a problem because if the first Wednesday is a public holiday, the special garbage would be collected the next day anyway.

You are right, a cronjob on Tuesday only is enough. But I’d need to check if the “tomorrow’s day of month” (not today) is less than 7. Another way is to check if today’s day of month is less than 6 or is the last day of the month.

Do you know how to code that in openhab? I can probably code it in Bash script (which I know better) and run the script via “executeCommandLine” but coding it directly in openhab (if possible) would be more elegant.

As Spiral suggests -
0 0 12 ? * WED *
In the rule check that the date day is less than or equal to 7. Else exit.

From quartz tutorial it looks like there is a way to run a job on the last day of month if it’s Tuesday.
Check out this paragraph:

  • L (“last”) - has different meaning in each of the two fields in which it is allowed. For example, the value “L” in the day-of-month field means “the last day of the month” - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, it simply means “7” or “SAT”. But if used in the day-of-week field after another value, it means “the last xxx day of the month” - for example “6L” means “the last friday of the month”. You can also specify an offset from the last day of the month, such as “L-3” which would mean the third-to-last day of the calendar month. When using the ‘L’ option, it is important not to specify lists, or ranges of values, as you’ll get confusing/unexpected results

Never tried it though so I’d be very interested to know if it works…

@Mihai_Badea, good suggestion. But if we take this month as an example, I want the message to be played on Tuesday July 31st but NOT on Tuesday August 7th. So it would imply 2 rules in openhab:

when
    Time cron "0 30 18 ? * 3#1 *"
then
	if (today's day_of_month < 6){
		playSound(“take_the_special_garbage_out.mp3”)
	}
end

and

when
    Time cron "0 30 18 L * ? *"
then
	if (today's weekday = 3){
		playSound(“take_the_special_garbage_out.mp3”)
	}
end

A more elegant way would be:

when
    Time cron "0 30 18 ? * TUE *"
then
	if (tomorrow's day_of_month < 7){
		playSound(“take_the_special_garbage_out.mp3”)
	}
end

How can I code “tomorrow’s day_of_month < 7” in openhab?

val today = now.getDayOfWeek is what I’m using in one of my rules

@Mihai_Badea is there the same for “tomorrow”?

No, but tomorrow = today + 1, right? :smile:

@Mihai_Badea, indeed but what is the correct syntax for:

val tomorrow = today + 1
val tomorrow_DayOfMonth = tomorrow.getDayOfMonth

?
I feel sorry for the stupid question, I just don’t know Xbase…

if(now.plusDays(1).getDayOfMonth < 7) 

If you use VSCode with the openHAB extension when you type in “now.” a list of all the methods on now will be listed.

image

1 Like

Take a look at the Ephemeris binding it provides exactly the awaited functionality. This is an unmerged PR of OH2. I’m currently submitting another PR based on the same principles in ESH

@rlkoshak thank you very much! I imagined it would that simple.

By the way, I see what you mean about typing “now.” and wait for the methods. I am currently using the 1.8.0-designer-linux64bit and I remember that feature but I don’t see it anymore. Can you tell me how I can get it back?

Designer is dead. Use VSCode with the openHAB extension. I provided a link to the instructions to download and configure it above.

I don’t get that in VS code but everything appears to be set up correctly according to the documentation.
Everything else seems to work and auto-complete suggests my own items etc.
I guess it’s a language server problem.

Any ideas?

Many thanks!

I posted this in the VS Code thread but no one responded.

Look in openhab.log and under the Problems panel at the bottom. Are there any errors?

Yes. I didn’t look there (but I know I should have). I’m none the wiser though and didn’t get this error yesterday - only the user-generated choices such as items.

The stuff below is after pressing CTRL + space after if(now.

VS CODE Problems:

[Error - 4:27:31 PM] Request textDocument/completion failed.
  Message: Internal error, please look at the server's logs.
  Code: -32603 

openHAB log:

2018-08-10 16:27:28.990 [ERROR] [ypes.access.impl.AbstractClassMirror] - resource is empty: java:/Objects/org.joda.time.LocalDate
java.lang.IllegalStateException: null
	at org.eclipse.xtext.common.types.access.impl.AbstractClassMirror.getEObject(AbstractClassMirror.java:94) ~[?:?]
	at org.eclipse.xtext.common.types.access.TypeResource.getEObject(TypeResource.java:90) ~[?:?]
	at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.getEObject(ResourceSetImpl.java:223) ~[?:?]
	at org.eclipse.xtext.common.types.access.impl.IndexedJvmTypeAccess.getIndexedJvmType(IndexedJvmTypeAccess.java:79) ~[?:?]
	at org.eclipse.xtext.common.types.access.impl.IndexedJvmTypeAccess.getIndexedJvmType(IndexedJvmTypeAccess.java:69) ~[?:?]
	at org.eclipse.xtext.common.types.access.TypeResource.resolveJavaObjectURIProxy(TypeResource.java:164) ~[?:?]
	at org.eclipse.xtext.common.types.impl.JvmTypeReferenceImplCustom.eResolveProxy(JvmTypeReferenceImplCustom.java:27) ~[?:?]
	at org.eclipse.xtext.common.types.impl.JvmParameterizedTypeReferenceImpl.getType(JvmParameterizedTypeReferenceImpl.java:111) ~[?:?]
	at org.eclipse.xtext.xbase.typesystem.internal.ExpressionScope$Scope.getParameterType(ExpressionScope.java:410) ~[?:?]
	at org.eclipse.xtext.xbase.typesystem.internal.ExpressionScope$Scope.appendParameters(ExpressionScope.java:507) ~[?:?]
	at org.eclipse.xtext.xbase.typesystem.internal.ExpressionScope$Scope.getSignature(ExpressionScope.java:491) ~[?:?]
	at org.eclipse.xtext.xbase.typesystem.internal.ExpressionScope$Scope.recordDescription(ExpressionScope.java:397) ~[?:?]
	at org.eclipse.xtext.xbase.typesystem.internal.ExpressionScope$Scope.populateFromParent(ExpressionScope.java:348) ~[?:?]
	at org.eclipse.xtext.xbase.typesystem.internal.ExpressionScope$Scope.ensureInitialized(ExpressionScope.java:325) ~[?:?]
	at org.eclipse.xtext.xbase.typesystem.internal.ExpressionScope$Scope.getAllElements(ExpressionScope.java:317) ~[?:?]
	at org.eclipse.xtext.ide.editor.contentassist.IdeCrossrefProposalProvider.queryScope(IdeCrossrefProposalProvider.java:76) ~[?:?]
	at org.eclipse.xtext.ide.editor.contentassist.IdeCrossrefProposalProvider.lookupCrossReference(IdeCrossrefProposalProvider.java:50) ~[?:?]
	at org.eclipse.xtext.xbase.ide.contentassist.XbaseIdeContentProposalProvider.createReceiverProposals(XbaseIdeContentProposalProvider.java:619) ~[?:?]
	at org.eclipse.xtext.xbase.ide.contentassist.XbaseIdeContentProposalProvider.completeXMemberFeatureCall(XbaseIdeContentProposalProvider.java:572) ~[?:?]
	at org.eclipse.xtext.xbase.ide.contentassist.XbaseIdeContentProposalProvider._createProposals(XbaseIdeContentProposalProvider.java:159) ~[?:?]
	at org.eclipse.xtext.xbase.ide.contentassist.XbaseIdeContentProposalProvider.createProposals(XbaseIdeContentProposalProvider.java:641) ~[?:?]
	at org.eclipse.xtext.ide.editor.contentassist.IdeContentProposalProvider.createProposals(IdeContentProposalProvider.java:94) ~[?:?]
	at org.eclipse.xtext.ide.server.contentassist.ContentAssistService.createProposals(ContentAssistService.java:108) ~[?:?]
	at org.eclipse.xtext.ide.server.contentassist.ContentAssistService.createCompletionList(ContentAssistService.java:73) ~[?:?]
	at org.eclipse.xtext.ide.server.LanguageServerImpl.lambda$completion$14(LanguageServerImpl.java:425) ~[?:?]
	at org.eclipse.xtext.ide.server.WorkspaceManager.doRead(WorkspaceManager.java:234) ~[?:?]
	at org.eclipse.xtext.ide.server.LanguageServerImpl.completion(LanguageServerImpl.java:427) ~[?:?]
	at org.eclipse.xtext.ide.server.LanguageServerImpl.lambda$completion$13(LanguageServerImpl.java:406) ~[?:?]
	at org.eclipse.xtext.ide.server.concurrent.RequestManager.lambda$runRead$2(RequestManager.java:116) ~[?:?]
	at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:602) [?:?]
	at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:577) [?:?]
	at java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:442) [?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:?]
	at java.lang.Thread.run(Thread.java:748) [?:?]

Thank you for replying.