Have a function run at a different time everyday - scheduled-tasks

I'm coming up with a piece of code that runs at a specific time each and every day for 1 or 2 hours.
import schedule
import time as t
import re
import datetime as dt
sunset = open("TESTsunset.txt")
text = sunset.read()
times = re.findall(r'(\d+:\d+:\d+)',text)
def start():
print ("Start solar panel and data collection")
def stop():
print ("Stop solar panel and data collection")
for time in times:
schedule.every().day.at(time).do(start) #Will be time of sunset,
date = dt.datetime.strptime(time, '%H:%M:%S')
date = date+dt.timedelta(minutes=1)
schedule.every().day.at(date.strftime('%H:%M:%S')).do(stop) #Will be 1 hour after the time of sunset
while True:
schedule.run_pending()
t.sleep(1)
The text document for testing looks like this:
16/05/2022 11:11:21
16/05/2022 11:12:26
16/05/2022 11:14:22
16/05/2022 11:15:25
16/05/2022 11:16:31
16/05/2022 11:17:39
The actual document would look like this
01/01/2022 16:25:21
02/01/2022 16:26:20
03/01/2022 16:27:22
04/01/2022 16:28:25
05/01/2022 16:29:31
06/01/2022 16:30:39
07/01/2022 16:31:48
Schedule seems to work, however it only looks at the time and I would like it to remember the date and time incase the computer its running from turns off. Otherwise the programme would start again. Also it would currently also run multiple times a day because of the start times of sunset
I've also tried using datetime but can't seem to get it to work.
import schedule
import time as t
import datetime as dt
sunset = open("TESTsunset.txt")
def start():
print ("Start solar panel and data collection")
def stop():
print ("Stop solar panel and data collection")
def collection():
for date in sunset:
date = date.rstrip()
if dt.datetime.now() == dt.datetime.strptime(date, "%d/%m/%Y %H:%M:%S"):
start
if dt.datetime.now() == dt.datetime.strptime(date, "%d/%m/%Y %H:%M:%S") + dt.timedelta(minutes=1):
stop
schedule.every().day.at("13:17").do(collection)
while True:
schedule.run_pending()
t.sleep(1)
Eventually this will be in something like an arduino attached to a solar panel that charges a battery at the set time while also collecting the data produced.
Am I on the right track or is there something else I can do? Reliability will be pretty crucial as it will run for a year

Related

How to calculate the next minute and next 5 minute intevals given a ZonedDateTime

I have a instance of a ZonedDatetime.
ZonedDateTime.now(ZoneId.of("America/New_York"))
I basically need a function that will take an instance of a ZonedDateTime and return the next 1 minute and 5 minute values.
So if the current time is:
2021-10-24T19:46:10.649817
The next minute will be 19:47:00 and the next 5 minute will be 19:50:00
The next 5 minute interval is always like:
1:00
1:05
1:10
1:15
1:20
1:25
...
1:50
1:55
2:00
i.e. the next 5 minute interval is not based on exactly 5 minutes from now, but rather the next 5 minutes based on starting from the beginning of the hour. Same goes for the next 1 minute interval in the future.
def nextIntervals(zdt: ZonedDateTime): (ZonedDateTime, ZonedDateTime) = {
???
}
It is fairly simple to do so without hardcoding the values. Unfortunately I'm not familiar with scala so I'll give you some pseudo code, I believe you'll be able to easily translate it.
nextIntervals(zdt) {
timestamp = zdt.toUnixTimestamp();
return [
new ZonedDateTime(timestamp + (60 - timestamp % 60)),
new ZonedDateTime(timestamp + (300 - timestamp % 300))
]
}
The above code assumes that ZonedDateTime can be instantiated by giving it a unix timestamp, measured in seconds. And also that it can be converted to a unix timestamp.
The idea is pretty simple: the remainder of the modulus will be the time that has elapsed since the last required period (in your case 1 minute or 5 minutes). Take that away from the period itself and you have the time that's left until the next period. Add that to the current time and you have the exact datetime.
Edit:
Here's a working javascript example
function nextIntervals(date) {
let t = date.getTime();
return [
60e3,
300e3,
].map(i => new Date(t + i - t % i));
}
console.log(nextIntervals(new Date));
You can use the following functions to meet your requirements:
ZonedDateTime#plusMinutes
ZonedDateTime#minusMinutes
ZonedDateTime#truncatedTo
Demo:
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String[] args) {
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"));
ZonedDateTime nextMinute = now.plusMinutes(1).truncatedTo(ChronoUnit.MINUTES);
ZonedDateTime nextMultipleOfFiveMin = now.truncatedTo(ChronoUnit.MINUTES)
.minusMinutes(now.getMinute() % 5)
.plusMinutes(5);
System.out.println(now);
System.out.println(nextMinute);
System.out.println(nextMultipleOfFiveMin);
}
}
Output from a sample run:
2021-10-25T16:59:22.662943-04:00[America/New_York]
2021-10-25T17:00-04:00[America/New_York]
2021-10-25T17:00-04:00[America/New_York]
Output from another sample run after a while:
2021-10-25T17:05:09.596952-04:00[America/New_York]
2021-10-25T17:06-04:00[America/New_York]
2021-10-25T17:10-04:00[America/New_York]
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time. Check this answer and this answer to learn how to use java.time API with JDBC.
Note: The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time.
We do need a little bit of hand-coded math to handle the 5-minute interval case. Excuse my Java syntax.
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println("Now: " + now);
// Truncate to the previous 5 minutes
ZonedDateTime zdt = now.truncatedTo(ChronoUnit.MINUTES);
zdt = zdt.withMinute(zdt.getMinute() / 5 * 5);
for (int i = 0; i <= 12; i++) {
zdt = zdt.plusMinutes(5);
System.out.println(zdt);
}
Example output:
Now: 2021-10-25T15:23:31.357567-04:00[America/New_York]
2021-10-25T15:25-04:00[America/New_York]
2021-10-25T15:30-04:00[America/New_York]
2021-10-25T15:35-04:00[America/New_York]
2021-10-25T15:40-04:00[America/New_York]
2021-10-25T15:45-04:00[America/New_York]
2021-10-25T15:50-04:00[America/New_York]
2021-10-25T15:55-04:00[America/New_York]
2021-10-25T16:00-04:00[America/New_York]
2021-10-25T16:05-04:00[America/New_York]
2021-10-25T16:10-04:00[America/New_York]
2021-10-25T16:15-04:00[America/New_York]
2021-10-25T16:20-04:00[America/New_York]
2021-10-25T16:25-04:00[America/New_York]
The trick to truncate to a whole multiple of 5 minutes is to divide by 5, obtain a whole number and discard any remainder, and multiply by 5 again.
The 1-minute interval is similar, only a bit simpler: we don’t need to do any math ourselves, java.time takes care of it all.

