Ruby's strftime not displaying timezone offset with '%Z'
The format directive %Z
requests the symbolic time zone (name or abbreviation); %z
is the offset. While you always know the offset, you may not know the symbolic time zone name.
I suspect that's what's going on with display_time
. It was initialized with an offset, so it doesn't have any symbolic time zone name to display.
You can't reliably derive a name from an offset, either; for example, -0400 could be Atlantic Standard Time or Eastern Daylight Time. Most offsets will have more than one option for what time zone they are, and most time zones have more than one name anyway.
strftime(%Z) returns wrong result
Sadly, it seems there is no 'FJT' abbreviation assigned to 'Fiji' in timezone data used by Rails. Also, support for those abbreviations seems patchy regarding Pacific timezones.
irb(main):002:0> DateTime.now.in_time_zone('Samoa').strftime('%Z')
=> "+13"
irb(main):003:0> DateTime.now.in_time_zone('Midway Island').strftime('%Z')
=> "SST"
irb(main):004:0> DateTime.now.in_time_zone('Samoa').strftime('%Z')
=> "+13"
irb(main):005:0> DateTime.now.in_time_zone('Tokelau Is.').strftime('%Z')
=> "+13"
irb(main):006:0> DateTime.now.in_time_zone('Wellington').strftime('%Z')
=> "NZST"
UTC offset is displayed as fallback. If it's any help, remember that full name and additional information can be retrieved with .time_zone.tzinfo
on ActiveSupport::TimeWithZone
objects. 'FJ' code is recognized by TZInfo::Country
.
irb(main):056:0> TZInfo::Country.get('FJ')
=> #<TZInfo::Country: FJ>
irb(main):057:0> TZInfo::Country.get('FJ').zone_info
=> [#<TZInfo::CountryTimezone: Pacific/Fiji>]
Why is %Z giving me the numeric offset instead of the abbreviated time zone name in Ruby?
From the strftime docs for rails, says it's working as intended.
Time zone:
%z - Time zone as hour and minute offset from UTC (e.g. +0900)
%:z - hour and minute offset from UTC with a colon (e.g. +09:00)
%::z - hour, minute and second offset from UTC (e.g. +09:00:00)
%:::z - hour, minute and second offset from UTC
(e.g. +09, +09:30, +09:30:30)
%Z - Equivalent to %:z (e.g. +09:00)
If you have the actual timezone name you can use that to get the abbreviation as outline here in the blog post
def human_timezone(time_string, timezone)
time = time_string.in_time_zone(timezone)
if time.zone.match?(/^\w/)
time.zone
else
time.formatted_offset
end
end
>> human_timezone('2019-03-28 16:00', 'Pacific Time (US & Canada)')
=> "PDT"
>> human_timezone('2019-03-28 16:00', 'Berlin')
=> "CET"
>> human_timezone('2019-05-01 16:00', 'Almaty')
=> "+06:00"
Different output for DateTime.strftime vs Time.strftime for timezone abbreviations
The documentation on DateTime#strftime
a bit unclear:
%Z
— Time zone abbreviation name or something similar information.
To make it possible to show the offset both ways, DateTime
shows the numeric value. To retrieve the abbreviated name, one should explicitly cast DateTime
object to Time
:
▶ DateTime.now.to_time.strftime("%Z")
#⇒ "CET"
Ruby: now.strftime(%a, %d %b %Y %X %z) gives wrong time
You should convert this time in a specific timezone. like:
time_zone = ActiveSupport::TimeZone.new(your_desire_time_zone)
converted_time = time.in_time_zone(time_zone)
or convert in UTC
converted_time = Time.now.utc
Then try to use strftime
converted_time.strftime("%a, %d %b %Y %X %z")
For more details, find here. Thanks.
Ruby strftime: Month without leading zero?
Some versions of strftime
do allow prefixing with minus to format out leading zeros, for eg:
strftime "%-d/%-m/%y"
However this will depend on strftime
on your system. So for consistency I would do something like this instead:
dt = Time.local(2010, 'Sep', 1)
printf "%d/%d/%d", dt.day, dt.month, dt.year
How to correctly set time format in strftime method?
If you stored time in your database in UTC than that time will always be in UTC when you fetch it. You need to display it according to user's local time zone. You have to do that using JavaScript, check this article.
Or if you need just Kiev time zone and nothing else you can do something like this:
<%= message.created_at.in_time_zone('Europe/Kiev').strftime("%H:%M") %>
Related Topics
Validate Japanese Character in Active Record Callback
Rvm Install Ruby-1.9.3-P286: Error Running 'Make -J 9' (Osx: Mountain Lion)
Exec Onlyif Registry Value Is Not Present
Closures and for Loops in Ruby
Ruby Net/Http Opening Connection Very Slow
Check If Folder Exist in S3 Bucket
How to Write Down the Rspec to Test Rescue Block
Rails: Parameterfilter::Compiled_Filter Tries to Dup Symbol
Is It Acceptable Having Parameter in Class Constructor
Ncurses to External Shell and Back Messing with Keys
Get Instance Variable Name from Itself in Ruby
Detect When a Devise Session Expires
Ruby/Rails - How to Validate Against Decimal Scale
Sort an Array in Ruby Ignoring Articles ("The", "A", "An")
Is It a Good Idea to Pass a Huge String as an Argument to Sidekiq Worker