RxJava: Is there an Observable.cachedDefer() operator, or some equivalent? - reactive-programming

Is there a safe way to defer the creation of an Observable<T>, but upon creation cache it for a period of time before it must create it again?
Observable.cachedDefer(() -> createExpensiveFiniteObservable().cache(), 5, TimeUnit.MINUTES);
I have data sets that are expensive to construct and I want them cached long enough to support a process, but let them expire approximately between each run.

I've added the functionality to do this to rxjava-extras. The code below depends on rxjava-extras 0.6.8-RC2 or later (which is on Maven Central).
Run the main method below and you will see these results which seem to match the behaviour you desire (a reset of the cache whenever the time gap to next subscribe is >=5 seconds):
source emits Tue Oct 13 21:00:16 AEDT 2015
Tue Oct 13 21:00:16 AEDT 2015
Tue Oct 13 21:00:16 AEDT 2015
Tue Oct 13 21:00:16 AEDT 2015
Tue Oct 13 21:00:16 AEDT 2015
Tue Oct 13 21:00:16 AEDT 2015
source emits Tue Oct 13 21:00:31 AEDT 2015
Tue Oct 13 21:00:31 AEDT 2015
Tue Oct 13 21:00:31 AEDT 2015
Tue Oct 13 21:00:31 AEDT 2015
Tue Oct 13 21:00:31 AEDT 2015
Tue Oct 13 21:00:31 AEDT 2015
source emits Tue Oct 13 21:00:46 AEDT 2015
Tue Oct 13 21:00:46 AEDT 2015
Tue Oct 13 21:00:46 AEDT 2015
...
Main method:
public static void main(String[] args) throws InterruptedException {
Observable<Date> source = Observable
.defer(() ->
Observable
.just(new Date())
.doOnNext(
d -> System.out.println("source emits " + d)));
CloseableObservableWithReset<Date> cached =
Obs.cache(source, 5, TimeUnit.SECONDS, Schedulers.computation());
Observable<Date> o = cached
.observable()
.doOnSubscribe(() -> cached.reset());
for (int i = 0; i < 30; i++) {
o.doOnNext(System.out::println).subscribe();
Thread.sleep((i % 5 + 1)*1000);
}
cached.close();
}
Note that to reset the cache on every emission as well then where you see
.doOnSubscribe(() -> cached.reset())
put
.doOnSubscribe(() -> cached.reset())
.doOnNext(x -> cached.reset())

Related

How i can create a new EndTime with getEndTime()

i will manage my calender about a simply script which is moving calender items 60 minutes further.
For this feature is take this Google Apps Script:
function myFunction() {
var cal = CalendarApp.getCalendarById("myCalendar#gmail.com");
cal.createEvent("TTIITTEELL", new Date("02/06/2018 18:00:00"), new Date("02/06/2018 19:00:00"));
var events = cal.getEvents(new Date("02/05/2018"), new Date("02/07/2018"));
for (var i=0;i<events.length;i++) {
if (events[i].getTitle() == "TTIITTEELL") {
var t = events[i].getEndTime();
var text = new Date(events[i].getEndTime()+.........);
}
}
}
The script is running, but i donĀ“t find the logig to create a new Time.
When i take a "+" it is calculation a minus and so - here are some examples:
Take: +5 = from: Tue Feb 06 2018 19:00:00 GMT+0100 (MEZ) --> to: Tue Feb 06 2018 18:55:00 GMT+0100 (MEZ)
Take: -5 = from: Tue Feb 06 2018 19:00:00 GMT+0100 (MEZ) --> to: Tue Feb 06 2018 18:59:59 GMT+0100 (MEZ)
Take: +60 = from: Tue Feb 06 2018 19:00:00 GMT+0100 (MEZ) --> to: Invalid Date
Take: -60*60*24*1000*1000 = from: Tue Feb 06 2018 19:00:00 GMT+0100 (MEZ) --> to: Wed May 13 2015 20:00:00 GMT+0200 (MESZ)
Take: +60*60*24*1000*1000 = from: Tue Feb 06 2018 19:00:00 GMT+0100 (MEZ) --> to: Invalid Date
Where is my mistake?
How about this answer? In your script, events[i].getEndTime() is an object for date. So when the number is added to the object, it dosn't become the result what you want. When you want the addition and subtraction, you can use the following script. Please modify as follows.
From :
var t = events[i].getEndTime();
var text = new Date(events[i].getEndTime()+.........);
To :
In this case, as a sample, I set the unit of +5, -5, +60, -60 to "minutes".
var num = 5; // Please input 5, -5, 60, -60, ...
var t = events[i].getEndTime().getTime();
var text = new Date(t + num * 60 * 1000);
If I misunderstand your question, I'm sorry.

How to find scala java.util.Date difference in minutes?

