Ruby strftime: don't show minutes if zero - ruby

I'm trying to achieve this style of output:
Time.new(2021,9,19,6,0,0) => "6am"
Time.new(2021,9,19,6,30,0) => "6:30am"
Closest I've gotten is strftime('%l:%-M%P') which yields:
Time.new(2021,9,19,6,0,0).strftime('%-l:%-M%P') => "6:0am"
Time.new(2021,9,19,6,30,0).strftime('%-l:%-M%P') => "6:30am"
Is there a known way to suppress %M or %-M when zero, or am I going to need to do my own thing here?

You might have to do your own thing but this is a simple way to do it.
time.strftime('%-l:%M%P').sub(':00', '')

Related

Make time stamp from string

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"

How can I calculate the number of weeks since a given date in Ruby?

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.

How to group in ranges a sorted array of integers in Bash

In bash I'have a sorted integer array like:
array[0]=1
array[1]=2
array[2]=3
array[3]=4
array[4]=7
array[5]=9
array[6]=10
array[7]=13
array[8]=15
array[9]=16
And I want to obtain output like:
1-4,7,9-10,13,15-16
There is a simple and fast way to do it?
I don't know of any standard ways of doing it, but it shouldn't be that hard to write your own function to do it. Something in the lines of:
Save the first array elements 'value' as 'low'
Iterate over the array and save current 'index' as 'high'
When array 'value' differs from 'index', print out 'low-high' IF not 'low == high', then print 'low'
Reset 'low' and 'index' to current 'value' and continue
Increase 'index' by one
Should be simple enough pseudo for a pre-sorted non-empty integer array :)
(Sorry about formatting, I'm currently on a Mac with a PC keyboard and I don't get along with it very well.)

How to select the first inner array?

I have the following:
arr = [["1/31/2012 8:00 PM"]]
Right now, to get that string I end up doing arr.first.first...which just seems awkward.
What's a more direct way to get 1/31/2012 8:00 PM?
It depends on your array purpose, you have several options:
arr[0][0] is is equal to arr.first.first. But I think arr.first.first is normal solution
arr.flatten.first
Consider other structure for arr with which you will be able to query for this data more naturally like meeting.nearest # => "1/31/2012 8:00 PM".
Your code seems the correct way to do it, but, you can also do
arr.to_s
=> "1/31/2012 8:00 PM"
But be cautious. This will concatenate the elements in the array into a single string, if more than one element is present in the array
[["this", "is"]].to_s
=> "thisis"
[["this", "is"], ["test"]].to_s
=> "thisistest"

iterate an array of strings and perform a regexp

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.

Resources