elixirtimex

`FunctionClauseError` error in `Timex.Timezone.resolve/3` when calling `Timex.Timezone.get/2` for a UTC `DateTime`


I have (what I suspect is) a UTC date-time. I'd like to convert it to my local time (the timezone named America/New_York for that date-time).

I was trying to follow the Timex docs:

> timezone = Timezone.get("America/Chicago", Timex.now)
#<TimezoneInfo(America/Chicago - CDT (-06:00:00))>

> Timezone.convert(datetime, timezone)
#<DateTime(2016-02-29T06:30:30.120-06:00 America/Chicago)>

Why is the third command shown below raising an error?

iex(1)> ~N[2019-12-02 16:27:18]                
~N[2019-12-02 16:27:18]
iex(2)> DateTime.from_naive(v(1), "Etc/UTC")
{:ok, #DateTime<2019-12-02 16:27:18Z>}
iex(3)> timezone = Timex.Timezone.get("America/New_York", v(2))
** (FunctionClauseError) no function clause matching in Timex.Timezone.resolve/3    

    The following arguments were given to Timex.Timezone.resolve/3:

        # 1
        "America/New_York"

        # 2
        {:error, :invalid_date}

        # 3
        :wall

    Attempted function clauses (showing 1 out of 1):

        def resolve(name, seconds_from_zeroyear, utc_or_wall) when is_binary(name) and is_integer(seconds_from_zeroyear) and (utc_or_wall === :wall or utc_or_wall === :utc)

    (timex) lib/timezone/timezone.ex:356: Timex.Timezone.resolve/3
iex(3)> timezone = Timex.Timezone.get("America/New_York")      
#<TimezoneInfo(America/New_York - EST (-05:00:00))>

The fourth command works, but the 'timezone' (with the same name) now is not always the 'same' timezone for any date-time. Tho this seems ambiguous. The Wikipedia article listing the tz database time zones states:

The UTC DST offset is different from the UTC offset for zones where daylight saving time is observed (see individual time zone pages for details).

That implies that timezones are (relatively) 'fixed'; the offset at any particular date-time for any given timezone is what varies.

But if that's true, it's confusing that Timex.Timezone.get/2 even accepts a date-time value as an argument. Why is the name of the timezone not only sufficient but entirely comprehensive? What's the point of retrieving a timezone by both name and date-time?


Solution

  • I'm an idiot!

    In the command that's failing:

    timezone = Timex.Timezone.get("America/New_York", v(2))
    

    v(2) has the value {:ok, #DateTime<2019-12-02 16:27:18Z>}, i.e. it's a tuple containing a DateTime.

    What I should have done instead:

    iex(5)> {:ok, datetime} = v(2)
    {:ok, #DateTime<2019-12-02 16:27:18Z>}
    iex(6)> timezone = Timex.Timezone.get("America/New_York", datetime)
    #<TimezoneInfo(America/New_York - EST (-05:00:00))>
    iex(7)> Timex.Timezone.convert(datetime, timezone)
    #DateTime<2019-12-02 11:27:18-05:00 EST America/New_York>