In Rails, can't I use .next_week with -.hours? - ruby-on-rails

I need to use .next_week not +1.week. Because the .next_week make the date next week and Monday at the same time. It's so comfortable. And then I subtract some hours. But nothing has been changed. Here's my code.
newDate = DateTime.now
newDate = newDate.next_week - 3.hours
=> Sun, 30 Aug 2015 21:00:00 +0900
newDate = newDate.next_week - 3.hours
=> Sun, 30 Aug 2015 21:00:00 +0900
newDate = newDate.next_week - 3.hours
=> Sun, 30 Aug 2015 21:00:00 +0900
Why they can't be used same time? Please explain to me. Thanks.

This has nothing to do with #next_week and - 3.hours working at the same time. It is a misunderstanding about how #next_week works.
#next_week assumes by default a week is Monday-Sunday. This means when calling just #next_week it will return the next Monday at 00:00:00:00.
Example:
DateTime.now.next_week
#=> Mon, 03 Aug 2015 00:00:00 -0400
Okay so that make sense. Now you are substracting 3.hours making it Sunday again
DateTime.now.next_week - 3.hours
#=> Sun, 02 Aug 2015 21:00:00 -0400
Still makes perfect sense. Now here is where the confusion is. Since you rolled back to Sunday by subtracting 3.hours the #next_week is the following Monday again so
(DateTime.now.next_week - 3.hours).next_week
#=> Mon, 03 Aug 2015 00:00:00 -0400
I hope this helps you understand the situation a bit better.
If you use + 1.week this will take you to the same exact point in time the following week
DateTime.now + 1.week
#=> Fri, 07 Aug 2015 09:01:17 -0400
This does not rely on a weekly calendar but rather the basic math of adding 7 days to the referenced Date object.
In conclusion while #next_week might be comfortable you need to understand what it actually implies and I think I would prefer + 1.week in this case for its flexibility and its lack of assumption.
There are also many other methods for traversing time through ActiveSupport such as #advance, #days_since, weeks_since, etc.
Final note next_week can accept a day parameter as well e.g
DateTime.now.next_week(:tuesday)
#=> Tue, 04 Aug 2015 00:00:00 -0400
DateTime.now.next_week(:thursday)
#=> Thu, 06 Aug 2015 00:00:00 -0400

Related

Parse Time in Ruby

