How to get leading 0 in seconds? - ruby

I'm trying to get hours, minutes and seconds from current time and print it into format "hourminutesecond". For example "121103". But there isn't printed leading zero when I try to do it with next code
irb(main):021:0> ct = Time.now
=> 2012-11-06 12:11:03 +0100
irb(main):022:0> "#{ct.hour}#{ct.min}#{ct.sec}"
=> 12113
Output is "12113" but I want "121103".
Is there method or option for that. I can extract it with regex but just wondering if there is easier way to do it.

You should use time formatting:
ct = Time.now
ct # => Tue Nov 06 15:31:03 +0400 2012
ct.strftime('%H%M%S') # => "153103"

You should accept Sergio's answer as that's the correct way to deal with date/time objects.
However if you must do it using String class you can use rjust method to add a leading zero.
"#{ct.hour}#{ct.min}#{ct.sec}" # 12113
"#{ct.hour}#{ct.min}#{String(ct.sec).rjust(2,"0")}" # 121103

Related

Date.parse fails when system date is 2017-02-01

I'm experiencing an strange issue with Date.parse method.
I tried several ruby versions and it happens in all of them. The tests below were run in version 2.1.10.
Yesterday all my tests were passing but today they started to fail. The cause is a Date.parse call that started to raise an exception.
If system date is 2017-01-31, it works fine:
2.1.10 :002 > system('date')
Ter 31 Jan 2017 11:24:08 BRST
=> true
2.1.10 :003 > Date.parse("29%2F10%2F2015")
=> #<Date: 2017-01-29 ((2457783j,0s,0n),+0s,2299161j)>
But if system date is today, it fails:
2.1.10 :002 > system('date')
Qua 1 Fev 2017 11:24:27 BRST
=> true
2.1.10 :003 > Date.parse("29%2F10%2F2015")
ArgumentError: invalid date
from (irb):3:in `parse'
from (irb):3
from /Users/fernando/.rvm/rubies/ruby-2.1.10/bin/irb:11:in `<main>'
I probably can get around this by using another method to parse this date but I'm interested in why it started to fail today.
Is 2017-02-01 a special date for ruby?
Date.parse is a method which tries to parse a date from the given string using a number of heuristics in order to support many different formats without specifying the actual format. Thus, unless the format is clear, it is always possible that Ruby come to different conclusions than you.
In order to get an idea how Ruby parses your string, you can use
Date._parse("29%2F10%2F2015")
# => {:mday=>29}
As you can see, Ruby is able to get the day of month as 29 from the passed string but doesn't get any additional information. In order to form a valid date, Ruby substitutes the missing parts from the current date. Now, since February 2017 only has 28 days, the resulting date is invalid here but would be valid in January.
Still, the result is not what you actually seem to want. Instead, try to first transform your date into a more easily parsed string and try again using the approach by Eric Duminil in another answer to this question:
require 'date'
require 'uri'
string = '29%2F10%2F2015'
Date.strptime(URI.unescape(string), '%d/%m/%Y')
# => #<Date: 2015-10-29 ((2457325j,0s,0n),+0s,2299161j)>
As you can see, with Date.strptime, you can specify the exact format of the parsed string and can thus be sure it either gets correctly parsed or errors out.
%2F is the URL Encoded value of the Forward Slash (/)
so you need to decode your url-encoded string first
> require 'open-uri'
#=> true
> string = "29%2F10%2F2015"
#=> "29%2F10%2F2015"
> date = URI::decode(string)
#=> "29/10/2015"
> Date.parse(date)
#=> #<Date: 2015-10-29 ((2457325j,0s,0n),+0s,2299161j)>
Is 2017-02-01 a special date for ruby?
no, it's not special ;)
> s = "2017-02-01"
> Date.parse(s)
#=> #<Date: 2017-02-01 ((2457786j,0s,0n),+0s,2299161j)>
You have three problems :
'%2F' shouldn't be here
'2017-02-01' could be "February 1" or "January 2".
Date.parse relies on system date to parse the string.
If you know which format you have, you really should use Date.strptime :
require 'date'
require 'uri'
def parse_url_date(url_date)
Date.strptime(URI.unescape(url_date), '%d/%m/%Y')
end
puts parse_url_date("29%2F10%2F2015")
#=> 2015-10-29
puts parse_url_date("01%2F02%2F2017")
#=> 2017-02-01
If you know your "dates" are URL-encoded then you have to URL-decode them first. Use URI.unescape() for this then pass the value it returns to Date.parse().
Date.parse(URI.unescape("29%2F10%2F2015"))

How can I output the AM/PM part of a string received in military time using Ruby?