Gnuplot - start date and time + incremented minutes

I have a question about Gnuplot - my measurement device records the start date and time (ex. 15.09.2020 15:09:00 format can be changed), every measurement is done after every 60 minutes. I do not know the ending time. How should I do the x-axis, so that axis tics are "day.month" ?
Keep in mind, in gnuplot time and date is handled as seconds from January, 1st 1970 00:00:00.
In gnuplot console check help strptime, help format. Try the following:
Code:
### convert relative time into absolute time
reset session
$Data <<EOD
minutes;temperature
0;12.8829
60;4.5346
120;4.5417
180;4.5454
240;4.5394
1440;2.22
2880;1.11
10000;0.00
EOD
set datafile separator ";"
Startdate = strptime("%d.%m.%Y %H:%M:%S","15.09.2020 15:09:00")
myTime(col) = Startdate + column(col)*60
set format x "%d.%m." timedate
plot $Data u (myTime(1)):2 w lp pt 7
### end of code
Result:
I know, that temperature logger started:
15.09.2020 15:09:00
The datafile.csv contains:
minutes;temperature
0;12.8829
60;4.5346
120;4.5417
180;4.5454
240;4.5394

Spark sliding window is not triggering when there is no data from the data stream

I have a simple spark sql with time window of 5 minutes, trigger policy of every minute:
val withTime = eventStreams(0).selectExpr("*", "cast(cast(parsed.time as long)/1000 as timestamp) as event_time")
val momentumDataAggQuery = withTime
.selectExpr("parsed.symbol", "parsed.bid", "parsed.ask", "event_time")
.withWatermark("event_time", "1 minutes")
.groupBy(col("symbol"), window(col("event_time"), "5 minutes", "60 seconds")) // change to 60 minutes
.agg(first("bid", true).as("first_bid"), first("ask").as("first_ask"), last("bid").as("last_bid"), last("ask").as("last_ask"))
val momentumDataQuery = momentumDataAggQuery
.selectExpr("window.start", "window.end", "ln(((last_bid + last_ask)/2)/((first_bid + first_ask)/2)) as momentum", "symbol")
When there is data from the stream, it gets triggered every minute to calculate 'momentum' but stop when there is not data point. I expect it will continue using old data to update every minute even there is not enough data point.
Consider the example in the following table
In the 1st window, there is only one data point so log return is zero.
In the 2nd window, there is only two data points so it takes log(97.5625/97.4625), where 97.5625 was received at 11:53 and 97.4625 was received at 11:52:10, within the time window 12:19 <> 12:54...it went on to calculate the log return when there was sufficient data point.
However, when there was NO more data point after 15:56:12, say, for the window 12:54 <> 12:59, i expect it would take ln(97.8625/97.6625) where the input were generated at 11:56:12 and 11:54:11 respectively. However it's not the case, the red box were never generated.
Is there something wrong with my spark sql?

