Project

General

Profile

Feature #14850

Add official API for setting timezone on Time

Added by sam.saffron (Sam Saffron) 5 months ago. Updated 22 days ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:87507]

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

Associated revisions

Revision ee58c638
Added by nobu (Nobuyoshi Nakada) about 1 month ago

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

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64952 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

Revision 64952
Added by nobu (Nobuyoshi Nakada) about 1 month ago

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

History

#1 [ruby-core:87508] Updated by shevegen (Robert A. Heiler) 5 months 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.

#2 [ruby-core:88809] Updated by nobu (Nobuyoshi Nakada) 3 months 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.

#3 Updated by nobu (Nobuyoshi Nakada) about 1 month 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 as off.

#4 [ruby-core:89397] Updated by nobu (Nobuyoshi Nakada) about 1 month 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.

#5 [ruby-core:89607] Updated by nobu (Nobuyoshi Nakada) 22 days 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.

Also available in: Atom PDF