I'm trying to parse this date Wed, 17 Feb 2021 13:00:00 +0100 into this 2021-02-17 13:00:00.000000000 +0100.
And I've tried using this Time.strptime(current_time.to_s, '%Q'), (where current_time it's the date above) but I get 1970-01-01 01:00:02.021 +0100
But I don't understand why I get another date, could you help me? Thanks!
I'm trying to parse this date Wed, 17 Feb 2021 13:00:00 +0100 [...]
You seem to already have an instance of Time: (or ActiveSupport::TimeWithZone which is Rails' drop-in replacement with better timezone support)
current_time = Time.current
#=> Thu, 19 May 2022 10:09:58.702560000 CEST +02:00
In this case, there's nothing to parse. You just have to format it via strftime the way you like:
current_time.strftime('%F %T.%N %z')
#=> "2022-05-19 10:09:58.702560000 +0200"
Parsing is only needed when you have a string representation that you want to turn into a Time object, e.g.: (using Rails' Time.zone.parse variant)
time_string = 'Thu, 19 May 2022 10:09:58.702560000 CEST +02:00'
time_obj = Time.zone.parse(time_string)
#=> Thu, 19 May 2022 10:09:58.702560000 CEST +02:00
time_obj.class
#=> ActiveSupport::TimeWithZone

Ruby parse DateTime with variable

I'm trying to parse a specific hour of a specific date. When I put the date directly as an argument, it works fine, but when I create a variable and put it in the argument it returns the current date.
Why is that?
NOTE: the variable time is 9pm and I need to parse 9pm of 12 March 2016.
datetime = DateTime.new(2016,3,12,9)
=> Sat, 12 Mar 2016 09:00:00 +0000
DateTime.parse("sat 12 march 2016 9pm")
=> Sat, 12 Mar 2016 21:00:00 +0000
DateTime.parse("datetime 9pm")
=> Mon, 14 Mar 2016 21:00:00 +0000
In your third call, you use the literal string "datetime" rather than the value of your datetime variable. You can use string interpolation to use the variable's value:
DateTime.parse("#{datetime} 9pm")
In this case, the "9pm" is ignored since it doesn't make sense added to the end of an existing date but this is why the initial attempt wasn't working. Interpolation is generally a solution for using a variable's value rather than its name.
If your goal is to change the time of an existing date, use the change method:
datetime.change(hour:21)
You can also try this
date = Date.new(2016,3,12)
DateTime.parse("#{date} 9pm")
## Output
Sat, 12 Mar 2016 21:00:00 +0000
OR
datetime = DateTime.new(2016,3,12,9)
DateTime.parse((datetime + 12.hours).to_s)
## Output
Sat, 12 Mar 2016 21:00:00 +0000
OR
DateTime.parse((datetime + 12.hours).to_s).strftime("%a, %d %b %Y %I:%M %p")
## Output
Sat, 12 Mar 2016 09:00 PM

Why does this DateTime subtraction operation return invalid results?

I have two DateTime objects, one in the past and one representing the current datetime. I am trying to find out how many minutes have passed between the two:
past = "Wed, 03 Jul 2013 00:59:39 UTC +00:00".to_datetime
now = "Wed, 03 Jul 2013 01:04:19 +0100".to_datetime
seconds = (now - past) #result is (-83/2160)
This is incorrect. Seconds should be 280, the number of seconds that have passed between the two times.
Subtracting two DateTimes returns the elapsed time in days.
So you can do:
past = "Wed, 03 Jul 2013 00:59:39 UTC +00:00".to_datetime
now = "Wed, 03 Jul 2013 01:04:19 +0100".to_datetime
seconds = (now - past) * 1.day
# => -3320.0
Or you could do:
seconds = (now.to_i - past.to_i)
# => -3320
※ The result is negative because of the Timezone.
past.utc
# => Wed, 03 Jul 2013 00:59:39 +0000
now.utc
# => Wed, 03 Jul 2013 00:04:19 +0000
You can see that now is actually older than past.

TimeZone offset bug – Rails

ActiveSupport::TimeZone.new(-4).parse("2012-08-20T14:00:00-0400")
returns
Mon, 20 Aug 2012 15:00:00 ADT -03:00
I would expect parse() to return a Time with -04:00, like Mon, 20 Aug 2012 14:00:00 EDT -04:00
How would you handle this? I think that Daylight Saving Time is messing up things here.
I've handled this problem using new_offset from DateTime.
time = "2012-08-20T14:00:00-0400"
DateTime.parse(time).new_offset("+2")
returns Mon, 20 Aug 2012 20:00:00 +0200

Time.use_zone is not working as expected

So right now it is 2:54 PM PST in San Francisco. For some reason, this code block is not returning 12:54 PM HST in Hawaii. Am I missing something here? I would expect this code to return me the current time in Hawaii
Time.use_zone('Hawaii') do
Time.now
end
# => 2012-01-03 14:54:54 -0800
This should work ok:
Time.use_zone('Hawaii') do
p Time.zone.now
end
Try using Time.now.in_time_zone inside your block instead.
> Time.use_zone('Hawaii') do
> Time.now.in_time_zone
> end
=> Tue, 03 Jan 2012 13:07:06 HST -10:00
Use Time.current if you want now with timezone support. Time.now is dangerous when working in a timezone aware application, as a rule of thumb I never use Time.now, only Time.current. Rails time helpers like 2.hours.ago and 4.days.from_now are based off of Time.current as well.
# Time.current will use Time.zone when needed (when Time.zone is present)
def current
::Time.zone ? ::Time.zone.now : ::Time.now
end
Also, this is a great article with a great cheat sheet at the bottom: https://www.varvet.com/blog/working-with-time-zones-in-ruby-on-rails/
DOs
code
result
2.hours.ago
Thu, 27 Aug 2015 14:39:36 AFT +04:30
1.day.from_now
Fri, 28 Aug 2015 16:39:36 AFT +04:30
Time.zone.parse("2015-08-27T12:09:36Z")
Thu, 27 Aug 2015 16:39:36 AFT +04:30
Time.current
Thu, 27 Aug 2015 16:39:36 AFT +04:30
When supliyng an API
Time.current.utc.iso8601
2015-08-27T12:09:36Z
If you can’t use Time.zone.parse
Time.strptime("2015-08-27T12:09:36Z", "%Y-%m-%dT%H:%M:%S%z").in_time_zone
Thu, 27 Aug 2015 16:39:36 AFT +04:30
If you really can’t have a Time or DateTime for some reason
Date.current
Thu, 27 Aug 2015
If you have a date and want to make the best out of it
Date.current.in_time_zone
Thu, 27 Aug 2015 00:00:00 AFT +04:30
DON’Ts
code
result
Returns system time and ignores your configured time zone.
Time.now
2015-08-27 14:09:36 +0200
Will assume time string given is in the system’s time zone.
Time.parse("2015-08-27T12:09:36Z")
2015-08-27 12:09:36 UTC
Same problem as with Time.parse.
Time.strptime("2015-08-27T12:09:36Z", "%Y-%m-%dT%H:%M:%S%z")
2015-08-27 12:09:36 UTC
This could be yesterday or tomorrow depending on the machine’s time zone, see issue 1 for more info.
Date.today
Thu, 27 Aug 2015
Time.now - using server time
Time.zone.now - using rails application time (in config: config.time_zone)
Time.use_zone - using 'your' timezone for given block
This example is wrong, because Time.now get time in your server timezone and with method in_time_zone translate time into an equivalent time in Hawaii timezone. But it's no current Time in Hawaii! It's your server time with utc offset for Hawaii.
Time.use_zone('Hawaii') do
Time.now.in_time_zone
end
=> Wed, 14 Aug 2013 10:33:18 HST -10:00
Time.now.in_time_zone
=> Thu, 15 Aug 2013 00:32:30 MSK +04:00
For getting time in Hawaii timezone you must use
Time.use_zone('Hawaii') do
Time.zone.now
end
Don't use Time.now this is using your local time zone instead use Time.current
Time.use_zone('Hawaii') do
p Time.current
end

Resources