Ruby count items by date - ruby

I have an array of dates e.g.
Fri Jan 28 10:13:19 UTC 2011
Thu Jan 27 16:57:59 UTC 2011
Thu Jan 27 16:41:21 UTC 2011
Wed Jan 26 09:20:48 UTC 2011
Mon Jan 24 16:19:48 UTC 2011
Fri Jan 21 11:45:34 UTC 2011
Fri Jan 21 11:42:19 UTC 2011
How can I group them so the output is as hash with the count of items each day:
Friday 28 => 1
Thursday 27 => 2
Wednesday 26 => 1
Monday 24 => 1
Friday 21 => 2

Or, to put kurumi's solution more verbosely and using Jimmy's strftime:
histogram = dates.inject(Hash.new(0)) do |hist, date|
hist[date.strftime('%A %d')] += 1
hist
end.sort_by{|date, count| date.split(' ').last}.reverse
give us:
Friday 28: 1
Thursday 27: 2
Wednesday 26: 1
Monday 24: 1
Friday 21: 2
OK?

#things.group_by {|thing| thing.strftime "%A %d" }.each do |key, group|
puts "#{key} => #{group.size}"
end
%A is the full weekday name and %d is the day of the month
I can't test this currently but I think it will work.

s=a.inject(Hash.new(0)) do |h,y|
z=y.split
h[ z[0]+z[2] ]+=1
h
end

Related

Spring boot cron expression, every 2 month

I wanted to construct a spring cron expression that executes At 23:00:00pm, on first Sunday, every 2 months starting in January, so far I have this
0 0 23 ? 1/2 SUN but this one executes At 23:00:00pm, every Sunday, every 2 months starting in January. how can I make it execute only the first Sunday every two months?
0 0 23 ? 1/2 SUN next excution dates are as follows
Sun Mar 07 23:00:00 UTC 2021
Sun Mar 14 23:00:00 UTC 2021
Sun Mar 21 23:00:00 UTC 2021
Sun Mar 28 23:00:00 UTC 2021
Sun May 02 23:00:00 UTC 2021
Sun May 09 23:00:00 UTC 2021
Sun May 16 23:00:00 UTC 2021
Sun May 23 23:00:00 UTC 2021
Sun May 30 23:00:00 UTC 2021
Sun Jul 04 23:00:00 UTC 2021
but what I wanted was
Sun Mar 07 23:00:00 UTC 2021
Sun May 02 23:00:00 UTC 2021
Sun Jul 04 23:00:00 UTC 2021
how can I improve my expression to get the above result?
0 0 23 1-7 1/2 SUN
The only part you are missing, is day number in the range 1-7.
Code to verify the schedule:
var sundays = CronExpression.parse("0 0 23 1-7 1/2 SUN");
var nextDate = LocalDateTime.now();
var dateFormatter = DateTimeFormatter.ofPattern("EEE, MMM d, yyyy 'at' hh:mm:ss a");
for (var i = 0; i < 10; i++) {
nextDate = sundays.next(nextDate);
System.out.println(nextDate.format(dateFormatter));
}
Will run at:
Sun, Mar 7, 2021 at 11:00:00 pm
Sun, May 2, 2021 at 11:00:00 pm
Sun, Jul 4, 2021 at 11:00:00 pm
Sun, Sep 5, 2021 at 11:00:00 pm
Sun, Nov 7, 2021 at 11:00:00 pm
...

Cron Job in Spring Boot

I want to automate a task quarterly in a year.
Task should execute
Jan 1st
April 1st
July 1st
October 1st
etc
As I tried #Scheduled(cron = "0 0 6 1 1/3 ?") in Spring Boot application but its not working currently and mail didn't trigger quarterly.
Try this
#scheduled(cron = "0 0 6 1 */3 *")
So read the first day of each 3 month at 6:00
Try this one -
#scheduled(cron ="0 0 0 1 JAN,APR,JUL,OCT ? *")
Next execution:
Wed Jul 01 00:00:00 UTC 2020
Thu Oct 01 00:00:00 UTC 2020
Fri Jan 01 00:00:00 UTC 2021
Thu Apr 01 00:00:00 UTC 2021
Thu Jul 01 00:00:00 UTC 2021
Fri Oct 01 00:00:00 UTC 2021
Sat Jan 01 00:00:00 UTC 2022
Fri Apr 01 00:00:00 UTC 2022
Fri Jul 01 00:00:00 UTC 2022
Sat Oct 01 00:00:00 UTC 2022

How to fetch 5th and 6th day of every month in Unix?

