I have date-time represented in string format like below in the input data I'm getting. I need to convert this to epoch time local. How do I go about this ?
example date-time string
str = "Aug 23 2018 03:49:17:017 PM IST"
Maybe this can put you on track.
Please refer to http://ruby-doc.org/stdlib-2.5.0//libdoc/date/rdoc/DateTime.html.
This is a usage example.
require 'date'
str = "Aug 23 2018 03:49:17:017 PM IST"
d = DateTime.strptime(str, '%b %d %Y %I:%M:%S:%L %p %z')
# Maybe you need %e - Day of the month, blank-padded ( 1..31) instead of %d - Day of the month, zero-padded (01..31)
p d.hour # => 15
p d.min # => 49
p d.sec # => 17
p d.second_fraction # => (17/1000)
p d.day # => 23
p d.month # => 8
p d.year # => 2018
p d.zone # => "+05:30"
# this way you can switch timezone
d = d.new_offset('utc')
p d.zone # => "+00:00"
p d.hour # => 10
d = d.new_offset('brt')
p d.hour # => 7
p d.zone # => "-03:00"
# to print back as string, use strftime:
p d.strftime('%Y-%m-%d %I:%M:%S %z') # => "2018-08-23 07:19:17 -0300"
Related
I am trying to use the case statement:
week # => "03 – 09 MAR 2019"
first_day = week.slice(0..2) # => 03
last_day = week.slice(5..7) # => 09
month = week.slice(8..11) # => MAR
year = week.slice(12..17) # => 2019
puts month # >> MAR
case month
when 'JAN' then month_num = '01'
when 'FEB' then month_num = '02'
when 'MAR' then month_num = '03'
when 'APR' then month_num = '04'
when 'MAY' then month_num = '05'
when 'JUN' then month_num = '06'
when 'JUL' then month_num = '07'
when 'AGO' then month_num = '08'
when 'SEP' then month_num = '09'
when 'OCT' then month_num = '10'
when 'NOV' then month_num = '11'
when 'DEC' then month_num = '12'
else month_num = 'ERROR'
end
puts month_num # >> ERROR
However, the case statement always goes to the else branch.
Why is the var month_num equal to the string "ERROR" instead of "03"?
You are using puts to examine what you have, and therefore you are missing to observe whitespaces in your results. You actually have:
week.slice(0..2) # => "03 "
week.slice(5..7) # => "09 "
week.slice(8..11) # => "MAR "
week.slice(12..17) # => "2019"
To observe what you have, it is better to use p rather than puts.
You have the wrong range. Actually, there is no reason to use ranges here. It is much easier to use the second argument to specify the length:
week.slice(0, 2) # => "03"
week.slice(5, 2) # => "09"
week.slice(8, 3) # => "MAR"
week.slice(12, 4) # => "2019"
Your month is "MAR "
Try
month = week.slice(8..10)
And makes sense, from 8 to 10 inclusive are three characters. Same for the other parts.
Seems like you want to parse a string containing data in a specific format. Instead of relying on absolute indices, you could use a regular expression to match the date format, e.g:
PATTERN = /
(?<first_day>\d{2}) # 2-digit first day
\s* # optional whitespace
[–-] # delimiter(s)
\s*
(?<last_day>\d{2}) # 2-digit last day
\s*
(?<month>\w{3}) # 3-letter month name
\s*
(?<year>\d{4}) # 4-digit year
/ix
To extract the data:
str = '03 – 09 MAR 2019'
m = str.match(PATTERN)
#=> #<MatchData "03 – 09 MAR 2019" first_day:"03" last_day:"09" month:"MAR" year:"2019">
m[:first_day] #=> "03"
m[:last_day] #=> "09"
m[:month] #=> "MAR"
m[:year] #=> "2019"
The results could further be fed into Date.strptime:
require 'date'
from = m.values_at(:first_day, :month, :year).join(' ') #=> "03 MAR 2019"
to = m.values_at(:first_day, :month, :year).join(' ') #=> "09 MAR 2019"
Date.strptime(from, '%d %b %Y') #=> #<Date: 2019-03-03 ...>
Date.strptime(to, '%d %b %Y') #=> #<Date: 2019-03-09 ...>
Or _strptime if you're just interested in the raw values:
Date._strptime(from, '%d %b %Y')
#=> {:mday=>3, :mon=>3, :year=>2019}
I try to parse string "01.09 2015" with "%d.%m %y", but it returns year 2020.
require 'date'
year = Time.now.year.to_s # => "2015"
ny = (Time.now.year+1).to_s # => "2016"
sem = "01.09"
Date.strptime(sem+" "+year, "%d.%m %y")
# => #<Date: 2020-09-01 ((2459094j,0s,0n),+0s,2299161j)>
I don't get what's happening here.
You need to replace %y (meaning year % 100 (00..99)) with %Y (4 digits year):
Date.strptime("01.09 2015", "%d.%m %Y")
dates = ["11/12/08 10:47", "11/12/08 13:23", "11/12/08 13:30",
"11/25/08 19:21", "2/2/09 11:29", "11/12/08 15:00"]
This throws an invalid argument error:
dates.each do |date|
d = Date.parse(date)
d.mon
end
#=> ArgumentError: invalid date
But take the first date in dates and this is the output:
d = Date.parse('11/12/08 10:47')
puts d.mon
#=> #<Date: 2011-12-08 ((2455904j,0s,0n),+0s,2299161j)>
#=> 12 but this should be 11
In the first example why am I getting an invalid ArgumentError?
In example 2, why is the Date object created with the mon and day swapped?
Given your input, Date.parse is parsing your dates assuming they are in the format YY/MM/DD, so when it try to parse 11/25/08 it fails because 25 is not a valid month:
d = Date.parse('11/12/08 10:47')
d.year
# => 2011
d.month
# => 12
d.day
# => 8
Date.parse('11/25/08 19:21')
# ArgumentError: invalid date
Given that your dates are all in the same format, you should use the Date.strptime method instead:
d = Date.strptime('11/12/08 10:47', '%m/%d/%y')
d.year
# => 2008
d.month
# => 11
d.day
# => 12
Date.strptime('11/25/08 19:21', '%m/%d/%y')
# => #<Date: 2008-11-25 ((2454796j,0s,0n),+0s,2299161j)>
Edit Instead of the format string %m/%d/%y the shortcut %D can be used:
Date.strptime('11/25/08 19:21', '%D')
# => #<Date: 2008-11-25 ((2454796j,0s,0n),+0s,2299161j)>
Ruby's Date.parse is expecting either a YYYY-MM-DD (see also ISO8601 for more information) or a DD-MM-YYYY as well but not DD-MM-YY (i.e. 2 digits only for year). The last is treated instead as YY-MM-DD.
How would I return the string between two string markers of a string in Ruby?
For example I have:
input_string
str1_markerstring
str2_markerstring
Want to do something like:
input_string.string_between_markers(str1_markerstring, str2_markerString)
Example text:
s
# => "Charges for the period 2012-01-28 00:00:00 to 2012-02-27 23:59:59:<br>\nAny Network Cap remaining: $366.550<br>International Cap remaining: $0.000"
str1_markerstring
# => "Charges for the period"
str2_markerstring
# => "Any Network Cap"
s[/#{str1_markerstring}(.*?)#{str2_markerstring}/, 1]
# => nil # IE DIDN'T WORK IN THIS CASE
Using Ruby 1.9.3.
input_string = "blahblahblahSTARTfoofoofooENDwowowowowo"
str1_markerstring = "START"
str2_markerstring = "END"
input_string[/#{str1_markerstring}(.*?)#{str2_markerstring}/m, 1]
#=> "foofoofoo"
or to put it in a method:
class String
def string_between_markers marker1, marker2
self[/#{Regexp.escape(marker1)}(.*?)#{Regexp.escape(marker2)}/m, 1]
end
end
"blahblahblahSTARTfoofoofooENDwowowowowo".string_between_markers("START", "END")
#=> "foofoofoo"
Just split it twice and get the string between the markers:
input_string.split("str1_markerstring").last.split("str2_markerstring").first
Here's some alternate ways to do what you want, that are how I'd go about it:
s = "Charges for the period 2012-01-28 00:00:00 to 2012-02-27 23:59:59:<br>\nAny Network Cap remaining: $366.550<br>International Cap remaining: $0.000" # => "Charges for the period 2012-01-28 00:00:00 to 2012-02-27 23:59:59:<br>\nAny Network Cap remaining: $366.550<br>International Cap remaining: $0.000"
dt1, dt2 = /period (\S+ \S+) to (\S+ \S+):/.match(s).captures # => ["2012-01-28 00:00:00", "2012-02-27 23:59:59"]
dt1 # => "2012-01-28 00:00:00"
dt2 # => "2012-02-27 23:59:59"
This is using "period" and "to" and the trailing ":" to mark the begin and end of the range to be searched for, and grabbing the non-whitespace characters that signify the date and time in each datetime stamp.
Alternately, using "named-captures" predefines the variables:
/period (?<dt1>\S+ \S+) to (?<dt2>\S+ \S+):/ =~ s # => 16
dt1 # => "2012-01-28 00:00:00"
dt2 # => "2012-02-27 23:59:59"
From that point, if you want to break down the values returned you could parse them as dates:
require 'date'
d1 = DateTime.strptime(dt1, '%Y-%m-%d %H:%M:%S') # => #<DateTime: 2012-01-28T00:00:00+00:00 ((2455955j,0s,0n),+0s,2299161j)>
d1.month # => 1
d1.day # => 28
Or you could even use sub-captures:
matches = /period (?<dt1>(?<date1>\S+) (?<time1>\S+)) to (?<dt2>(?<date2>\S+) (?<time2>\S+)):/.match(s)
matches # => #<MatchData "period 2012-01-28 00:00:00 to 2012-02-27 23:59:59:" dt1:"2012-01-28 00:00:00" date1:"2012-01-28" time1:"00:00:00" dt2:"2012-02-27 23:59:59" date2:"2012-02-27" time2:"23:59:59">
matches['dt1'] # => "2012-01-28 00:00:00"
matches['date1'] # => "2012-01-28"
matches['time2'] # => "23:59:59"
This is all documented in the Regexp documentation.
In C#, There is a method AddDays([number of days]) in DateTime class.
Is there any kind of method like this in ruby?
The Date class provides a + operator that does just that.
>> d = Date.today
=> #<Date: 4910149/2,0,2299161>
>> d.to_s
=> "2009-08-31"
>> (d+3).to_s
=> "2009-09-03"
>>
In Rails there are very useful methods of Fixnum class for this (here n is Fixnum. For example: 1,2,3.... ):
Date.today + n.seconds # you can use 1.second
Date.today + n.minutes # you can use 1.minute
Date.today + n.hours # you can use 1.hour
Date.today + n.days # you can use 1.day
Date.today + n.weeks # you can use 1.week
Date.today + n.months # you can use 1.month
Date.today + n.years # you can use 1.year
These are convenient for Time class too.
PS: require Active Support Core Extensions to use these in Ruby
require 'active_support/core_ext'
I think next_day is more readable than + version.
require 'date'
DateTime.new(2016,5,17)
# => #<DateTime: 2016-05-17T00:00:00+00:00 ((2457526j,0s,0n),+0s,2299161j)>
DateTime.new(2016,5,17).next_day(10)
# => #<DateTime: 2016-05-27T00:00:00+00:00 ((2457536j,0s,0n),+0s,2299161j)>
Date.new(2016,5,17)
# => #<Date: 2016-05-17 ((2457526j,0s,0n),+0s,2299161j)>
Date.new(2016,5,17).next_day(10)
# => #<Date: 2016-05-27 ((2457536j,0s,0n),+0s,2299161j)>
http://ruby-doc.org/stdlib-2.3.1/libdoc/date/rdoc/Date.html#method-i-next_day.
From the Date class:
+(n)
Return a new Date object that is n days later than the current one.
n may be a negative value, in which case the new Date is earlier than the current one; however, #-() might be more intuitive.
If n is not a Numeric, a TypeError will be thrown. In particular, two Dates cannot be added to each other.
Date.new(2001,9,01).next_day(30) # 30 - numbers of day
# => #<Date: 2001-10-01 ...
You can also use the advance (https://apidock.com/rails/DateTime/advance) method. I think it's more legible.
date = Date.today
# => Fri, 25 Oct 2019
date.advance(days: 10)
# => Mon, 04 Nov 2019
time = DateTime.now
# => Fri, 25 Oct 2019 14:32:53 +0200
time.advance(months:1, weeks: 2, days: 2, hours: 6, minutes: 6, seconds: 34)
# => Wed, 11 Dec 2019 20:39:27 +0200