Ruby DateTime.Parse to local time - ruby

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"

Related

Determine if a past date falls in the DST range using ruby 2.4

In ruby 2.4 there was a change to how the DateTime#to_time method works. These changes have broken some existing code I had which checked if a given past datetime was in DST
The date below is in the DST range for that year. However, ruby is reporting that dst? == false. I'm pretty stumped here: without using rails how can I test the dst? value of a past datetime?
# 2016-07-27 00:00:00
unix_timestamp = 1469577600
time = Time.at(unix_timestamp).utc
pacific_time = Time.new(time.year, time.month, time.day, 0, 0, 0, "-08:00")
=> 2016-07-27 00:00:00 -0800
pacific_time.dst?
=> false
pacific_time.zone
=> nil
If your local timezone is Pacific Time, then let Time assume it:
irb(main):001:0> unix_timestamp = 1469577600
=> 1469577600
time = Time.at(unix_timestamp).utc
irb(main):004:0> pacific_time = Time.local(time.year, time.month, time.day)
=> 2016-07-27 00:00:00 -0700
irb(main):006:0> pacific_time.dst?
=> true
irb(main):007:0> pacific_time.zone
=> "PDT"
You can also get the local version of your UTC time:
irb(main):015:0> time_local = time.getlocal
=> 2016-07-26 17:00:00 -0700
irb(main):016:0> time_local.dst?
=> true
irb(main):017:0> time_local.zone
=> "PDT"
But, it may be a little brittle to depend on the local timezone without actually specifying it. If you need to display times in another timezone, different than UTC and different than the local one, then maybe Rails' in_time_zone and this related question can help.

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 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.

How do I create a Ruby date object from a string?

How do I create a Ruby date object from the following string?
DD-MM-YYYY
Date.parse('31-12-2010')
Alternatively Date#strptime(str, format).
Because in the USA they get the dates backwards, it's important not to simply use Date.parse() because you'll find 9/11/2001 can be 11 September 2001 in the USA and 9 November 2001 in the rest of the world. To be completely unambiguous use Date::strptime(your_date_string,"%d-%m-%Y") to correctly parse a date string of format dd-mm-yyyy.
Try this to be sure:
>irb
>> require 'date'
=> true
>> testdate = '11-09-2001'
=> "11-09-2001"
>> converted = Date::strptime(testdate, "%d-%m-%Y")
=> #<Date: 4918207/2,0,2299161>
>> converted.mday
=> 11
>> converted.month
=> 9
>> converted.year
=> 2001
For other strptime formats see http://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html
Also I always make sure I set my base timezone to :utc if my website is going to be handling any dates, and use Javascript on the client side to display local times.
You can use Time#parse.
Time.parse("20-08-2010")
# => Fri Aug 20 00:00:00 +0200 2010
However, because Ruby could parse the date as "MM-DD-YYYY", the best way is to go with DateTime#strptime where you can specify the input format.
If you have control over the format of the date in the string, then Date.parse works fine internationally with strings in YYYY-MM-DD (ISO 8601) format:
Date.parse('2019-11-20')
I find this approach simpler since it avoid having to specify the date format for the parser:
date1 = Time.local(2012, 1, 20, 12, 0, 0).to_date
Like this You can get time Object from a string like this:
t = Time.parse "9:00 PM"
=> 2013-12-24 21:00:00 +0530
t = Time.parse "12:00 AM"
=> 2013-12-24 00:00:00 +0530
But Ruby parsing this as a Date!
So you can use the column as a string.
add_column :table_name, :from, :string, :limit => 8, :default => "00:00 AM", :null => false
add_column :table_name, :to, :string, :limit => 8, :default => "00:00 AM", :null => false
And you can assign string object to the attribute,
r.from = "05:30 PM"
r.save
And parse the string for getting time object,
Time.zone.parse("02:00 PM")
Not necessary for this particular string format, but best string to time parsing utility I know is Chronic which is available as a gem and works for about 99.9% of usecases for human formatted dates/times.

How do I Convert DateTime.now to UTC in Ruby?

If I have d = DateTime.now, how do I convert 'd' into UTC (with the appropriate date)?
DateTime.now.new_offset(0)
will work in standard Ruby (i.e. without ActiveSupport).
d = DateTime.now.utc
Oops!
That seems to work in Rails, but not vanilla Ruby (and of course that is what the question is asking)
d = Time.now.utc
Does work however.
Is there any reason you need to use DateTime and not Time? Time should include everything you need:
irb(main):016:0> Time.now
=> Thu Apr 16 12:40:44 +0100 2009
Unfortunately, the DateTime class doesn't have the convenience methods available in the Time class to do this. You can convert any DateTime object into UTC like this:
d = DateTime.now
d.new_offset(Rational(0, 24))
You can switch back from UTC to localtime using:
d.new_offset(DateTime.now.offset)
where d is a DateTime object in UTC time. If you'd like these as convenience methods, then you can create them like this:
class DateTime
def localtime
new_offset(DateTime.now.offset)
end
def utc
new_offset(Rational(0, 24))
end
end
You can see this in action in the following irb session:
d = DateTime.now.new_offset(Rational(-4, 24))
=> #<DateTime: 106105391484260677/43200000000,-1/6,2299161>
1.8.7 :185 > d.to_s
=> "2012-08-03T15:42:48-04:00"
1.8.7 :186 > d.localtime.to_s
=> "2012-08-03T12:42:48-07:00"
1.8.7 :187 > d.utc.to_s
=> "2012-08-03T19:42:48+00:00"
As you can see above, the initial DateTime object has a -04:00 offset (Eastern Time). I'm in Pacific Time with a -07:00 offset. Calling localtime as described previously properly converts the DateTime object into local time. Calling utc on the object properly converts it to a UTC offset.
Try this, works in Ruby:
DateTime.now.to_time.utc
You can set an ENV if you want your Time.now and DateTime.now to respond in UTC time.
require 'date'
Time.now #=> 2015-11-30 11:37:14 -0800
DateTime.now.to_s #=> "2015-11-30T11:37:25-08:00"
ENV['TZ'] = 'UTC'
Time.now #=> 2015-11-30 19:37:38 +0000
DateTime.now.to_s #=> "2015-11-30T19:37:36+00:00"
In irb:
>>d = DateTime.now
=> #<DateTime: 11783702280454271/4800000000,5/12,2299161>
>> "#{d.hour.to_i - d.zone.to_i}:#{d.min}:#{d.sec}"
=> "11:16:41"
will convert the time to the utc. But as posted if it is just Time you can use:
Time.now.utc
and get it straight away.

Resources