Is it possible to fetch 5th and/or 6th day of every month in Unix?
I've tried this but it does not give me the desired output:
echo $((($(date +%-d)-1)/5))
Use this:
for month in {1..12}; do date -d "$month/5/2017" +"%c - is a %A"; done
Output:
Thu 05 Jan 2017 12:00:00 AM CET - is a Thursday
Sun 05 Feb 2017 12:00:00 AM CET - is a Sunday
Sun 05 Mar 2017 12:00:00 AM CET - is a Sunday
Wed 05 Apr 2017 12:00:00 AM CEST - is a Wednesday
Fri 05 May 2017 12:00:00 AM CEST - is a Friday
Mon 05 Jun 2017 12:00:00 AM CEST - is a Monday
Wed 05 Jul 2017 12:00:00 AM CEST - is a Wednesday
Sat 05 Aug 2017 12:00:00 AM CEST - is a Saturday
Tue 05 Sep 2017 12:00:00 AM CEST - is a Tuesday
Thu 05 Oct 2017 12:00:00 AM CEST - is a Thursday
Sun 05 Nov 2017 12:00:00 AM CET - is a Sunday
Tue 05 Dec 2017 12:00:00 AM CET - is a Tuesday
For the 6th of the month, it's done in a similar way.
I am not sure if this is what you are looking for: i am assuming you want to get the 5th(or 6th) day of a month sitting on any day. If so, you can make use of the current date and get the 5th day of current month like below:
dd=`date '+%d'`
if(( $dd > 5 )); then
(( diff = dd - 5 ))
myDate=`date -d "-$diff days"`
else
(( diff = 5 - dd ))
myDate=`date -d "+$diff days"`
fi
echo $myDate
For 6th day you can do similarly. Above code should work on Linux distro.

Crontab schedule every two week