Ruby: dealing with booleans: How to address not using military time for a clock Class

TDD
gem 'minitest', '~> 5.2'
require 'minitest/autorun'
require 'minitest/pride'
require_relative 'clock'
class ClockTest < Minitest::Test
def test_start_at_6
clock = Clock.new
assert_equal 6, clock.time
end
def test_passage_of_time
clock = Clock.new
clock.wait
assert_equal 7, clock.time
3.times { clock.wait }
assert_equal 10, clock.time
end
def test_clocks_are_not_military_time
clock = Clock.new
8.times { clock.wait }
assert_equal 2, clock.time
end
end
CODE
class Clock
attr_reader :time
def initialize
#time = 6
end
def wait(time = 1)
#time += time
end
def not_military_time
#time += (time - 10)
end
end
Can anyone guide me into figuring out how to address that the clocks are not in military time? It's coming as Expected : 2 , Actual : 14. I feel like there needs to be some of subtraction going in order to address the clock saying 2 instead of 14.
I know what I have in the code does not work, but am I on the right track?
If you look through all of the tests you'll see that apart from test_start_at_6 each test essentially calls wait some number of times and then checks for the right time in clock.time.
If you look at your code, clock.time is generated by attr_reader and so all it will ever do is return the current value of #time. So this leaves you with wait as a place to implement the behaviour needed to make the tests pass.
One other thing to notice is that you're currently overcomplicating the wait method. It's never called with any parameters and so the time parameter isn't needed. So to start simplify that to just:
def wait
#time += 1
end
Next, step away from the code and make a little list showing for each current time what the next time needs to be after wait is called. You can then think about how to change wait so that it matches that required behaviour.
In terms of whether to use an if or a case statement, everything that you could achieve using a case statement can also be done with an if as an alternative. It's best to think about the most common use of a case statement which is for checking the same variable for various possible values. i.e. the case statement
case #time
when 1
puts "One o'clock"
when 2
puts "Two o'clock"
else
puts "Later!"
end
is the same as:
if #time == 1
puts "One o'clock"
elsif #time == 2
puts "Two o'clock"
else
puts "Later!"
end
Often when you're just working out what some logic needs to be you'll write it as an if statement and then once it's working realise that it can more elegantly be expressed as a case statement. In this exercise an if should be fine.

Cron timer testing with psuedo clock in Drools Fusion?

I am trying to test the firing of a rule based on a cron timer using the pseudo clock in Drools Fusion 5.5. I want the rule to fire everyday at 1am:
rule "CALCULATING DATE FOR NEXT DAY"
timer (cron:00 00 01 * * ?)
no-loop
when
$summary: FxSummary(sameDayCcyFlag == false)
then
BusinessDayUtil b = new BusinessDayUtil();
modify($summary) {
setSettlementDate(b);
}
end
I then do the following in my test case:
PseudoClockScheduler timeService = ( PseudoClockScheduler ) ksession.getSessionClock();
DateFormat df = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ" );
Date date = df.parse( "2014-01-16T01:00:00.000-0000" );
Summary sum = new Summary("YEN").setSameDayCcyFlag(false);
ksession.fireAllRules();
timeService.advanceTime( date.getTime(), TimeUnit.MILLISECONDS );
ksession.fireAllRules();
It doesn't seem to do anything...no indication that the timer fired or anything. I've also tried to insert a date at say 12:59:50 and advanced the clock 10sec. Also, fireUntilHalt to have the engine running, etc. Nothing seems to work. Am I using this correctly? Does the pseudo clock work with timers? Also, does it fire "missed" timers if I advance the clock past a timer that was supposed to fire?
Think about how cron can be implemented. The basic function is timer, and this works like ye olde kitchen's egg-timer: at one point in time you wind it up, and then it'll ring 4 or 5 minutes later. Thus, for the next cron ring of the bell, the Cook will have to look at the clock and calculate the interval to the indicated point in time.
You'll have to let the Cook look at the clock some time before the next 1:00am, say, around midnight. The code goes something like this, with advance() overloaded with Date and long to advance the pseudo-clock:
date = df.parse( "2014-01-15T00:00:00.000-0000" ); // Note: midnight
advance( date );
kSession.fireAllRules(); // (Ah, ring in one hour!)
advance( 1000*60*60 );
kSession.fireAllRules(); // Ring!
advance( 24*1000*60*60 );
kSession.fireAllRules(); // Ring!
The postman only rings twice ;-)