scala> val dates = filtering1.map(x => (format.parse(x._1),format.parse(x._2)))
dates: org.apache.spark.rdd.RDD[(java.util.Date, java.util.Date)] = MapPartitionsRDD[7] at map at <console>:34
stores below values
scala> dates.collect
res0: Array[(java.util.Date, java.util.Date)] = Array((Sat Jun 30 23:42:00 IST 2018,Thu Jul 04 15:10:00 IST 2019), (Sat Jun 30 23:37:00 IST 2018,Sun Jul 01 14:44:00 IST 2018), (Sat Jun 30 23:13:00 IST 2018,Sun Feb 28 23:34:00 IST 219), (Sat Jun 30 22:58:00 IST 2018,Mon Jul 01 18:22:00 IST 2019), (Sat Jun 30 22:36:00 IST 2018,Mon Jul 01 16:01:00 IST 2019), (Sat Jun 30 21:53:00 IST 2018,Tue Jul 02 10:36:00 IST 2019), (Sat Jun 30 21:42:00 IST 2018,Sun Jun 30 23:25:00 IST 2019), (Sat Jun 30 21:36:00 IST 2018,Mon Jul 01 16:47:00 IST 2019), (Sat Jun 30 21:16:00 IST 2018,Mon Jul 01 18:18:00 IST 2019), (Sat Jun 30 21:10:00 IST 2018,Thu Jul 04 12:25:00 IST 2019), (Sat Jun 30 21:02:00 IST 2018,Sat Dec 01 17:29:00 IST 2018), (Sat Jun 30 20:54:00 IST 2018,Mon Jul 01 15:51:00 IST 2019), (Sat Jun 30 ...
But how to perform operation so the difference in dates, is grouped together, gives value in minutes.
I have command , it does not give me desired output, what changes should be made?
val time_diff = dates.map(x => (x._2.getTime()-x._1.getTime())/(60*1000)%60)
what is (60*1000)%60) values represent?
getTime gives milliseconds, so dividing by 1000.0 gives seconds and dividing by 1000.0*60 gives minutes. Be aware that dividing a Long by an Int gives you another Long, so you are truncating the resulting minutes to the next lowest integer. Adding modulus 60, % 60, simply wraps the minutes to 0-59, so if you had a 90 minutes difference, that would be 1 hour 30 minutes, and the result of your calculation would just be 30.
val t = System.currentTimeMillis
val x = new java.util.Date(t)
val y = new java.util.Date(t + 10000) // ten seconds later
(y.getTime - x.getTime) / (1000.0 * 60) // 0.167
(y.getTime - x.getTime) / (1000 * 60) // 0 !
First problem when you subtract two times, time might go negative.
Second, getTime returns value in miliseconds.
1000ms = 1 second
So, first there is need to divide it by 1000 to get time in seconds. To get in minutes,divide it again by 60.
Since you require result in minutes.
val time_diff = dates.map(x => (x._2.getTime()-x._1.getTime())/(60*1000))

freeradius daloradius authentication failure

i followed this tutorial to install freeradius and dalo radius for the raspberry pi:
http://www.binaryheartbeat.net/2013/12/raspberry-pi-based-freeradius-server.html
i tested the file authentication and it worked fine but after installing daloradius and switching to MySQL authnetications fail for unknown reasons
here is freeradius output that occurs when trying to authenticate a user:
rad_recv: Access-Request packet from host 192.168.1.1 port 32779, id=216, length=172
User-Name = "ccc"
State = 0xf9775519ff7f4c9188c14494359a170f
EAP-Message = 0x0208005b190017030100500d2898ca35aa9fa9e4febd8816c9e6deda71960fe5692b7c3d0499f2b5bba6b531483e373e14f8aff517aa081e214edc98e2c8bb22d16a961ecff4f498d20d152535b4d11ace1484b985bd2501ade77b
Service-Type = Framed-User
Framed-MTU = 1420
NAS-IP-Address = 192.168.1.1
Message-Authenticator = 0x49fc781b8a152fbec467b2c1f275a1a1
Tue Dec 29 18:38:47 2015 : Info: # Executing section authorize from file /etc/freeradius/sites-enabled/default
Tue Dec 29 18:38:47 2015 : Info: +group authorize {
Tue Dec 29 18:38:47 2015 : Info: ++[preprocess] = ok
Tue Dec 29 18:38:47 2015 : Info: ++[chap] = noop
Tue Dec 29 18:38:47 2015 : Info: ++[mschap] = noop
Tue Dec 29 18:38:47 2015 : Info: ++[digest] = noop
Tue Dec 29 18:38:47 2015 : Info: [suffix] No '#' in User-Name = "ccc", looking up realm NULL
Tue Dec 29 18:38:47 2015 : Info: [suffix] No such realm "NULL"
Tue Dec 29 18:38:47 2015 : Info: ++[suffix] = noop
Tue Dec 29 18:38:47 2015 : Info: [eap] EAP packet type response id 8 length 91
Tue Dec 29 18:38:47 2015 : Info: [eap] Continuing tunnel setup.
Tue Dec 29 18:38:47 2015 : Info: ++[eap] = ok
Tue Dec 29 18:38:47 2015 : Info: +} # group authorize = ok
Tue Dec 29 18:38:47 2015 : Info: Found Auth-Type = EAP
Tue Dec 29 18:38:47 2015 : Info: # Executing group from file /etc/freeradius/sites-enabled/default
Tue Dec 29 18:38:47 2015 : Info: +group authenticate {
Tue Dec 29 18:38:47 2015 : Info: [eap] Request found, released from the list
Tue Dec 29 18:38:47 2015 : Info: [eap] EAP/peap
Tue Dec 29 18:38:47 2015 : Info: [eap] processing type peap
Tue Dec 29 18:38:47 2015 : Info: [peap] processing EAP-TLS
Tue Dec 29 18:38:47 2015 : Info: [peap] eaptls_verify returned 7
Tue Dec 29 18:38:47 2015 : Info: [peap] Done initial handshake
Tue Dec 29 18:38:47 2015 : Info: [peap] eaptls_process returned 7
Tue Dec 29 18:38:47 2015 : Info: [peap] EAPTLS_OK
Tue Dec 29 18:38:47 2015 : Info: [peap] Session established. Decoding tunneled attributes.
Tue Dec 29 18:38:47 2015 : Info: [peap] Peap state phase2
Tue Dec 29 18:38:47 2015 : Info: [peap] EAP type mschapv2
Tue Dec 29 18:38:47 2015 : Info: [peap] Got tunneled request
EAP-Message = 0x0208003e1a0208003931461c2f1334a4b7bab38912e9d82dd97b000000000000000070fb7810a938a00d884f17dc01b62eaa7dde9fbb7ab2cf4200636363
server {
Tue Dec 29 18:38:47 2015 : Info: [peap] Setting User-Name to ccc
Sending tunneled request
EAP-Message = 0x0208003e1a0208003931461c2f1334a4b7bab38912e9d82dd97b000000000000000070fb7810a938a00d884f17dc01b62eaa7dde9fbb7ab2cf4200636363
FreeRADIUS-Proxied-To = 127.0.0.1
User-Name = "ccc"
State = 0x4bb6eef44bbef48a7072f4e023895561
server inner-tunnel {
Tue Dec 29 18:38:47 2015 : Info: # Executing section authorize from file /etc/freeradius/sites-enabled/inner-tunnel
Tue Dec 29 18:38:47 2015 : Info: +group authorize {
Tue Dec 29 18:38:47 2015 : Info: ++[chap] = noop
Tue Dec 29 18:38:47 2015 : Info: ++[mschap] = noop
Tue Dec 29 18:38:47 2015 : Info: [suffix] No '#' in User-Name = "ccc", looking up realm NULL
Tue Dec 29 18:38:47 2015 : Info: [suffix] No such realm "NULL"
Tue Dec 29 18:38:47 2015 : Info: ++[suffix] = noop
Tue Dec 29 18:38:47 2015 : Info: ++update control {
Tue Dec 29 18:38:47 2015 : Info: ++} # update control = noop
Tue Dec 29 18:38:47 2015 : Info: [eap] EAP packet type response id 8 length 62
Tue Dec 29 18:38:47 2015 : Info: [eap] No EAP Start, assuming it's an on-going EAP conversation
Tue Dec 29 18:38:47 2015 : Info: ++[eap] = updated
Tue Dec 29 18:38:47 2015 : Info: ++[files] = noop
Tue Dec 29 18:38:47 2015 : Info: ++[expiration] = noop
Tue Dec 29 18:38:47 2015 : Info: ++[logintime] = noop
Tue Dec 29 18:38:47 2015 : Info: ++[pap] = noop
Tue Dec 29 18:38:47 2015 : Info: +} # group authorize = updated
Tue Dec 29 18:38:47 2015 : Info: Found Auth-Type = EAP
Tue Dec 29 18:38:47 2015 : Info: # Executing group from file /etc/freeradius/sites-enabled/inner-tunnel
Tue Dec 29 18:38:47 2015 : Info: +group authenticate {
Tue Dec 29 18:38:47 2015 : Info: [eap] Request found, released from the list
Tue Dec 29 18:38:47 2015 : Info: [eap] EAP/mschapv2
Tue Dec 29 18:38:47 2015 : Info: [eap] processing type mschapv2
Tue Dec 29 18:38:47 2015 : Info: [mschapv2] # Executing group from file /etc/freeradius/sites-enabled/inner-tunnel
Tue Dec 29 18:38:47 2015 : Info: [mschapv2] +group MS-CHAP {
Tue Dec 29 18:38:47 2015 : Info: [mschap] No Cleartext-Password configured. Cannot create LM-Password.
Tue Dec 29 18:38:47 2015 : Info: [mschap] No Cleartext-Password configured. Cannot create NT-Password.
Tue Dec 29 18:38:47 2015 : Info: [mschap] Creating challenge hash with username: ccc
Tue Dec 29 18:38:47 2015 : Info: [mschap] Client is using MS-CHAPv2 for ccc, we need NT-Password
Tue Dec 29 18:38:47 2015 : Info: [mschap] FAILED: No NT/LM-Password. Cannot perform authentication.
Tue Dec 29 18:38:47 2015 : Info: [mschap] FAILED: MS-CHAP2-Response is incorrect
Tue Dec 29 18:38:47 2015 : Info: ++[mschap] = reject
Tue Dec 29 18:38:47 2015 : Info: +} # group MS-CHAP = reject
Tue Dec 29 18:38:47 2015 : Info: [eap] Freeing handler
Tue Dec 29 18:38:47 2015 : Info: ++[eap] = reject
Tue Dec 29 18:38:47 2015 : Info: +} # group authenticate = reject
Tue Dec 29 18:38:47 2015 : Info: Failed to authenticate the user.
Tue Dec 29 18:38:47 2015 : Info: Using Post-Auth-Type REJECT
Tue Dec 29 18:38:47 2015 : Info: # Executing group from file /etc/freeradius/sites-enabled/inner-tunnel
Tue Dec 29 18:38:47 2015 : Info: +group REJECT {
Tue Dec 29 18:38:47 2015 : Info: [attr_filter.access_reject] expand: %{User-Name} -> ccc
Tue Dec 29 18:38:47 2015 : Debug: attr_filter: Matched entry DEFAULT at line 11
Tue Dec 29 18:38:47 2015 : Info: ++[attr_filter.access_reject] = updated
Tue Dec 29 18:38:47 2015 : Info: +} # group REJECT = updated
} # server inner-tunnel
Tue Dec 29 18:38:47 2015 : Info: [peap] Got tunneled reply code 3
MS-CHAP-Error = "\010E=691 R=1"
EAP-Message = 0x04080004
Message-Authenticator = 0x00000000000000000000000000000000
Tue Dec 29 18:38:47 2015 : Info: [peap] Got tunneled reply RADIUS code 3
MS-CHAP-Error = "\010E=691 R=1"
EAP-Message = 0x04080004
Message-Authenticator = 0x00000000000000000000000000000000
Tue Dec 29 18:38:47 2015 : Info: [peap] Tunneled authentication was rejected.
Tue Dec 29 18:38:47 2015 : Info: [peap] FAILURE
Tue Dec 29 18:38:47 2015 : Info: ++[eap] = handled
Tue Dec 29 18:38:47 2015 : Info: +} # group authenticate = handled
Sending Access-Challenge of id 216 to 192.168.1.1 port 32779
EAP-Message = 0x0109002b190017030100205991bfd8f9e7f70794477d653c848e8b443626b3b935a5b3f049ac7af1534d3e
Message-Authenticator = 0x00000000000000000000000000000000
State = 0xf9775519fe7e4c9188c14494359a170f
Tue Dec 29 18:38:47 2015 : Info: Finished request 7.
Tue Dec 29 18:38:47 2015 : Debug: Going to the next request
Tue Dec 29 18:38:47 2015 : Debug: Waking up in 0.4 seconds.
rad_recv: Access-Request packet from host 192.168.1.1 port 32779, id=217, length=124
User-Name = "ccc"
State = 0xf9775519fe7e4c9188c14494359a170f
EAP-Message = 0x0209002b190017030100202a7f1a72de2970b689e44c005661d1e1e444854af7499ebeb23eabc7bfad7b64
Service-Type = Framed-User
Framed-MTU = 1420
NAS-IP-Address = 192.168.1.1
Message-Authenticator = 0xc9b0d8e268df2d8e4b484725c3efa189
Tue Dec 29 18:38:47 2015 : Info: # Executing section authorize from file /etc/freeradius/sites-enabled/default
Tue Dec 29 18:38:47 2015 : Info: +group authorize {
Tue Dec 29 18:38:47 2015 : Info: ++[preprocess] = ok
Tue Dec 29 18:38:47 2015 : Info: ++[chap] = noop
Tue Dec 29 18:38:47 2015 : Info: ++[mschap] = noop
Tue Dec 29 18:38:47 2015 : Info: ++[digest] = noop
Tue Dec 29 18:38:47 2015 : Info: [suffix] No '#' in User-Name = "ccc", looking up realm NULL
Tue Dec 29 18:38:47 2015 : Info: [suffix] No such realm "NULL"
Tue Dec 29 18:38:47 2015 : Info: ++[suffix] = noop
Tue Dec 29 18:38:47 2015 : Info: [eap] EAP packet type response id 9 length 43
Tue Dec 29 18:38:47 2015 : Info: [eap] Continuing tunnel setup.
Tue Dec 29 18:38:47 2015 : Info: ++[eap] = ok
Tue Dec 29 18:38:47 2015 : Info: +} # group authorize = ok
Tue Dec 29 18:38:47 2015 : Info: Found Auth-Type = EAP
Tue Dec 29 18:38:47 2015 : Info: # Executing group from file /etc/freeradius/sites-enabled/default
Tue Dec 29 18:38:47 2015 : Info: +group authenticate {
Tue Dec 29 18:38:47 2015 : Info: [eap] Request found, released from the list
Tue Dec 29 18:38:47 2015 : Info: [eap] EAP/peap
Tue Dec 29 18:38:47 2015 : Info: [eap] processing type peap
Tue Dec 29 18:38:47 2015 : Info: [peap] processing EAP-TLS
Tue Dec 29 18:38:47 2015 : Info: [peap] eaptls_verify returned 7
Tue Dec 29 18:38:47 2015 : Info: [peap] Done initial handshake
Tue Dec 29 18:38:47 2015 : Info: [peap] eaptls_process returned 7
Tue Dec 29 18:38:47 2015 : Info: [peap] EAPTLS_OK
Tue Dec 29 18:38:47 2015 : Info: [peap] Session established. Decoding tunneled attributes.
Tue Dec 29 18:38:47 2015 : Info: [peap] Peap state send tlv failure
Tue Dec 29 18:38:47 2015 : Info: [peap] Received EAP-TLV response.
Tue Dec 29 18:38:47 2015 : Info: [peap] The users session was previously rejected: returning reject (again.)
Tue Dec 29 18:38:47 2015 : Info: [peap] *** This means you need to read the PREVIOUS messages in the debug output
Tue Dec 29 18:38:47 2015 : Info: [peap] *** to find out the reason why the user was rejected.
Tue Dec 29 18:38:47 2015 : Info: [peap] *** Look for "reject" or "fail". Those earlier messages will tell you.
Tue Dec 29 18:38:47 2015 : Info: [peap] *** what went wrong, and how to fix the problem.
Tue Dec 29 18:38:47 2015 : Info: [eap] Handler failed in EAP/peap
Tue Dec 29 18:38:47 2015 : Info: [eap] Failed in EAP select
Tue Dec 29 18:38:47 2015 : Info: ++[eap] = invalid
Tue Dec 29 18:38:47 2015 : Info: +} # group authenticate = invalid
Tue Dec 29 18:38:47 2015 : Info: Failed to authenticate the user.
Tue Dec 29 18:38:47 2015 : Info: Using Post-Auth-Type REJECT
Tue Dec 29 18:38:47 2015 : Info: # Executing group from file /etc/freeradius/sites-enabled/default
Tue Dec 29 18:38:47 2015 : Info: +group REJECT {
Tue Dec 29 18:38:47 2015 : Info: [sql] expand: %{User-Name} -> ccc
Tue Dec 29 18:38:47 2015 : Info: [sql] sql_set_user escaped user --> 'ccc'
Tue Dec 29 18:38:47 2015 : Info: [sql] expand: %{User-Password} ->
Tue Dec 29 18:38:47 2015 : Info: [sql] ... expanding second conditional
Tue Dec 29 18:38:47 2015 : Info: [sql] expand: %{Chap-Password} ->
Tue Dec 29 18:38:47 2015 : Info: [sql] expand: INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( '%{User-Name}', '%{%{User-Password}:-%{Chap-Password}}', '%{reply:Packet-Type}', '%S') -> INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( 'ccc', '', 'Access-Reject', '2015-12-29 18:38:47')
Tue Dec 29 18:38:47 2015 : Debug: rlm_sql (sql) in sql_postauth: query is INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( 'ccc', '', 'Access-Reject', '2015-12-29 18:38:47')
Tue Dec 29 18:38:47 2015 : Debug: rlm_sql (sql): Reserving sql socket id: 29
Tue Dec 29 18:38:47 2015 : Debug: rlm_sql (sql): Released sql socket id: 29
Tue Dec 29 18:38:47 2015 : Info: ++[sql] = ok
Tue Dec 29 18:38:47 2015 : Info: [attr_filter.access_reject] expand: %{User-Name} -> ccc
Tue Dec 29 18:38:47 2015 : Debug: attr_filter: Matched entry DEFAULT at line 11
Tue Dec 29 18:38:47 2015 : Info: ++[attr_filter.access_reject] = updated
Tue Dec 29 18:38:47 2015 : Info: +} # group REJECT = updated
Tue Dec 29 18:38:47 2015 : Info: Delaying reject of request 8 for 1 seconds
Tue Dec 29 18:38:47 2015 : Debug: Going to the next request
Tue Dec 29 18:38:47 2015 : Debug: Waking up in 0.1 seconds.
Tue Dec 29 18:38:47 2015 : Info: Cleaning up request 0 ID 209 with timestamp +11
Tue Dec 29 18:38:47 2015 : Debug: Waking up in 0.3 seconds.
Tue Dec 29 18:38:47 2015 : Info: Cleaning up request 1 ID 210 with timestamp +11
Tue Dec 29 18:38:47 2015 : Debug: Waking up in 0.3 seconds.
Tue Dec 29 18:38:48 2015 : Info: Cleaning up request 2 ID 211 with timestamp +12
Tue Dec 29 18:38:48 2015 : Debug: Waking up in 0.1 seconds.
Tue Dec 29 18:38:48 2015 : Info: Sending delayed reject for request 8
Sending Access-Reject of id 217 to 192.168.1.1 port 32779
EAP-Message = 0x04090004
Message-Authenticator = 0x00000000000000000000000000000000
Found the solution,
the problem was that i didn't configure the /etc/raddb/sites-available/inner-tunnel file to use sql

First program in bash pipeline is blocking

I'm trying to pipe several perl programs together, and from everything I've read, piped programs are supposed to all open and run in parallel. That doesn't appear to be the case with whatever it is that I did. Here is the simplified version:
./video
#!/usr/bin/env perl
my $i = 0;
while($i<10){
my $time = localtime(time);
print "VID: $time $i\n";
sleep 1;
$i++;
}
./controller
#!/usr/bin/env perl
while(my $line = <STDIN>){
my $time = localtime(time);
print "CTRL: $time $line";
}
./pipes
#!/usr/bin/env perl
open(my $controller, "|./controller") || die "Can't fork: $!";
open(STDOUT, ">&", $controller);
open(my $video, "|./video") || die "Can't fork: $!";
print STDERR "All processes started\n";
I tried executing it two ways, but both resulted in the same output:
<16:34:21> rswhiting#Minas-Tirith:~/code/Pipes $ ./pipes
All processes started
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:22 2014 0
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:23 2014 1
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:24 2014 2
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:25 2014 3
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:26 2014 4
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:27 2014 5
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:28 2014 6
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:29 2014 7
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:30 2014 8
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:31 2014 9
<16:34:49> rob#Minas-Tirith:~/code/Pipes $ ./video | ./controller
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:15 2014 0
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:16 2014 1
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:17 2014 2
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:18 2014 3
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:19 2014 4
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:20 2014 5
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:21 2014 6
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:22 2014 7
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:23 2014 8
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:24 2014 9
<16:35:25> rob#Minas-Tirith:~/code/Pipes $
The timestamps from the video program increment as they should, but the time that the control program receives them is identical (after the video program has ended). How do I make the controller receive the data as it is produced instead of after the fact?
It's because of STDOUT buffering in the video program. print is line-buffered only if it goes to an interactive terminal. Otherwise it uses a much bigger buffer, and the accumulated output is emitted in one big chunk when video exits. Try flushing after each print or use autoflush.
$| = 1; # Enables autoflush
By the way I don't get why you open a pipe TO video, it does not read anything. It should be
system "./video";
If you have a program that you can't modify but does not autoflush, you are in trouble. Except, you're not. You can use a pseudoterminal instead of a pipe. I've never done it. But chapter 64 of the book "The UXIX Programming Interface" is about pseudoterminals.

How to get first day of last month with Perl

So I would like to use function localtime(), but I'm having problems with getting first and last day of last month properly. Right now I have working functionality, but I bet there is a better way to solve this.
use Time::Piece;
use Time::Seconds;
$start_of_month = localtime();
while($start_of_month->mday < 10) {
$start_of_month += ONE_DAY;
}
$start_of_month -= ONE_MONTH; # Subtract one month to get previous month. "ONE_MONTH" is defined by Time::Seconds
$end_of_month = $start_of_month; # Copy start_of_month to end_of_month as they both have same year and month.
# Subtract day from $start_of_month until mday is the first day of the month.
while($start_of_month->mday != 1) {
$start_of_month -= ONE_DAY;
}
# Silly workaround to bring $end_of_month to last day of the month as Time::Piece object does not have good way to change mday.
while($end_of_month->mday != $start_of_month->month_last_day) {
$end_of_month += ONE_DAY;
}
$period_start = $start_of_month->dmy("."); # End result has to be same!
Can anyone give me a better way of handling this?
Don't rely on Time::Piece and constants in Time::Seconds for date manipulation
The following was my suggested simplification of the OP's date manipulation using Time::Piece and Time::Seconds. IF this worked on overloaded operators, it might actually work as intended, but as ikegami pointed out, this isn't guaranteed. So I tested below.
If you want to go the math route, at least you could simplify things a little:
use strict;
use warnings;
use Time::Piece;
use Time::Seconds;
my $date_start = localtime();
$date_start -= ONE_MONTH;
$date_start -= ($date_start->mday - 1) * ONE_DAY;
my $date_end = $date_start + ($date_start->month_last_day - 1) * ONE_DAY;
print $date_start , "\n"; # Prints Mar 1st (at least today it does)
print $date_end , "\n"; # Prints Mar 31st
I'd consider using a different module for this, like Date::Calc or DateTime, but this might work for your purposes.
Testing the above solution - many failures
I created a script the below script that loops through every date for a year starting at January 15th, showing every range where the above code does not work as expected.
use strict;
use warnings;
use Time::Piece;
use Time::Seconds;
my $t = 1389812400; # Wed 2014-Jan-15 7pm GMT. 11am PST
my $t_max = 1421348400; # Thu 2015-Jan-15 7pm GMT. 11am PST
my %prev_month = map {$_ => ($_ - 1) || 12} (1..12);
my $fail = '';
while ($t <= $t_max) {
$t += 60; # Increment by 1 minute
# Testing potentially overloaded math of Time::Piece & Time::Seconds
my $start = my $src = localtime($t);
$start -= ONE_MONTH;
$start -= ($start->mday - 1) * ONE_DAY;
if ($start->mon != $prev_month{$src->mon}) {
print "From ($t) $src -> $start\n" if !$fail;
$fail = " To ($t) $src -> $start\n\n";
} elsif ($fail) {
print $fail;
$fail = '';
}
}
The below is the output of this script with comments inserted to explain why each range fails:
# ONE_MONTH is exactly 2_629_744 seconds, or 30.437 days.
# ONE_MONTH is too short for January
From (1391193000) Fri Jan 31 10:30:00 2014 -> Wed Jan 1 00:00:56 2014
To (1391241540) Fri Jan 31 23:59:00 2014 -> Wed Jan 1 13:29:56 2014
# ONE_MONTH is too long for February
From (1393660800) Sat Mar 1 00:00:00 2014 -> Wed Jan 1 13:30:56 2014
To (1393871340) Mon Mar 3 10:29:00 2014 -> Wed Jan 1 23:59:56 2014
# ONE_MONTH is too short for March
From (1396290600) Mon Mar 31 11:30:00 2014 -> Sat Mar 1 00:00:56 2014
To (1396335540) Mon Mar 31 23:59:00 2014 -> Sat Mar 1 12:29:56 2014
# ONE_DAY is 86_400 seconds, or 24 hours.
# March 9th is only 23 hours long due to DST, ONE_DAY goes to far.
From (1397064600) Wed Apr 9 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397068140) Wed Apr 9 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397151000) Thu Apr 10 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397154540) Thu Apr 10 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397237400) Fri Apr 11 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397240940) Fri Apr 11 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397323800) Sat Apr 12 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397327340) Sat Apr 12 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397410200) Sun Apr 13 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397413740) Sun Apr 13 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397496600) Mon Apr 14 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397500140) Mon Apr 14 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397583000) Tue Apr 15 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397586540) Tue Apr 15 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397669400) Wed Apr 16 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397672940) Wed Apr 16 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397755800) Thu Apr 17 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397759340) Thu Apr 17 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397842200) Fri Apr 18 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397845740) Fri Apr 18 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397928600) Sat Apr 19 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397932140) Sat Apr 19 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398015000) Sun Apr 20 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398018540) Sun Apr 20 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398101400) Mon Apr 21 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398104940) Mon Apr 21 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398187800) Tue Apr 22 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398191340) Tue Apr 22 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398274200) Wed Apr 23 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398277740) Wed Apr 23 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398360600) Thu Apr 24 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398364140) Thu Apr 24 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398447000) Fri Apr 25 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398450540) Fri Apr 25 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398533400) Sat Apr 26 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398536940) Sat Apr 26 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398619800) Sun Apr 27 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398623340) Sun Apr 27 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398706200) Mon Apr 28 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398709740) Mon Apr 28 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398792600) Tue Apr 29 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398796140) Tue Apr 29 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398879000) Wed Apr 30 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398882540) Wed Apr 30 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
# ONE_MONTH is too long for April
From (1398927600) Thu May 1 00:00:00 2014 -> Sat Mar 1 12:30:56 2014
To (1398965340) Thu May 1 10:29:00 2014 -> Sat Mar 1 22:59:56 2014
# ONE_MONTH is too short for May
From (1401557400) Sat May 31 10:30:00 2014 -> Thu May 1 00:00:56 2014
To (1401605940) Sat May 31 23:59:00 2014 -> Thu May 1 13:29:56 2014
# ONE_MONTH is too long for June
From (1404198000) Tue Jul 1 00:00:00 2014 -> Thu May 1 13:30:56 2014
To (1404235740) Tue Jul 1 10:29:00 2014 -> Thu May 1 23:59:56 2014
# ONE_MONTH is too short for July
From (1406827800) Thu Jul 31 10:30:00 2014 -> Tue Jul 1 00:00:56 2014
To (1406876340) Thu Jul 31 23:59:00 2014 -> Tue Jul 1 13:29:56 2014
# ONE_MONTH is too short for August
From (1409506200) Sun Aug 31 10:30:00 2014 -> Fri Aug 1 00:00:56 2014
To (1409554740) Sun Aug 31 23:59:00 2014 -> Fri Aug 1 13:29:56 2014
# ONE_MONTH is too long for September
From (1412146800) Wed Oct 1 00:00:00 2014 -> Fri Aug 1 13:30:56 2014
To (1412184540) Wed Oct 1 10:29:00 2014 -> Fri Aug 1 23:59:56 2014
# ONE_MONTH is too short for October
From (1414776600) Fri Oct 31 10:30:00 2014 -> Wed Oct 1 00:00:56 2014
To (1414825140) Fri Oct 31 23:59:00 2014 -> Wed Oct 1 13:29:56 2014
# ONE_MONTH is too long for November
From (1417420800) Mon Dec 1 00:00:00 2014 -> Wed Oct 1 14:30:56 2014
To (1417454940) Mon Dec 1 09:29:00 2014 -> Wed Oct 1 23:59:56 2014
# ONE_MONTH is too short for December
From (1420050600) Wed Dec 31 10:30:00 2014 -> Mon Dec 1 00:00:56 2014
To (1420099140) Wed Dec 31 23:59:00 2014 -> Mon Dec 1 13:29:56 2014
Alternative using Time::Piece->add_months? Nope
Time::Piece has two functions, add_months and add_years intended for date calculations. Unfortunately, the documentation states:
Note that there is some "strange" behaviour when adding and subtracting months at the ends of months. Generally when the resulting month is shorter than the starting month then the number of overlap days is added. For example subtracting a month from 2008-03-31 will not result in 2008-02-31 as this is an impossible date. Instead you will get 2008-03-02. This appears to be consistent with other date manipulation tools.
The below code fully demonstrates this behavior for the timezone PST.
use strict;
use warnings;
use Time::Piece;
my $t = localtime(1420012800);
print $t->add_months($_),"\n" for (0..12)
Output:
Wed Dec 31 00:00:00 2014
Sat Jan 31 00:00:00 2015
Tue Mar 3 00:00:00 2015
Tue Mar 31 00:00:00 2015
Fri May 1 00:00:00 2015
Sun May 31 00:00:00 2015
Wed Jul 1 00:00:00 2015
Fri Jul 31 00:00:00 2015
Mon Aug 31 00:00:00 2015
Thu Oct 1 00:00:00 2015
Sat Oct 31 00:00:00 2015
Tue Dec 1 00:00:00 2015
Thu Dec 31 00:00:00 2015
Now, it is kind of nice how this function is able to accurately cycle back to the same date a year later, but there are lots of unfavorable months until then.
Conclusion
The constants in Time::Seconds are just that, constants. They are exact numbers of seconds meant to represent periods of time. There is no operator overloading to facilitate fancy date manipulation. Instead, these values are simply good for mathematical comparisons.
To manipulate specific dates, I'd advise using Date::Calc, DateTime, or any of the other modules suggested in this question.
A less OO, but alternate solution:
use POSIX qw(mktime);
my #now = localtime;
# mday = 1, month = month - 1
my $date_start = mktime(#now[0 .. 2], 1, $now[4] - 1, #now[5 .. 8]);
# mday = 0, the 0th day of this month == last day of prior month
my $date_end = mktime(#now[0 .. 2], 0, #now[4 .. 8]);
print scalar localtime $date_start, "\n";
print scalar localtime $date_end, "\n";
This hiccups with daylight saving time; if you don't care about time-of-day you could set $now[2] to 12 noon and hope no country declares night to be day and day to be night:
my #now = (0, 0, 12, (localtime)[3..8]);
I don't trust code that uses Time::Piece. It relies on overloading operators to make it look like you're doing it wrong ($time += ONE_DAY; looks like you're adding a constant) when you're actually doing it right. Maybe. It's hard to tell. You must have intimate knowledge of the guts of the module to know if you're doing it right.
DateTime solution:
my $dt = DateTime
->now( time_zone => 'local' )
->set_time_zone('floating') # Do this when you want to date arithmetic.
->truncate( to => 'day' );
$dt->set( day => 1 )->subtract( days => 1 );
my $last = $dt->ymd('-');
$dt->set( day => 1 );
my $first = $dt->ymd('-');
say "$first .. $last";
Using the Time::Seconds definition of ONE_MONTH gives you a solution that is wrong for several days a year. It is the average length of a month in seconds, and is equal to about 30.4 days. Subtracting that from 1 March, for instance, gives you a date in late January.
However the first day of the previous month can be calculated simply from the month and day fields returned by localtime. Converting this into a Time::Piece object lets us calculate the last day of the same month.
use strict;
use warnings;
use Time::Piece;
my ($m, $y) = (localtime)[4,5];
$y += 1900;
if ($m == 0) {
$m = 11;
$y -= 1;
}
my $period_start = sprintf '%02d.%02d.%04d', 1, $m, $y;
my $period_end = do {
my $tp = Time::Piece->strptime($period_start, '%d.%m.%Y');
sprintf '%02d.%02d.%04d', $tp->month_last_day, $m, $y;
};
print $period_start, "\n";
print $period_end, "\n";
output
01.03.2014
31.03.2014
Sorry if I did not understood property but: DaysInMonth (check coment)
my #monthDays= qw( 31 28 31 30 31 30 31 31 30 31 30 31 );
sub MonthDays {
my $month= shift(#_);
my $year= #_ ? shift(#_) : 1900+(localtime())[5];
if( $year <= 1752 ) {
# Note: Although September 1752 only had 19 days,
# they were numbered 1,2,14..30!
return 19 if 1752 == $year && 9 == $month;
return 29 if 2 == $month && 0 == $year % 4;
} else {
return 29 if 2 == $month and
0 == $year%4 && 0 != $year%100 || 0 == $year%400;
}
return $monthDays[$month-1];
}
If you wish easy data to seconds then take look Time::Local
$time = timelocal( $sec, $min, $hour, $mday, $mon, $year );