timex
timex copied to clipboard
Half/Quarter hour timezones are treated as invalid timezones
Thanks for this great library!
###Steps to reproduce
iex(1)> time = "2017-01-02T02:00:00+08:45"
"2017-01-02T02:00:00+08:45"
iex(2)> {:ok, date } = Timex.parse(time, "{ISO:Extended:Z}")
{:ok, #<DateTime(2017-01-02T02:00:00+08:45 Etc/GMT-8:45)>}
iex(3)> Timex.shift(date, hours: -2)
** (FunctionClauseError) no function clause matching in Timex.Timezone.parse_offset/1
(timex) lib/timezone/timezone.ex:232: Timex.Timezone.parse_offset("8:45")
(timex) lib/timezone/timezone.ex:204: Timex.Timezone.do_get/3
(timex) lib/timezone/timezone.ex:353: Timex.Timezone.resolve/3
(timex) lib/datetime/datetime.ex:406: Timex.Protocol.DateTime.shift_by/3
(timex) lib/datetime/datetime.ex:249: Timex.Protocol.DateTime.apply_shifts/2
Description of issue
- What are the expected results? ** +08:45 Is a valid offset. ** https://en.wikipedia.org/wiki/UTC%2B08:45
Thanks!
I've hit this too, coming out of Timex.Timezone.convert/2. Various different formats work until:
- there's a leading
+or-, and - there's a
0prefixed on the hour, and - the minutes are something other than
00
(examples run with Timex version 3.2.1, have also seen on 3.1.24)
iex(5)> Timex.Timezone.convert(Timex.now(), "+9:00")
#DateTime<2018-03-08 07:58:18.550392+09:00 +09 Etc/GMT-9>
iex(6)> Timex.Timezone.convert(Timex.now(), "9:00")
{:error, {:invalid_timezone, {:error, {:invalid_timezone, "9:00"}}}}
iex(7)> Timex.Timezone.convert(Timex.now(), "09:00")
{:error, {:invalid_timezone, {:error, {:invalid_timezone, "09:00"}}}}
iex(8)> Timex.Timezone.convert(Timex.now(), "-9:00")
#DateTime<2018-03-07 13:58:27.650314-09:00 -09 Etc/GMT+9>
iex(9)> Timex.Timezone.convert(Timex.now(), "-09:00")
#DateTime<2018-03-07 13:58:29.797884-09:00 -09 Etc/GMT+9>
iex(10)> Timex.Timezone.convert(Timex.now(), "+09:00")
#DateTime<2018-03-08 07:58:34.237682+09:00 +09 Etc/GMT-9>
iex(11)> Timex.Timezone.convert(Timex.now(), "+9:30")
#DateTime<2018-03-08 07:58:42.181430+09:00 +09 Etc/GMT-9>
iex(12)> Timex.Timezone.convert(Timex.now(), "9:30")
{:error, {:invalid_timezone, {:error, {:invalid_timezone, "9:30"}}}}
iex(13)> Timex.Timezone.convert(Timex.now(), "-9:30")
#DateTime<2018-03-07 13:58:51.213119-09:00 -09 Etc/GMT+9>
iex(14)> Timex.Timezone.convert(Timex.now(), "-09:30")
** (FunctionClauseError) no function clause matching in Timex.Timezone.parse_offset/1
The following arguments were given to Timex.Timezone.parse_offset/1:
# 1
"9:30"
Attempted function clauses (showing 10 out of 10):
defp parse_offset(<<48::integer(), h2::utf8(), 58::integer(), m1::utf8(), m2::utf8(), 58::integer(), s1::utf8(), s2::utf8()>>)
defp parse_offset(<<h1::utf8(), h2::utf8(), 58::integer(), m1::utf8(), m2::utf8(), 58::integer(), s1::utf8(), s2::utf8()>> = suffix)
defp parse_offset(<<48::integer(), h2::utf8(), 58::integer(), m1::utf8(), m2::utf8()>>)
defp parse_offset(<<h1::utf8(), h2::utf8(), 58::integer(), m1::utf8(), m2::utf8()>> = suffix)
defp parse_offset(<<48::integer(), h2::utf8()>>)
defp parse_offset(<<h1::utf8(), h2::utf8()>> = suffix)
defp parse_offset(<<h1::utf8(), h2::utf8(), 46::integer(), rest::binary()>>)
defp parse_offset(<<h2::utf8(), 46::integer(), rest::binary()>>)
defp parse_offset("0")
defp parse_offset(<<h1::utf8()>> = suffix)
(timex) lib/timezone/timezone.ex:232: Timex.Timezone.parse_offset/1
(timex) lib/timezone/timezone.ex:193: Timex.Timezone.do_get/3
(timex) lib/timezone/timezone.ex:420: Timex.Timezone.convert/2
iex(14)> Timex.Timezone.convert(Timex.now(), "+09:30")
** (FunctionClauseError) no function clause matching in Timex.Timezone.parse_offset/1
The following arguments were given to Timex.Timezone.parse_offset/1:
# 1
"9:30"
Attempted function clauses (showing 10 out of 10):
defp parse_offset(<<48::integer(), h2::utf8(), 58::integer(), m1::utf8(), m2::utf8(), 58::integer(), s1::utf8(), s2::utf8()>>)
defp parse_offset(<<h1::utf8(), h2::utf8(), 58::integer(), m1::utf8(), m2::utf8(), 58::integer(), s1::utf8(), s2::utf8()>> = suffix)
defp parse_offset(<<48::integer(), h2::utf8(), 58::integer(), m1::utf8(), m2::utf8()>>)
defp parse_offset(<<h1::utf8(), h2::utf8(), 58::integer(), m1::utf8(), m2::utf8()>> = suffix)
defp parse_offset(<<48::integer(), h2::utf8()>>)
defp parse_offset(<<h1::utf8(), h2::utf8()>> = suffix)
defp parse_offset(<<h1::utf8(), h2::utf8(), 46::integer(), rest::binary()>>)
defp parse_offset(<<h2::utf8(), 46::integer(), rest::binary()>>)
defp parse_offset("0")
defp parse_offset(<<h1::utf8()>> = suffix)
(timex) lib/timezone/timezone.ex:232: Timex.Timezone.parse_offset/1
(timex) lib/timezone/timezone.ex:204: Timex.Timezone.do_get/3
(timex) lib/timezone/timezone.ex:420: Timex.Timezone.convert/2
I suggest changing the title of the issue to: "Half/Quarter hour timezones are treated as invalid timezones".
My example:
> {:ok, dt} = Timex.parse("2018-05-21T23:59:59.999+09:30", "{ISO:Extended:Z}")
{:ok, #DateTime<2018-05-21 23:59:59.999+09:30 +09:30 Etc/GMT-9:30>}
> Timex.to_datetime(~N[2018-05-21 00:00:00], dt.time_zone)
{:error, {:invalid_timezone, "Etc/GMT-9:30"}}
Was this fixed? Is this a problem in the tzdata package or Timex itself?
Something seems to have been fixed. I can't reproduce my original error now:
iex(2)> Timex.Timezone.convert(Timex.now(), "-09:30")
#DateTime<2020-08-10 15:44:14.712366-09:30 -09:30 Etc/GMT+9:30>
iex(3)> Timex.Timezone.convert(Timex.now(), "+09:30")
#DateTime<2020-08-11 10:44:23.840286+09:30 +09:30 Etc/GMT-9:30>