Reputation: 43
I have an array with multiple dates and times:
[ "24/Oct/2014:13:43:15 -0600",
"25/Oct/2014:14:47:25 -0600",
"24/Oct/2014:13:46:15 -0600" ]
I've been trying to get.
["24/Oct/2014", "25/Oct/2014", "24/Oct/2014"]
I have tried using gsub
to replace what's not needed with a blank space, but it's only removed the colons. How could I remove this?
Upvotes: 0
Views: 599
Reputation: 110735
arr = ["24/Oct/2014:13:43:15 -0600",
"05/Oct/2014:14:47:25 -0600",
"24/Oct/2014:13:46:15 -0600"]
If you are certain that the format of the date strings will be correct, and represent valid dates, you can simply write
arr.map { |s| s[0,11] }
#=> ["24/Oct/2014", "05/Oct/2014", "24/Oct/2014"]
On the other hand, if you wish to check the validity of the date strings, you may wish to convert each date string to a date object, then convert that object to the desired string format. That way, an exception will be raised if a date string is invalid.
require 'date'
arr.map { |s| DateTime.strptime(s, '%d/%b/%Y:%H:%M:%S %z').strftime('%d/%b/%Y') }
#=> ["24/Oct/2014", "05/Oct/2014", "24/Oct/2014"]
This uses the methods DateTime::strptime and DateTime#strftime. Date format strings are explained in the doc for strftime
.
Suppose
arr = ["42/Oct/2014:13:43:15 -0600"]
then
arr.map { |s| DateTime.strptime(s, '%d/%b/%Y:%H:%M:%S %z').strftime('%d/%b/%Y') }
#=> ArgumentError: invalid date
You could instead use DateTime::parse instead of strptime
to convert date strings to Date
objects, but it is quite weak at identifying invalid dates. For example:
DateTime.parse "123456/01-02abc"
#=> #<DateTime: 123456-01-02T00:00:00+00:00 ((46812439j,0s,0n),...
DateTime.parse "-7/8"
#=> #<DateTime: 2016-07-08T00:00:00+00:00 ((2457578j,0s,0n),...
DateTime.parse "He demanded 1/2 of the pie"
#=> #<DateTime: 2016-01-02T00:00:00+00:00 ((2457390j,0s,0n),...
Upvotes: 1
Reputation: 84423
There are a lot of ways to manipulate date strings as String objects. In your case, two such options include String#partition and String#match. For example:
dates = [
"24/Oct/2014:13:43:15 -0600",
"25/Oct/2014:14:47:25 -0600",
"24/Oct/2014:13:46:15 -0600"
]
dates.map { |date| date.match(/\A[^:]+/).to_s }
dates.map { |date| date.partition(?:)[0] }
Both methods will return an array of strings like the following:
#=> ["24/Oct/2014", "25/Oct/2014", "24/Oct/2014"]
The main problem with dealing with dates like this as String objects is that you're assuming that the string representation will always be the same. If you know your data, that's fine, but it's often better to treat dates as dates. For example, you can use Date#parse, with or without Date#strftime, to automagically handle common representations as follows:
require 'date'
# Remove #to_s if you want to return actual Date objects for
# further processing, rather than an array of strings.
dates.map { |date| Date.parse(date).to_s }
#=> ["2016-10-24", "2016-10-25", "2016-10-24"]
# This will only return strings, but that's what you originally
# asked for.
dates.map { |date| Date.parse(date).strftime '%d/%b/%Y' }
#=> ["24/Oct/2016", "25/Oct/2016", "24/Oct/2016"]
The Date and DateTime libraries contain other parsers, too. Of course, if you use a non-standard input format you can use Date#strptime with a custom template.
The point here is that munging String objects works, but it's generally better to deal with dates as Date or DateTime objects to avoid edge cases, validate inputs, and to raise exceptions like:
dates.map { |date| Date.rfc2822 date }
ArgumentError: invalid date
when appropriate. You should definitely leverage core capabilities like this whenever possible.
Upvotes: 2
Reputation: 211690
Just split on :
and discard the rest:
times = [ "24/Oct/2014:13:43:15 -0600", "25/Oct/2014:14:47:25 -0600", "24/Oct/2014:13:46:15 -0600" ]
times.map do |time|
time.split(':').first
end
# => ["24/Oct/2014", "25/Oct/2014", "24/Oct/2014"]
If you want to do that in-place and modify your array, use map!
.
Upvotes: 0