I need to format 161901 to 04:19:01PM.
I tried the following:
Time.parse(161901)
"161901".chars.each_slice(2).map(&:join)
Time.parse("161901".chars.each_slice(2).map(&:join))
Being a newbie to ruby, it is difficult to find a way.
Here's is the most basic answer, but it makes some assumptions:
require 'time'
time = Time.strptime('161901', '%H%M%S')
time.strftime('%I:%M:%S%p')
=> "04:19:01PM"
The issue is that your string '161901' may or may not be padded and it might also be an integer and not a string. For example, if the time was 6:00 am, perhaps you get a string such as: '60000', you would need to pad this on the left hand side to parse this properly. Due to this I would suggest the following approach:
require 'time'
# Assume your time is an integer with no right padding:
time = 61901
ptime = Time.strptime(time.to_s.rjust(6, '0'), '%H%M%S') # Do proper padding
ptime.strftime('%I:%M:%S%p')
=> "06:19:00AM"
This should help sanitize your variable that you are parsing to produce consistent results.
References: https://ruby-doc.org/stdlib/libdoc/date/rdoc/DateTime.html#method-i-strftime
DateTime::strptime and DateTime#strftime are purpose-built for this task.
require 'time'
fmt_in = '%H%M%S'
fmt_out = '%I:%M:%S%p'
t = DateTime.strptime('161901', fmt_in)
t.strftime(fmt_out)
#=> "04:19:01PM
You can do like below it was very easy for use multiple times with environment variables if you have fixed display format for time
require 'time'
class Time
def self.strpftime(str, in_format,
out_format = ENV.fetch('out_format'))
strptime(str, in_format).strftime(out_format)
end
end
# with out using environment variable
Time.strpftime('161901', '%H%M%S', '%I:%M:%S%p')
=> "04:19:01PM"
# using environment variable
Time.strpftime('161901', '%H%M%S')
=> "04:19:01PM"
You'll be best off using "strptime" when converting strings to dates or times.
https://ruby-doc.org/stdlib-2.4.1/libdoc/time/rdoc/Time.html#method-c-strptime :
2.5.8 :006 > Time.strptime("161901","%H%M%S")
=> 2020-12-18 16:19:01 +0000
this will get you a "Time" object that you'll be able to query, parse, sort and/or output in different format.
require 'time'
input = '161901'
formatted_input = input.split('').each_slice(2).to_a.map(&:join).join(':')
time = Time.parse(formatted_time)
formatted_time = time.strftime("%I:%M:%S%p")
Output:
=> "04:19:01PM"
Related
My current project has me converting Ruby into Node.js. I've never worked with Ruby before this and so I'm still trying to learn all the syntactical differences. Currently, I'm a bit confused about this snippet:
myUri = Addressable::URI.parse(original_path)
idx = original_path.index(myUri.path)
hit.props[:path] = original_path[idx..original_path.length-1]
else
hit.is_invalid = true
So, I understand that we are parsing the original_path.
Then, we are getting the index of the myUri.path inside of the original_path, which I believe will return a number.
The next line is what's confusing me. I know I'm setting [:path] to something, but I don't understand what. I think that it's a modified version of original_path but I'm not understanding how its being modified.
original_path[idx..original_path.length-1] accesses string using a range.
See a range exaple
(1..4).to_a
# [1,2,3,4]
Range string/array access takes a part of the array/string that is between range boundaries. In this case - between idx (that is the beginning of myUri.path) and the end of the string.
See below:
a = 'abcd'
# => "abcd"
a[1..a.size-1]
# => "bcd"
Docs
Objective
I am trying to calculate the distance in weeks since a given date without jumping through hoops. I'd prefer to do it in plain Ruby, but ActiveSupport is certainly an acceptable alternative.
My Code
I wrote the following, which seems to work but looks like the long way around to me.
require 'date'
DAYS_IN_WEEK = 7.0
def weeks_since date_string
date = Date.parse date_string
days = Date.today - date
weeks = days / DAYS_IN_WEEK
weeks.round 2
end
weeks_since '2015-06-15'
#=> 32.57
ActiveSupport's #weeks_since takes a number of weeks as its argument, so it doesn't fit this use case. Ruby's Date class doesn't seem to have anything relevant, either.
Alternatives?
Is there a better built-in solution or well-known algorithm for calculating the number of weeks separating a pair of dates? I'm not trying to code-golf this, as readability trumps brevity, but simply to learn whether Ruby natively supports the type of date arithmetic I've coded by hand.
require 'date'
str = '2015-06-15'
Date.parse(str).step(Date.today, 7).count # => 33
Date.parse(str).upto(Date.today).count.fdiv(7).round(2) # => 32.71
Might be easier to convert the dates to time and then divide the time difference by a week. You can round it however you want or ceil.
def weeks_since(date_string)
time_in_past = Date.parse(date_string).to_time
now = Time.now
time_difference = now - time_in_past
(time_difference / 1.week).round(2)
end
in_weeks (Rails 6.1+)
Rails 6.1 introduces new ActiveSupport::Duration conversion methods like in_seconds, in_minutes, in_hours, in_days, in_weeks, in_months, and in_years.
As a result, now, your problem can be solved as:
date_1 = Time.parse('2020-10-18 00:00:00 UTC')
date_2 = Time.parse('2020-08-13 03:35:38 UTC')
(date_2 - date_1).seconds.in_weeks.to_i.abs
# => 9
Here is a link to the corresponding PR.
time_format = '%H.%M.%S.%6N'
timestamp = DateTime.now.strftime(time_format) # this works, it shows something like "10.09.53.595977"
DateTime.strptime(timestamp, time_format) # error, in `strptime': invalid date (ArgumentError)
So is it possible to make the #strptime work if I really want to parse the microsecond (6 digits) as well?
Looking at the ruby source code at ext/date/date_strptime.c it seems the N case is taken into account, try this:
DateTime.strptime(timestamp, '%H.%M.%S.%N')
And to check the seconds fraction was parsed try this:
d = DateTime.strptime(timestamp, '%H.%M.%S.%N')
p d.sec_fraction
And compare it with what you have in *time_format*.
Given an array of DateTime Strings, I want to just fetch the times e.g. 10:30:00.
So far I come up with this, but it wont give me the right result:
["2011-07-30 10:00:00","2011-07-30 12:00:00"].each{|item| item.match(/\d{2}:\d{2}:\d{2}/)}
If all the strings really are like that then just do some substring mangling:
a = ["2011-07-30 10:00:00","2011-07-30 12:00:00"]
times = a.map { |e| e[11,8] }
This will also work if your timestamps include things like 2011-07-30 10:00:00.1123, 2011-07-30T10:00:00, or 2011-07-30 10:00:00 +0700.
If you wanted to be friendlier to the future, then you could do this:
off = '9999-99-99 '.length
len = '99:99:99'.length
times = a.map { |e| e[off, len] }
so no one would have to guess what the 11 and 8 were all about.
You could achieve the same using the excellent DateTime library from Ruby.
require 'date'
["2011-07-30 10:00:00","2011-07-30 12:00:00"].map{|item|
DateTime.parse(item).strftime("%H:%M:%S")
}
=> ["10:00:00", "12:00:00"]
Though, mu's answer is great.
I have this string s that is formatted in this way. I want to turn it into a Time object.
Here is my attempt at doing this and making it readable.
s = "15081992"
n = { :year=> s[4..7], :month=> s[2..3], :day=> s[0..1] }
newtime = Time.mktime( n[:year], n[:month], n[:day] )
# 1992-08-15 00:00:00 -0400
It works, but I'm seeking any suggestion or feedback on how to write this in a better way to achieve the same result or is this pretty much it?
require 'date'
Date.strptime("15081992", "%d%m%Y")