How to find the dates which are there in a week or month till date - ruby

How to find the dates which are there in a week or month till date.
days_for_week should return 19,20,21 (assuming current date is 21st)
days_for_month should return 1..21 (assuming current date is 21st)

For the first, you could use Time.now.wday to get the current week day, then minus that will give you the date of beginning of this week.
For the second, it's much simpler, every month begin with 1st, right?

Assuming I'm reading your question correctly...
The second is simple:
def days_for_month
1..Date.today.day
end
The first requires a little algorithm to work back to Saturday:
def days_for_week
days = []
day = Date.today
until day.saturday?
days.unshift(day.day)
day -= 1
end
days
end

Active support provides a lot of useful methods like at_beginning_of_week, at_end_of_week, at_beginning_of_month etc ..
> Date.today.at_beginning_of_week
=> Mon, 20 May 2013
For this particular case, you could do
> (Date.today.at_beginning_of_week..Date.today).map &:day
=> [20, 21]
Similarly
> (Date.today.at_beginning_of_month..Date.today).map &:day
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
or simply
> 1..Date.today.day

Related

Dynamic Date and Time Filter: After 5:00 PM In Previous Day

I am trying to creat a filter that will pull every account that has been set up after 5:00 PM from the previous day. The date and time exist in the same row. I have created a filter that works for the day but the next day, it pulls for two days. For example, here is what it looks like right now:
= Table.SelectRows(#"Sorted Rows", each [Driver ID] > #datetime(2021, 12, 29, 17, 0, 0))
I have tried changing it to the following so it would dynamically change as the days pass:
= Table.SelectRows(#"Sorted Rows", each DateTime.From([Driver ID]) > Date.AddDays(DateTime.From(Driver ID), -1))
But when I do this I get the following error:
Expression.Error: We cannot convert the value #datetime(2021, 12, 30, 0, 5, 0) to type Function.
Details:
Value=12/30/2021 12:05:00 AM
Type=[Type]
I have made sure the column type is in Date/Time format but that doesn’t seem to help.
Has anybody ran into this issue and know a good solution?
try
= Table.SelectRows(#"Sorted Rows", each Date.IsInPreviousNDays([DriverID], 1) and Time.From([DriverID])> #time( 17, 0, 0))

Micropython: How to use utime.mktime() without knowing the weekday/yearday?

I'm trying to convert an ISO time string like '2021-05-11T18:21:35Z' to an int (seconds from epoch), which mktime() does, except it seems strange to me that it requires the weekday and yearday as part of the argument. In general, it seems unlikely that you would know this, and in my situation I don't.
Obviously in python this is doable with things like datetime, but in uPython these don't exist and I haven't seen a non-external-library way to do this.
Much like with regular Python, the values of weekday and yearday are ignored (they get computed from the other values and are only accepted so that you can pass mktime the tuple returned by e.g. localtime).
You can run:
MicroPython v1.14 on 2021-03-07; ESP module with ESP8266
Type "help()" for more information.
>>> import time
>>> res = time.mktime((2021, 5, 11, 18, 21, 35, 0, 0))
>>> res
674072495
>>> time.localtime(res)
(2021, 5, 11, 18, 21, 35, 1, 131)

I am trying to subtract 3 hours from a method that I have created but I am getting an error

I have successfully created a DST method called dst_datechange that takes a date, is parsed out using Time.parse. It looks like this:
require 'time'
def dst_datechange(date)
date = Time.parse(date.to_s) # if date.class.eql?(String)
case
when (date > Time.parse('March 11, 2018 2:00am')) && (date <
Time.parse('November 4, 2018 2:00am'))
date = Time.parse('November 4, 2018 2:00am')
puts "the date rounded to november 4, 2018"
when (date > Time.parse('November 4 2018, 2:00am')) && (date <
Time.parse('March 10, 2:00am'))
date = Time.parse('March 10, 2019 2:00am')
puts "the date rounded to march 10 2019"
when (date > Time.parse('March 10, 2019 2:00am')) && (date <
Time.parse('November 3, 2019 2:00am'))
date = Time.parse('November 3, 2019 2:00am')
when (date > Time.parse('November 3, 2019 2:00am')) && (date <
Time.parse('March 8, 2020 2:00am'))
date = Time.parse('March 8, 2020 2:00am')
when (date > Time.parse('March 8, 2020 2:00am')) && (date <
Time.parse('November 1, 2020 2:00am'))
date = Time.parse ('November 1, 2020 2:00am')
else
raise "The date #{date} does not match any dst date parameter"
end
date
puts "the new DST date is #{date}"
end
and my "puts" displays this...
the date rounded to: november 4, 2018
the new DST date is now: 2018-11-04 02:00:00 -0600
Now that I am receiving the correct date, I have a step that takes that dst_datechange and performs a subtraction, however, I am getting an error that says:
TypeError: no implicit conversion of Integer into Array
I am not sure what I am doing wrong but I know its most likely a formatting issue where I am trying to subtract a date time object with just a time object. here is my step below where the stacktrace is pointing the failure at:
date = (dst_datechange(Time.now) - (60*60*3))
puts "the date is now adjusted 3 hours back from 2:00am: #{date} "
end
I am unsure how to format that (60*60*3) to subtract 3 hours from that new November 2018-11-04 02:00:00 -0600 date and basically roll it back to 2018-11-03 23:00:00 -0600
Your method def dst_datechange(date) doesn't return the date you want it to, but instead puts your string.
When you call that in your second part, dst_datechange(Time.now), that doesn't return the date, but the return value for the last puts.
Try calling 'date' again after your final puts in your dst_datechange method:
when (date > Time.parse('March 8, 2020 2:00am')) && (date < Time.parse('November 1, 2020 2:00am'))
date = Time.parse ('November 1, 2020 2:00am')
else
raise "The date #{date} does not match any dst date parameter"
end
puts "the new DST date is #{date}"
date
end
You need to specify that you want to subtract hours. Try:
(Time.now - 3.hours).to_datetime
Or, if using ActiveSupport you can specify that you want three hours ago:
3.hours.ago
Since 2007, in most jurisdictions in the United States and Canada, Daylight Saving Time ("DST") has begun at 2:00am on the second Sunday of March, and ended at 2:00am on the first Sunday in November. In Mexico, DST begins at 2:00am on the first Sunday in April and ends at 2:00am on the last Sunday in October. The experience varies in other parts of the world.1
Given a Time object (possibly computed from a string representation of a time) your code returns a second Time object equal to the time at which the next time change occurs, from DST to STD or vice-versa (i.e., in those parts of the United States and Canada that have adopted DST). There is no need to hard-wire those dates. The calculation can be done as follows.
require 'time'
def dst_datechange(time)
year = time.year
if time.dst?
start_std(year)
else
year += 1 if time >= Time.new(year, 11)
start_dst(year)
end
end
def start_std(year)
date = Date.new(year, 11)
date += (7-date.wday) % 7
Time.new(date.year, date.month, date.day, 2)
end
def start_dst(year)
date = Date.new(year, 3, 8)
date += (7-date.wday) % 7
Time.new(date.year, date.month, date.day, 2)
end
['June 17, 2018 1:00pm', 'November 4, 2018 12:59am', 'November 4, 2018 1:00am',
'March 10, 2019 1:59am', 'March 10, 2019 2:00am'].
each do |s|
t = DateTime.strptime(s, '%B %e, %Y %l:%M%P').to_time
t = Time.new(t.year, t.month, t.day, t.hour, t.min, t.sec)
puts "#{s}: #{ dst_datechange(t) }"
end
June 17, 2018 1:00pm: 2018-11-04 02:00:00 -0800
November 4, 2018 12:59am: 2018-11-04 02:00:00 -0800
November 4, 2018 1:00am: 2019-03-10 03:00:00 -0700
March 10, 2019 1:59am: 2019-03-10 03:00:00 -0700
March 10, 2019 2:00am: 2019-11-03 02:00:00 -0800
Notice that the first, second and last examples return a time whose hour is 2. This is in fact one hour after the time changed. The other two examples return an hour of 3, which is an instant after the time changed. Note:
Time.new(2019, 3, 10, 2)
#=> 2019-03-10 03:00:00 -0700
Time.parse('March 10, 2019 2:00am')
#=> 2019-03-10 03:00:00 -0700
In future, DST date ranges could change (as they did in 2007) or DST could be eliminated altogether. In production code, therefore, it would be prudent to address these possibilities. Assuming the method Time#dst? would continue to exist, Time.new(year,6).dst? should tell us if we still have DST, and if so, one could search day-by-day to see when the time changes occur.
1. Source

How to compare two Time objects only down to the hour

I want to compare two Time objects only down to the hour, while ignoring the difference of minutes and seconds.
I'm currently using t0.strftime("%Y%m%d%H") == t1.strftime("%Y%m%d%H"), but I don't think this is a good solution.
Is there better way to do this?
You can use this trick in pure Ruby
t0.to_a[2..9] == t1.to_a[2..9]
Where Time#to_a
$> Time.now.to_a
# => [7, 44, 2, 8, 3, 2014, 6, 67, false, "GMT"]
# [ sec, min, hour, day, month, year, wday, yday, isdst, zone ]
So you can check that the times are equals or not up to the level you want and without missing important components of the object like the zone, etc.
If you have ActiveSupport (either through Rails, or just installed as a gem), it includes an extension to the Time class that adds a change method which will truncate times:
$> require "active_support/core_ext/time"
# => true
$> t = Time.now
# => 2014-03-07 21:30:01 -0500
$> t.change(hour: 0)
# => 2014-03-07 00:00:00 -0500
This won't modify the original time value either. So you can do this:
t0.change(minute: 0) == t1.change(minute: 0)
It'll zero out everything at a lower granularity (seconds, etc.).
require 'time'
t1 = Time.new ; sleep 30 ; t2 = Time.new
t1.hour == t2.hour
This should give you a boolean answer.

How to find out the date of second Monday of each month of given year?

My customer has an event each second Monday of each month.
I need to mark them with red in calendar.
How do i "cleanly" find out the date of that Mondays?
Here's my version.
If the eighth of the month is a Monday, then it is the second Monday. If it is not a Monday, then how many days until the next Monday?
oct_2012 = Date.new 2012, 10, 8
oct_2012.wday # => 1, We're done!
nov_2012 = Date.new 2012, 11, 8
nov_2012.wday # => 4
nov_2012 + (8 - nov_2012.wday) # => 2012-11-12
Does that help?
Edit
Easier version: Just add and be done. This algorithm works even if the month starts on a Monday.
oct_2012 = Date.new 2012, 10, 1
oct_2012 + (8 - oct_2012.wday) # => 2012-10-08
nov_2012 = Date.new 2012, 11, 1
nov_2012 + (8 - nov_2012.wday) # => 2012-11-12
One rule and done!
You second Monday will always fall within the 8th and 14th of each month.

Resources