Given an IANA time zone ID, such as "America/New_York" or "Europe/Lisbon", how can I obtain the corresponding BCP-47 time zone ID, such as "usnyc" or "ptlis", using ICU4C?
These values are required to generate Unicode BCP-47 Locale IDs with extensions, e.g. 'en-US-u-fw-mon-hc-h23-tz-usnyc".
Related
I have a use-case in which I need a user to enter an availability date on the browser (which will be saved in the database in UTC format) for example
July 2nd at 6:30PM,
i am getting IANA location string using momentjs
moment.tz.guess(); //'America/New_York'
now when I do the server side rendering, I would like to render the availability date as
July 2nd at 6:30 EST
or
July 2nd at 6:30 PMT
Is there a javascript library to do this for me? how can I convert 'America/New_York' to EST?
worth mentioning it is a reactjs application
we can achieve this by momentjs. get the IANA timezone with guess() function as explained above to set the timezone and then format it with as documented in moment documents
const date = user input date saved in the database
const z = value of moment.tz.guess() which saved in db
moment(date).tz(z).format('MM/DD/YYYY hh:mm A z');
I am running PostgreSQL 9.6.6 on x86_64-pc-linux-gnu and my time zone is set to 'UTC'.
Does anyone know why the results of the following SELECT statements are different?
A)
SELECT timezone('EST', '2017-12-21');
timezone
---------------------
2017-12-20 19:00:00
B)
SELECT timezone('-05', '2017-12-21');
timezone
---------------------
2017-12-21 05:00:00
According to the pg_timezone_names table -05 should have the same offset as EST... Any thoughts? Thanks.
https://www.postgresql.org/docs/current/static/view-pg-timezone-names.html
The view pg_timezone_names provides a list of time zone names that are
recognized by SET TIMEZONE
and further:
utc_offset interval Offset from UTC (positive means east of Greenwich)
when you set timezone to 'EST' - you declare that your client is in EST time zone, thus returned time will be adjusted for your tz:
t=# select '2017-12-21'::timestamptz;
timestamptz
------------------------
2017-12-21 00:00:00-05
(1 row)
the interval match utc_offset from pg_timezone_names and isequal -05, so it works as expected. (indeed in EST will be 5 hours less then UTC) same result if you set timezone to '-05'.
Both -05 and EST give same result for SET TIMEZONE as described in docs.
Now you answer reconciles with docs on using interval: https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-ZONECONVERT
In these expressions, the desired time zone zone can be specified
either as a text string (e.g., 'PST') or as an interval (e.g.,
INTERVAL '-08:00').
following these rules it works as well:
t=# select '2017-12-21'::timestamptz at time zone 'EST';
timezone
---------------------
2017-12-20 19:00:00
(1 row)
t=# select '2017-12-21'::timestamptz at time zone interval '-05:00';
timezone
---------------------
2017-12-20 19:00:00
(1 row)
but further, docs say:
In the text case, a time zone name can be specified in any of the ways
described in Section 8.5.3.
which is https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-TIMEZONES
PostgreSQL allows you to specify time zones in three different forms:
recognized time zone names are listed in the pg_timezone_names
recognized abbreviations are listed in the pg_timezone_abbrevs
POSIX-style time zone specifications of the form STDoffset or STDoffsetDST
(formatting mine)
and lastly:
One should be wary that the POSIX-style time zone feature can lead to
silently accepting bogus input...Another issue to keep in mind is that
in POSIX time zone names, positive offsets are used for locations west
of Greenwich. Everywhere else, PostgreSQL follows the ISO-8601
convention that positive timezone offsets are east of Greenwich.
TL;DR
So in short - when you define '-05' as text (not interval) input for timezone() function or AT TIME ZONE directive (effectively same) Postgres thinks this is an attempt to use POSIX style time zone and thus inverts sign, thus you get "opposite" result...
a simple demonstration of this documented inversion:
t=# select '2017-12-21'::timestamptz at time zone '05';
timezone
---------------------
2017-12-20 19:00:00
(1 row)
Okay I think I found an answer to my own question:
According to the PostgreSQL docs, section 9.9.3 at the following link https://www.postgresql.org/docs/9.6/static/functions-datetime.html
In these expressions, the desired time zone zone can be specified either as a text string (e.g., 'PST') or as an interval (e.g., INTERVAL '-08:00'). In the text case, a time zone name can be specified in any of the ways described in Section 8.5.3.
So using the INTERVAL syntax, the following appears to work:
SELECT timezone(INTERVAL '-05:00', '2017-12-21');
timezone
---------------------
2017-12-20 19:00:00
I think it is still curious, what exactly SELECT timezone('-05', '2017-12-21'); means, as the following also provides the expected result (with the addition of a TZ offset):
SELECT timezone('-05', '2017-12-21'::timestamp);
timezone
------------------------
2017-12-20 19:00:00+00
I'm importing an object from an API with a datetime that looks like this:
"2017-06-28 09:00:00"
This time is in the user's time zone, which is known in my application. (i.e. Pacific Time (US & Canada))
Datetimes are stored in my database as datetime format in UTC. When we display dates on the front-end, we account for the user's time zone (ie datetime.in_time_zone(user_time_zone)).
How do I save the datetime in my database correctly?
You should be able to append your apps timezone to the end of the datetime string.
time = "2017-06-28 09:00:00"
time += Time.zone.name
Parsing that will give you the time in Pacific Time (US & Canada). Or use ActiveSupport.
time_pacific = DateTime.parse(time)
### ActiveSupport version ###
time_pacific = ActiveSupport::TimeZone.new(Time.zone.name).parse("2017-06-28 09:00:00")
You can then call #utc on that to get the correct UTC time from your original string.
time_utc = time_pacific.utc
Background
Article model with default created_at column
Rails config.time_zone = 'Warsaw'
I've got an article with created_at = local time 2012-08-19 00:15 (2012-08-18 22:15 in UTC).
Goal
To receive all articles created in 2012-08-19 (in local time).
My (not working properly) solution
Article.where(
"date_trunc('day', created_at AT TIME ZONE '#{Time.zone.formatted_offset}')
= '#{Date.civil(2012, 8, 19)}'"
)
Which generates SQL:
SELECT "articles".* FROM "articles"
WHERE (date_trunc('day', created_at AT TIME ZONE '+01:00') = '2012-08-19')
And returns an empty set. But if I run the same query in psql it returns an article ... which confuses me.
Question
What am I doing wrong and how to fix it?
Goal: To receive all articles created in 2012-08-19 (in local time).
'+01:00' (like you use it) is a fixed time offset and cannot take DST (Daylight Saving Time) into account. Use a time zone name for that (not an abbreviation). These are available in PostgreSQL:
SELECT * FROM pg_timezone_names;
For Warsaw this should be 'Europe/Warsaw'. The system knows the bounds for DST from its stored information and applies the according time offset.
Also, your query can be simplified.
As created_at is a timestamp [without time zone], the values saved reflect the local time of the server when the row was created (saved internally as UTC timestamp).
There are basically only two possibilities, depending on the time zone(s) of your client.
Your reading client runs with the same setting for timezone as the writing client: Just cast to date.
SELECT *
FROM articles
WHERE created_at::date = '2012-08-19';
Your reading client runs with a different setting for timezone than the writing client: Add AT TIME ZONE '<tz name of *writing* client here>'. For instance, if that was Europe/Warsaw, it would look like:
...
WHERE (created_at AT TIME ZONE 'Europe/Warsaw')::date = '2012-08-19';
The double application of AT TIME ZONE like you have it in your posted answer should not be necessary.
Note the time zone name instead of the abbreviation. See:
Time zone names with identical properties yield different result when applied to timestamp
If you span multiple time zones with your application ..
.. set the column default of created_at to now() AT TIME ZONE 'UTC' - or some other time zone, the point being: use the same everywhere.
.. or, preferably, switch to timestamptz (timestamp with time zone).
Linked answer helped. I have to run following query:
SELECT *
FROM articles
WHERE (created_at AT TIME ZONE 'UTC' AT TIME ZONE 'CEST')::date = '2012-08-19';
This question would need the exact definition of the column created_at (what data type exactly?)
Rails always creates created_at column as timestamp without time zone. So I have to make the first AT TIME ZONE 'UTC' to say dbms that this timestamp is at UTC, and the second one to display date at CEST zone.
I have timezones in the following array format:
'America/New_York' => '(GMT-05:00) Eastern Time (US & Canada)',
'Europe/Lisbon' => '(GMT) Greenwich Mean Time : Lisbon',
etc.
How do I go about displaying a user-friendly summer/daylight savings time dependent timezone identifier to the user?
For example, displaying the time now in New York would append "(EDT)" to the time, which would make sense for local users. I want to avoid having to display ((GMT-05:00) Eastern Time (US & Canada)) or just (GMT-05:00), which isn't strictly accurate all year round.
Ideally then, is there a web service/database that can take a tz string in the format "America/New_York", and a timestamp as paramters and return the abbreviation in the formats here?
strftime's %Z format specifier gives you this abbreviation. You didn't say what programming language you are using, but most programming languages give you access to strftime in one way or another.
Python:
import pytz
from datetime import datetime
here = pytz.timezone('Asia/Tokyo')
print here.localize(datetime.utcnow()).strftime("%Z")
there = pytz.timezone('America/Montreal')
print there.localize(datetime.utcnow()).strftime("%Z")
PHP:
date_default_timezone_set("Asia/Tokyo");
echo strftime("%Z");
date_default_timezone_set("America/Montreal");
echo strftime("%Z");