There is a question happened this week on my crontab job.
It's be set as below and works normal every two weeks until now.
10 06 * * 1 test $(($(date +\%W)\%2)) -eq 0 && echo 'test' > /tmp/test.log
The problem is
$(($(date +\%W)\%2)) would be 08, over 7 in February.
And it will show error message if you run in bash: value too great for base (error token is "08").
There is also not working when I try to revise it for forcing decimal base purpose :
10 06 * * 1 test $((10#$(date +\%W)\%2)) -eq 0 && echo 'test' > /tmp/test.log
Does someone know how to solve this issue? Many thanks.
Every two week at midnight
0 0 */15 * * echo 'test' > tmp.txt
Your cron job will be run at: (5 times displayed)
2016-03-15 00:00:00 UTC
2016-03-30 00:00:00 UTC
2016-04-15 00:00:00 UTC
2016-04-30 00:00:00 UTC
2016-05-15 00:00:00 UTC
Make condition in your script
The use of % sign is discouraged in crontab!
To ensure having jod started on monday, every two weeks you've better to create a small script.
#!/bin/bash
if [ "$1" == "-f" ] ;then # use "-f" switch to force execution on odd weeks
shift
else
printf -v d '%(%W)T' -1
((10#$d%2)) || exit 0 # stop here if odd week
fi
printf "Real job begin at %(%c)T, there...\n" -1
This could be shortened to one single line:
#!/bin/bash
[ "$1" == "-f" ]&&shift||{ printf -v d '%(%W)T' -1;((10#$d%2))||exit;}
So you could add standard lines in your crontab:
10 06 * * 1 path/to/myScript > /tmp/test.log
Sample: year 2016
date -d 2016-1-4\ 10:06 +%s
1451898360
for i in {0..52};do
printf -v d '%(%W)T' $((c=i*7*86400+1451898360))
((10#$d%2)) && printf "%(%a %d %b, week: %W)T\n" $c
done | cat -n
1 Mon 04 Jan, week: 01
2 Mon 18 Jan, week: 03
3 Mon 01 Feb, week: 05
4 Mon 15 Feb, week: 07
5 Mon 29 Feb, week: 09
6 Mon 14 Mar, week: 11
7 Mon 28 Mar, week: 13
8 Mon 11 Apr, week: 15
9 Mon 25 Apr, week: 17
10 Mon 09 May, week: 19
11 Mon 23 May, week: 21
12 Mon 06 Jun, week: 23
13 Mon 20 Jun, week: 25
14 Mon 04 Jul, week: 27
15 Mon 18 Jul, week: 29
16 Mon 01 Aug, week: 31
17 Mon 15 Aug, week: 33
18 Mon 29 Aug, week: 35
19 Mon 12 Sep, week: 37
20 Mon 26 Sep, week: 39
21 Mon 10 Oct, week: 41
22 Mon 24 Oct, week: 43
23 Mon 07 Nov, week: 45
24 Mon 21 Nov, week: 47
25 Mon 05 Dec, week: 49
26 Mon 19 Dec, week: 51
27 Mon 02 Jan, week: 01
For comparission with idea of using 15th and 30th each months:
for i in {1..12}/{15,30};do
date -d '2016/'$i +'%a %d %b, week: %W' 2>/dev/null
done | cat -n
1 Fri 15 Jan, week: 02
2 Sat 30 Jan, week: 04
3 Mon 15 Feb, week: 07
4 Tue 15 Mar, week: 11
5 Wed 30 Mar, week: 13
6 Fri 15 Apr, week: 15
7 Sat 30 Apr, week: 17
8 Sun 15 May, week: 19
9 Mon 30 May, week: 22
10 Wed 15 Jun, week: 24
11 Thu 30 Jun, week: 26
12 Fri 15 Jul, week: 28
13 Sat 30 Jul, week: 30
14 Mon 15 Aug, week: 33
15 Tue 30 Aug, week: 35
16 Thu 15 Sep, week: 37
17 Fri 30 Sep, week: 39
18 Sat 15 Oct, week: 41
19 Sun 30 Oct, week: 43
20 Tue 15 Nov, week: 46
21 Wed 30 Nov, week: 48
22 Thu 15 Dec, week: 50
23 Fri 30 Dec, week: 52
As you could see, there miss one operation on weeks: 6, 9, 10, 21, 32 and 45. At least there is 3 operation less in one year.

How do you get DateTime.parse to return a time in your time zone?

I need this
require 'date'
DateTime.parse "Mon, Dec 27 6:30pm"
to return a DateTime for 6:30pm in the EDT timezone, but it returns one in UTC. How can I get a EST DateTime or convert the UTC one into an EDT DateTime with a 6:30pm value?
OK I'm going to offer an answer to my own question
require 'time'
ENV["TZ"] = "US/Eastern"
Time.parse("Mon, Dec 27 6:30pm").to_datetime
=> #<DateTime: 2011-12-27T18:30:00-05:00 (117884327/48,-5/24,2299161)>
In Rails, this worked nicely for me
DateTime.parse "Mon, Dec 27 6:30pm #{Time.zone}"
It won't work in vanilla Ruby though.
Final answer ;-)
require 'date'
estHoursOffset = -5
estOffset = Rational(estHoursOffset, 24)
date = (DateTime.parse("Mon, Dec 27 6:30pm") - (estHoursOffset/24.0)).new_offset(estOffset)
(or -4 for EDT)
DateTime#change()
You can try using change() after parsing it to alter the timezone offset:
DateTime.parse( "Mon, Dec 27 6:30pm" ).change( offset: '-0400' )
# => Wed, 27 Dec 2017 18:30:00 -0400
You can also just use the hours:
DateTime.parse( "Mon, Dec 27 6:30pm" ).change( offset: '-4' )
# => Wed, 27 Dec 2017 18:30:00 -0400
But, be careful, you cannot use an integer:
DateTime.parse( "Mon, Dec 27 6:30pm" ).change( offset: -4 )
# => Wed, 27 Dec 2017 18:30:00 +0000
If you need to determine the correct offset to use based on a time zone you can do something like this:
offset = ( Time.zone_offset('EDT') / 1.hour ).to_s
# => "-4"
DateTime.parse( "Mon, Dec 27 6:30pm" ).change( offset: offset )
# => Wed, 27 Dec 2017 18:30:00 -0400
You can also use change() to manually set other parts of the DateTime as well, like setting the hour to noon:
DateTime.parse( "Mon, Dec 27 6:30pm" ).change( offset: '-4', hour: 12 )
# => Wed, 27 Dec 2017 12:00:00 -0400
Be careful with that one because you can see that it's cleared the minutes as well.
Here's the docs for the change() method: http://api.rubyonrails.org/v5.1/classes/DateTime.html#method-i-change
If you're using Rails' ActiveSupport:
"Mon, Dec 27 6:30pm".in_time_zone(-4.hours).to_datetime
# => Mon, 27 Dec 2021 18:30:00 -0400
Time.find_zone(-4.hours).parse("Mon, Dec 27 6:30pm").to_datetime
# => Mon, 27 Dec 2021 18:30:00 -0400
If you want to use the local daylight saving time (DST) rules, you could use:
"Mon, Dec 27 6:30pm".in_time_zone("Eastern Time (US & Canada)")
# => Mon, 27 Dec 2021 18:30:00 EST -05:00
Time.find_zone("Eastern Time (US & Canada)").parse("Mon, Dec 27 6:30pm")
# => Mon, 27 Dec 2021 18:30:00 EST -05:00
Time.find_zone("Eastern Time (US & Canada)").parse("Mon, Dec 27 6:30pm").to_datetime
# => Mon, 27 Dec 2021 18:30:00 -0500
Time.find_zone("Eastern Time (US & Canada)").parse("Mon, Jun 27 6:30pm")
# => Sun, 27 Jun 2021 18:30:00 EDT -04:00
Time.find_zone("Eastern Time (US & Canada)").parse("Mon, Jun 27 6:30pm").to_datetime
# => Sun, 27 Jun 2021 18:30:00 -0400
Time.find_zone("EST5EDT").parse("Mon, Jun 27 6:30pm").to_datetime
# => Sun, 27 Jun 2021 18:30:00 -0400
Notice the date in June, above, is automatically set to EDT (-0400) because this date is in DST, contrary to the December date.
To force EST regardless if date is within DST or not:
Time.find_zone("EST").parse("Mon, Jun 27 6:30pm")
# => Sun, 27 Jun 2021 18:30:00 EST -05:00
Time.find_zone("EST").parse("Mon, Jun 27 6:30pm").to_datetime
# => Sun, 27 Jun 2021 18:30:00 -0500

Resources