Rails: Get timezone offset name - ruby-on-rails

In Ruby or Rails, given a timezone identifier like America/Los_Angeles, I see how I can get the specific timezone offset abbreviation like PDT:
Time.current.in_time_zone('America/Los_Angeles').zone
=> "PDT"
Time.now.in_time_zone("America/Los_Angeles").strftime('%Z')
=> "PDT"
Time.now.in_time_zone("America/Los_Angeles").strftime('%z')
=> "-0700"
And even a friendly name for the timezone itself:
ActiveSupport::TimeZone::MAPPING.key('America/Los_Angeles')
=> "Pacific Time (US & Canada)"
But how can I get a string like Pacific Daylight Time instead of just PDT to represent the full timezone offset name for a specific date?
Input: America/Los_Angeles and a specific date or datetime
Desired Output: Pacific Daylight Time

Short story: ~for some reason,~ (as #bata mentioned in his answer the abbreviations are not unique so this might be a reason for no official abbreviation-human friendly name mapping) The standard seems not to support it. You might need to implement this mapping yourself. But read on if you want to get some pointers why it might not be that easy.
So... this was an interesting rabbit hole to fall into...
Which gems are used and where do they get the info from
ActiveSupport uses tzinfo gem for that which in turn uses tz-info gem. tz-info says it uses one of two data sources:
zoneinfo directory in the Unix like system
TZInfo::Data
Rails' Gemfile template confirms that TZInfo data is used on window
At first I thought there might be a PR opportunity to contribute to a popular gem. Quick search suggests that there's no mapping of PDT to any "human friendly form".
Looking at unix's zoneinfo database
$ cat /usr/share/zoneinfo/America/Los_Angeles
TZif2H*ˉ#pa&t\؀Ðݩ޾߉iip~KIR^-)4GJQ',3qo_O?/v( fe HG *)
x
q(a'Q
A 0C ΐ
௠
#j$5 %J& '*'))6 "S 54+ !"V
eGYe턠g';gfiiHjke lmvG noV) pq6: XX YZ [޵\ ]^d _y`Mޠab-cgwdE G-Gӵ I
ros tOt v8vxx͠yz{f|~}H~^s*&
LMTPDTPSTPWTPPTTZif2^H*ˉ#pa&t\؀Ðݩ޾߉iip~KIR^-)4GJQ',3qo_O?/v( fe HG *)
x
q(a'Q
A 0C ΐ
௠
#j$5 %J& '*'))6 "S 54+ !"V
eGYe턠g';gfiiHjke lmvG noV) pq6: XX YZ [޵\ ]^d _y`Mޠab-cgwdE G-Gӵ I
ros tOt v8vxx͠yz{f|~}H~^s*&
LMTPDTPSTPWTPPT
PST8PDT,M3.2.0,M11.1.0
Looks like a binary file...
$ strings /usr/share/zoneinfo/America/Los_Angeles
TZif2
v+ !
2s$
3Gt 4S
5'V 62
mvG n
oV) p
TZif2
v+
3Gt
5'V
mvG
oV)
PST8PDT,M3.2.0,M11.1.0
Hmm. Whatever each of those means, there seems to be no "human friendly" name for this TZ.
More digging for unix tzinfo format, and there's apparently a zic and zdump tool
$ zdump /usr/share/zoneinfo/America/Los_Angeles
/usr/share/zoneinfo/America/Los_Angeles Thu Sep 10 03:07:49 2020 PDT
Not very useful...
$ zic /usr/share/zoneinfo/America/Los_Angeles
"/usr/share/zoneinfo/America/Los_Angeles", line 1: line too long
Ugh.
But reading the manpages for one of those tools I've found out that timezoneinfo is an official RFC 8536. I'm not great at reading those, but in the format there's header (with version only) and
data block (check it out, apparently it stores all historical changes for the TZ)
footer which seems to contain the PDT strings and alike, and nowhere is mentioned a possibility to provide "friendly" name.
If you have hard times reading an RFC, it looks like the tzinfo-data gem tries to reproduce the same data for system that does not include tzinfo databases (i.e. Windows):
https://github.com/tzinfo/tzinfo-data/blob/4ab39f022f5537b97eed133c1169f9ace3a82e2b/lib/tzinfo/data/definitions/PST8PDT.rb
timezone 'America/Los_Angeles' do |tz|
tz.offset :o0, -28378, 0, :LMT
tz.offset :o1, -28800, 0, :PST
tz.offset :o2, -28800, 3600, :PDT
tz.offset :o3, -28800, 3600, :PWT
tz.offset :o4, -28800, 3600, :PPT
tz.transition 1883, 11, :o1, -2717640000, 7227400, 3
tz.transition 1918, 3, :o2, -1633269600, 29060207, 12
tz.transition 1918, 10, :o1, -1615129200, 19375151, 8
tz.transition 1919, 3, :o2, -1601820000, 29064575, 12
tz.transition 1919, 10, :o1, -1583679600, 19378063, 8
tz.transition 1942, 2, :o3, -880207200, 29164799, 12
# ... [cut!]
Here's offset method definition: https://github.com/tzinfo/tzinfo/blob/f361d7d0b859ba5b91d30ffd6b66c3c59f90e969/lib/tzinfo/format2/timezone_definer.rb#L37:L59 (at least I think this is it, you never know until you run the code in ruby)
As you can see, no daylight saving time has :LMT and :PST abbreviations.
And here is the transition method https://github.com/tzinfo/tzinfo/blob/8c549373736a7873e18bb787b818d8786591e5e5/lib/tzinfo/format1/timezone_definer.rb#L30:L61
Feel free to explore more on your own. But it looks like each and every one transition from DST and back is supposed to be present in the tzinfo. And LA seems to have stuff planned until 2060. That's actually interesting if you'll get TZ bugs related to DST if you try to calculate times after 2060?
Last thing: Abbreviations
No idea if this is the case for unix's tzinfo db, but in the gem they are defined locally!
It seems to be the case that :PDT means the same if all definitions (https://github.com/tzinfo/tzinfo-data/search?q=%3APDT&unscoped_q=%3APDT)
But notice that
lib/tzinfo/data/definitions/Asia/Manila.rb defines positive offset tz.offset :o3, 28800, 3600, :PDT, but
lib/tzinfo/data/definitions/America/Dawson.rb defines negative offset tz.offset :o7, -28800, 3600, :PDT with the same abbreviation.
What does that mean - no idea. But that might be the reason we don't have "global friendly timezone names" anywhere.
There might be errors in the database. The official DB README says:
This database of historical local time information has several goals:
Provide a compendium of data about the history of civil time that
is useful even if not 100% accurate.
Give an idea of the variety of local time rules that have existed
in the past and thus may be expected in the future.
Test the generality of the local time rule description system.
The information in the time zone data files is by no means authoritative;
fixes and enhancements are welcome. Please see the file CONTRIBUTING
for details.

I don’t think there is a standard for abbreviations. Also, they are not unique as you see here: https://www.timeanddate.com/time/zones/

Related

What is the difference between Informix `%iY` and `%Y` format

I found in some code I maintain they used this format for an update query
UPDATE X=to_date('$var','%iY-%m-%d %H:%M:%S.%F3') ...
But I can't find anywhere in Informix documentation what the i is for. Running this next query will result the same values.
SELECT TO_CHAR(CURRENT, '%Y-%m-%d %H:%M:%S%F3') as wo_I,
TO_CHAR(CURRENT, '%iY-%m-%d %H:%M:%S%F3') as with_I FROM X;
wo_i | with_i
------------------------|------------------------
2017-06-20 16:49:44.712 | 2017-06-20 16:49:44.712
So what am I missing?
Resources I looked into:
https://www.ibm.com/support/knowledgecenter/SSGU8G_11.70.0/com.ibm.sqlt.doc/ids_sqt_130.htm
https://www.ibm.com/support/knowledgecenter/SSGU8G_11.70.0/com.ibm.sqlt.doc/ids_sqt_129.htm
http://www.sqlines.com/informix-to-oracle/to_char_datetime
It's a trifle hard to find, but one location for the information you need (assuming you use Informix 11.70 rather than 12.10, though it probably hasn't changed much) is:
Client APIs and Tools — GLS User's Guide — GLS Environment Variables
In particular, it says:
%iy — Is replaced by the year as a two-digit number (00 - 99) for both reading and printing. It is the formatting directive specific to IBM Informix for %y.
%iY — Is replaced by the year as a four-digit number (0000 - 9999) for both reading and printing. It is the formatting directive specific to IBM Informix for %Y.
…
%y — Requires that the year is a two-digit number (00 through 99) for both reading and printing.
%Y — Requires that the year is a four-digit number (0000 through 9999) for both reading and printing.
There clearly isn't much difference between the two — I'm not even sure I understand what the difference is supposed to be. I think it may be the difference between accepting but not requiring leading zeros on 1, 2 or 3 digit year numbers. But for the most part, it seems you can treat them as equivalent.

write Regex to find match

I never wrote any complex regular expression before, and what I need seems to be (at least) a bit complicated.
I need a Regex to find matches for the following:
"On Fri, Jan 16, 2015 at 4:39 PM"
Where On will always be there;
then 3 characters for week day;
, is always there;
space is always there;
then 3 characters for month name;
space is always there;
day of month (one or two numbers);
, is always there;
space is always there;
4 numbers for year;
space at space always there;
time (have to match 4:39 as well as 10:39);
space and 2 caps letters for AM or PM.
Here's a very simple and readable one:
/On \w{3}, \w{3} \d{1,2}, \d{4} at \d{1,2}:\d{2} [AP]M/
See it on rubular
Try this:
On\s+(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), (?:Jan|Feb|Mar|Apr|May|June|July|Aug|Sept|Oct|Nov|Dec) \d{1,2}, \d{4} at \d{1,2}:\d{2} (?:AM|PM)
/On \w{3}, \w{3} \d{1,2}, \d{4} at \d{1,2}:\d{1,2} [A-Z]{2}/
# \w{3} for 3 charecters
# \d{1,2} for a or 2 digits
# \d{4} for 4 digits
# [A-Z]{2} for 2 capital leters
You could try the below regex and it won't check for the month name or day name or date.
^On\s[A-Z][a-z]{2},\s[A-Z][a-z]{2}\s\d{1,2},\s\d{4}\sat\s(?:10|4):39\s[AP]M$
DEMO
You can use Rubular to construct and test Ruby Regular Expressions.
I have put together an Example: http://rubular.com/r/45RIiwheqs
Since it looks you try to parse dates, you should use Date.strptime.
/On [A-Za-z]{3}, [A-Za-z]{3} \d{1,2}, \d{4} at \d{1,2}:\d{1,2}/g
The way you are describing the problem makes me thing that the format will always be preserved.
I would then in your case use the Time.parse function, passing the format string
format = "On %a, %b"On Fri, Jan 16, 2015 at 4:39 PM", format)
which is more readable than a regexp (in my opinion) and has the added value that it returns a Time object, which is easier to use than a regexp match, in case you need to perform other time-based calculations.
Another good thing is that if the string contains an invalid date (like "On Mon, Jan 59, 2015 at 37:99 GX" ) the parse function will raise an exception, so that validation is done for free for you.

Ruby on Rails I18n - Localization of Dates Works In localhost but Not In Production

I am using Ruby on Rails 3.2.13 Ruby 1.9.3.
I have the following code in my en.yml file:
date:
formats:
default: "%Y-%m-%d"
short: "%b %d"
long: "%A, %B %d, %Y"
mmyy: "%B %Y"
I have the following code in my fr.yml file:
date:
formats:
default: "%Y-%m-%d"
short: "%b %d"
long: "%A, %d %B %Y"
mmyy: "%B %Y"
My date field media_created is stored in a string in YYYY-MM-DD format
Here is the code in my view to display the short date format in my view:
<%= l media_item.media_created.to_date, format: :mmyy %>
Here is an example of how my short format works in localhost (date 2013-07-01):
July 2013 (en)
juillet 2013 (fr)
Here is an example of how my long format works in production (date 2013-07-01):
July 2013 (en)
July 2013 (fr)
Here is the code in my view to display the long date format in my view:
<%= l media_item.media_created.to_date, format: :long %>
Here is an example of how my long format works in localhost (date 2013-06-23 which was on Sunday):
Sunday, June 23, 2013 (en)
dimanche, 23 juin 2013 (fr)
Here is an example of how my long format works in production (date 2013-06-23):
Sunday, June 23, 2013 (en)
Sunday, June 23, 2013 (fr)
I read the http://guides.rubyonrails.org/i18n.html and several examples on Stack Overflow which used the l helper as described in section 3.3. However in section 5 it talks about using the t helper for custom translations. I am using t for all my other I18n internationalization and it is working fine. The only problem is when I use the l helper for dates.
I have looked for examples of how to use the t helper as described in the link Rails Guide link. The link does not give an example of how to code a statement with a field name. All of the examples I have found in Stack Overflow are using the l helper or the strftime method. I want to be able to 'translate' the date formats like I do the rest of the application in production like it works in localhost. I have checked all the files that I have changed to do this on my production server to make sure that all the files were moved over there. From what I did read it seems like the l helper may not work that well for custom translations. Maybe using the t helper will take care of this problem which was suggested by the Rails Guide. I will keep looking to see if I can find examples using the t helper like I included here for the l helper or try and guess some solutions.
Any help would be appreciated.
UPDATE: 7/29/2013 12:47 pm CDT - The only other difference that I can see between the two servers is that the development server is running ruby 1.9.3p327 and the production server is running ruby 1.9.3p362. However I cannot believe that could be causing my problem but it is a difference that I feel I should note.
I could not find any other questions or comments relating to this. I decided to copy the fr.yml hashes for the rails-i18n gem. I did not have to do this on my development server to get the date formatting to translate into French. As I stated it was working fine without them. When I deployed the new yaml file in production all my clauses are in French. I guess there is a needle in a haystack type of bug somewhere in the i18n process. At least the Rails translations for dates are working now.

What does the 'Z' mean in Unix timestamp '120314170138Z'?

I have an X.509 certificate which has the following 2 timestamps:
['validFrom'] = String(13) "120314165227Z"
['validTo'] = String(13) "130314165227Z"
What does the postfix character 'Z' mean. Does it specify the timezone?
Yes. 'Z' stands for Zulu time, which is also GMT and UTC.
From http://en.wikipedia.org/wiki/Coordinated_Universal_Time:
The UTC time zone is sometimes denoted by the letter Z—a reference to
the equivalent nautical time zone (GMT), which has been denoted by a Z
since about 1950. The letter also refers to the "zone description" of
zero hours, which has been used since 1920 (see time zone history).
Since the NATO phonetic alphabet and amateur radio word for Z is
"Zulu", UTC is sometimes known as Zulu time.
Technically, because the definition of nautical time zones is based on longitudinal position, the Z time is not exactly identical to the actual GMT time 'zone'. However, since it is primarily used as a reference time, it doesn't matter what area of Earth it applies to as long as everyone uses the same reference.
From wikipedia again, http://en.wikipedia.org/wiki/Nautical_time:
Around 1950, a letter suffix was added to the zone description,
assigning Z to the zero zone, and A–M (except J) to the east and N–Y
to the west (J may be assigned to local time in non-nautical
applications; zones M and Y have the same clock time but differ by 24
hours: a full day). These were to be vocalized using a phonetic
alphabet which pronounces the letter Z as Zulu, leading sometimes to
the use of the term "Zulu Time". The Greenwich time zone runs from
7.5°W to 7.5°E longitude, while zone A runs from 7.5°E to 22.5°E longitude, etc.
"Z" doesn't stand for "Zulu"
I don't have any more information than the Wikipedia article cited by the two existing answers, but I believe the interpretation that "Z" stands for "Zulu" is incorrect. UTC time is referred to as "Zulu time" because of the use of Z to identify it, not the other way around. The "Z" seems to have been used to mark the time zone as the "zero zone", in which case "Z" unsurprisingly stands for "zero" (assuming the following information from Wikipedia is accurate):
Around 1950, a letter suffix was added to the zone description, assigning Z to the zero zone, and A–M (except J) to the east and N–Y to the west (J may be assigned to local time in non-nautical applications — zones M and Y have the same clock time but differ by 24 hours: a full day). These can be vocalized using the NATO phonetic alphabet which pronounces the letter Z as Zulu, leading to the use of the term "Zulu Time" for Greenwich Mean Time, or UT1 from January 1, 1972 onward.
The Z stands for 'Zulu' - your times are in UTC. From Wikipedia:
The UTC time zone is sometimes denoted by the letter Z—a reference to the equivalent nautical time zone (GMT), which has been denoted by a Z since about 1950. The letter also refers to the "zone description" of zero hours, which has been used since 1920 (see time zone history). Since the NATO phonetic alphabet and amateur radio word for Z is "Zulu", UTC is sometimes known as Zulu time. This is especially true in aviation, where Zulu is the universal standard.

Prolog: Making a procedure to print Hello World

I want to load this simple something into my Editor:
Write:-repeat,write("hi"),nl,fail.
So that it prints "hi".
What should I do?
I'm currently trying to do File->New
and Saving a file named Write into E:\Program Files\pl\xpce\prolog\lib
When doing the query:
?-Write.
It's printing:
1 ?- Write.
% ... 1,000,000 ............ 10,000,000 years later
%
% >> 42 << (last release gives the question)
Why?
EDIT
I did some more research. Apparently this is what SWI-Prolog does when you ask it about an uninstantiated variable.
$ prolog
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 5.6.64)
Copyright (c) 1990-2008 University of Amsterdam.
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- X.
% ... 1,000,000 ............ 10,000,000 years later
%
% >> 42 << (last release gives the question)
?-
UPDATE
Changing the name to lowercase works. Uppercase is for variables:
helloworld.prolog:
helloworld:-write('Hello World!'),nl,fail.
Then:
$ prolog
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 5.6.64)
Copyright (c) 1990-2008 University of Amsterdam.
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- ['helloworld.prolog'].
% helloworld.prolog compiled 0.00 sec, 1,376 bytes
true.
?- helloworld.
Hello World!
false.
?-
Notice that you have to consult the file first. I tried this out and it works for sure.
You need to name the procedure write, not Write. Upper case starting letters are for variables. (It might be less confusing if you call it something else like writeHi or something, so it doesn't have the same name as a built-in procedure, but it will still work when you call it write because your write has a different arity than the built in one).
Also you might want to replace "hi" with 'hi', though it will work either way (but only the second version will actually print the word hi to the screen - your version will print it as an integer list).

Resources