Say I have a string like 13:00, which is 1:00PM, but only the first two characters (13). How can I output a string datatype of the PM part? Like
'13'.print_ampm()
=> PM
Use Time#strftime, which is for formatting times. The %p flag will get you an uppercase "AM" or "PM":
t = Time.now
# => 2016-10-14 22:37:03 -0400
t.strftime('%p')
=> "PM"
For just a string that's not a Time object, use:
require 'time'
Time.parse('10:30').strftime('%p')
# => "AM"
Time.parse('23:30').strftime('%p')
# => "PM"
If you want lowercase, use %P instead:
Time.parse('23:30').strftime('%P')
# => "pm"
One way to handle this is to use the Time.parse method as defined here:
https://ruby-doc.org/stdlib-2.3.1/libdoc/time/rdoc/Time.html#method-c-parse
Like this:
require 'time'
hour = '13'
puts Time.parse("#{hour}:00").strftime('%p') # PM

How to get the current month with Sequel

I would like recover a list of entries for the current month with Sequel.
I tried:
Entry.where(:date >= Date.month).sum(:duration)
or
Entry.where(:date.like('%/06/2013')).sum(:duration)
and other ways, but none of them seemed to work.
If you want all entries the current month and the current year, it's probably easiest to use a range:
d = Date.today
Entry.where(:date=> Date.new(d.year, d.month)...(Date.new(d.year, d.month) >> 1)).sum(:duration)
If you want the current month in any year, Sequel has built in support for this:
Entry.where(Sequel.extract(:month, :date) => Date.today.month).sum(:duration)
You'll need to think in terms of how a database thinks, and how Sequel turns Ruby ranges into SQL:
require 'date'
today = Date.today # => #<Date: 2013-07-03 ((2456477j,0s,0n),+0s,2299161j)>
first_of_month = (today - today.day) + 1
first_of_month # => #<Date: 2013-07-01 ((2456475j,0s,0n),+0s,2299161j)>
next_month = today + 31 # => #<Date: 2013-08-03 ((2456508j,0s,0n),+0s,2299161j)>
last_of_month = next_month - next_month.day # => #<Date: 2013-07-31 ((2456505j,0s,0n),+0s,2299161j)>
last_of_month # => #<Date: 2013-07-31 ((2456505j,0s,0n),+0s,2299161j)>
Entry.where(:date => [first_of_month .. last_of_month]).sum(:duration)
I'd show you the SQL output, but I don't know the database type you're using, and, well, I'm lazy.
Often, you can play tricks inside the DB by truncating "now" to remove the day, then finding all timestamps whose truncated date matches it. That's a lot more specific to the DBM than using Sequel, which already knows how to deal with ranges when converting them to a "between"-type statement.

Ruby DateTime.Parse to local time

I have a date string 20101129220021, so I will use
require 'date'
d = DateTime.parse('20101129220021')
This part works fine, and I get a date, which is in UTC.
My question is, how can I convert this into my local time? I tried many methods like extracting the time part using d.to_time and manipulate the result, but it didn't work. As far as I know, DateTime object is immutable. Can I please get some help?
irb(main):001:0> require "date"
=> true
irb(main):002:0> d = DateTime.parse('20101129220021')
=> #<DateTime: 2010-11-29T22:00:21+00:00 (70719276007/28800,0/1,2299161)>
irb(main):003:0> d.to_time
=> 2010-11-30 00:00:21 +0200
ruby 1.9.2p180 (2011-02-18)
You can add a rational fraction based on the timezone to get the local time.
require 'date'
# Make this whatever your zone is. Using UTC +0300 here.
ZONE = 3
d = DateTime.parse('20101129220021') + Rational(ZONE,24)
d.to_s # => "2010-11-30T01:00:21+00:00"

Make Date#parse assume a US format instead of an EU format

With 1.9.2p0, Date#parse assumes an UE format. Check out format.rb, line: 1042 if you don't believe me.
Anyways, how can I make it assume a US format, so that:
> Date.parse("10/4/2010")
=> Mon, 04 Oct 2010
Instead of April 10th.
I've tried this:
class Date
def _parse_eu(str,e)
_parse_us(str,e)
end
end
but no luck. Any other ideas?
Date.strptime is what you want but unfortunately it doesn't look like the documentation has the date formatting strings. I got the following to work based on Googling for the format strings:
1.9.2 > d = Date.strptime("10/4/2010", "%m/%d/%Y")
=> #<Date: 2010-10-04 (4910947/2,0,2299161)>
1.9.2 > d.day
=> 4
1.9.2 > d = Date.strptime("10/4/2010", "%d/%m/%Y")
=> #<Date: 2010-04-10 (4910593/2,0,2299161)>
1.9.2 > d.day
=> 10
You might want to check out strptime instead.

Resources