Feature #14850
closedAdd official API for setting timezone on Time
Description
Only way of setting zone on a Time object appears to be via marshalling and messing with ENV.
>> ENV['TZ'] = 'America/New_York'
>> Time.now.zone
=> "EDT"
>> ENV['TZ'] = 'Europe/London'
>> Time.now.zone
=> "BST"
Is there any particular reason there is no direct, supported API for setting timezone?
ActiveSupport carries http://api.rubyonrails.org/v5.1/classes/ActiveSupport/TimeWithZone.html for this exact reason, it would be nice for core Ruby to support this out-of-the-box
Updated by shevegen (Robert A. Heiler) over 6 years ago
I agree in regards to it being odd that in an OOP-centric language
we have to fiddle with environment variables.
Irrelevant fun fact:
I once set TZ as "alias" (well, export TC= some value) towards '.tar.gz'
or something like that in the bash shell. Turns out that was not good
for when you want to compile programs from source in bash ... things
failed to compile/work past that point. :)
There are quite a few environment variables that can induce an
odd behaviour. This is not so much related to your issue request
but I can completely understand where you are coming from,
because while manipulating ENV works (I use it to modify CFLAGS
for example, in the ruby-project that I use to compile programs
from source), it's not extremely elegant.
So personally, I agree with your general issue request about
having some way to set the timezone. I don't care so much
where it resides (Time, Date... whatever, though the fewer
cases where time-related information is stored, the better).
API-wise, though, I think the ActiveSupport API or choice of
name is bad.
ActiveSupport::TimeWithZone
I am not sure about:
Time.zone =
But I think that this is mostly a detail that can be expanded
on when matz/the ruby core team would approve of this.
Some of the API in ActiveSupport is weird to me though.
This one for example:
Time.zone.parse('2007-02-10 15:30:45')
I am not sure this should exist in core ruby. People will
be confused as to Time.parse() versus Time.zone.parse()
so I don't think this is great ...
There is one thing for you to consider in the request, because
what happens in regards to backwards compatibility? Some people
may rely on that ENV behaviour. So the method should also clearly
state whether it will modify ENV, or have no effect on ENV (but
in that case, what happens when people modify ENV['TZ'] - will
that have an impact?)
I think these details have to be added into the issue request.
Perhaps as a compromise an argument could be used to denote
this, with the default argument retaining the old behaviour
as-is, whereas people who want an API + method need to pass
some additional argument to it.
Updated by nobu (Nobuyoshi Nakada) over 6 years ago
Here is a patch to extend Time.new
and Time#getlocal
for timezone support.
A timezone object should have local_to_utc
, utc_to_local
and utc_offset
methods, like timezone gem.
Updated by nobu (Nobuyoshi Nakada) about 6 years ago
- Status changed from Open to Closed
Applied in changeset trunk|r64952.
Timezone support by Time [Feature #14850]
-
strftime.c (rb_strftime): support timezone object by
%z
. -
time.c (time_init_1, time_new_timew, time_getlocaltime): accept
timezone object asoff
.
Updated by nobu (Nobuyoshi Nakada) about 6 years ago
sam.saffron (Sam Saffron) wrote:
Is there any particular reason there is no direct, supported API for setting timezone?
Because there is no standard in POSIX or similar.
Even the tz database provides data files only, not API.
ActiveSupport carries http://api.rubyonrails.org/v5.1/classes/ActiveSupport/TimeWithZone.html for this exact reason, it would be nice for core Ruby to support this out-of-the-box
I don't think we adopt that API directly.
Instead we'll provide "rawer" methods, Time.new
and Time#getlocal
with a timezone object.
I adjusted the interface for conversion between local and UTC times, to "tzinfo" and "timezone" gems.
I think methods of Time.zone
and Time#in_time_zone
would be able to implement with these features.
Some issues:¶
I'm wondering a couple of issues, any suggestions are welcome.
timezone argument to Time.at
Time.at
already has the fraction second and its unit arguments.
To add another optional argument feels complicated, or a keyword argument?
Or, is Time.at(time).localtime(tz)
suffice?
look-up timezone by the name¶
With "tzinfo" gem, Time.new(Y, M, D, h, m, s, TZInfo::Timezone.get(zone_name))
, and
with "timeone" gem, Time.new(Y, M, D, h, m, s, Timezone[zone_name])
are possible but not handy.
Time.new(Y, M, D, h, m, s, zone_name)
feels preferable, but I don't want to couple them tightly.
Or leave it to gems?
This also affects marshaling.
Marshal.dump
writes the zone name only right now, and Marshal.load
loads it as a fixed offset Time
.
I think it would be better to be converted to a timezone object.
Updated by nobu (Nobuyoshi Nakada) about 6 years ago
Here're my plans.
timezone argument to
Time.at
Time.at
already has the fraction second and its unit arguments.
To add another optional argument feels complicated, or a keyword argument?
To add in
keyword argument.
Time.at(1540000000, in: Timezone.fetch("Asia/Colombo")) #=> 2018-10-20 07:16:40 +0530
look-up timezone by the name¶
With "tzinfo" gem,
Time.new(Y, M, D, h, m, s, TZInfo::Timezone.get(zone_name))
, and
with "timeone" gem,Time.new(Y, M, D, h, m, s, Timezone[zone_name])
are possible but not handy.
Time.new(Y, M, D, h, m, s, zone_name)
feels preferable, but I don't want to couple them tightly.
If find_timezone
class method is defined, it will be called with the zone_name
argument.
Any options?
If no objection, I'll commit the above features.