3

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?

Kenny Evitt
  • 9,291
  • 5
  • 65
  • 93
  • 1
    This isn't a great question on its own but it, and my answer, might help someone else. – Kenny Evitt Dec 19 '19 at 19:24
  • I don't think it will be useful to others. The cause was a misuse of `v/1` and is nothing to do with Timex or Datetime. I think this question is off topic. – Adam Millerchip Dec 20 '19 at 01:19
  • 1
    @AdamMillerchip Meh – I'm open to deleting it but the error is *very* unclear. It's the kind of error I've observed frequently among beginners in similar functional programming languages (and I still consider myself not much more than a beginner). A question that's in effect about a mistake that's easy to make for beginners is totally on-topic. There's ton of them on this site and many that are highly up-voted. I'll wait for some more feedback before doing anything with the question. – Kenny Evitt Dec 20 '19 at 01:55
  • 1
    [Here](https://stackoverflow.com/questions/37703632/elixir-assert-raise-doesnt-catch-exceptions)'s a pretty well received question answered by realizing that what they thought was a macro call was really a function call. – Kenny Evitt Dec 20 '19 at 02:01
  • 1
    What exactly is unclear in `# 2 {:error, :invalid_date}`? One goes to check the second parameter and voilà. Delete it, please, or at least remove any reference to `Timex` and `DateTime`. It’s all about passing crap to function as an argument. – Aleksei Matiushkin Dec 20 '19 at 06:51
  • @AlekseiMatiushkin Furthermore, the error was not immediately clear because *I* didn't call `Timex.Timezone.resolve/3`. Yes, I noticed the `{:error, :invalid_date}` but I was confused as to why `resolve/3` would fail given that its caller seemed to 'know' that the date-time I passed was 'invalid'. It's not obvious to me that this isn't, at least in a sense, a 'UX bug' – it'd be far more helpful were `Timex.Timezone.get/2` to have returned a clear `{:error, "Invalid date-time}` as [its spec](https://hexdocs.pm/timex/Timex.Timezone.html#get/2) implies it would. – Kenny Evitt Dec 20 '19 at 14:53

1 Answers1

1

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>
Kenny Evitt
  • 9,291
  • 5
  • 65
  • 93
  • 1
    I think if somebody is going to vote you down, they should at least provide a reason as to why they did. It helps everybody learn. – traday Dec 20 '19 at 19:42
  • 1
    @traday Meh – I think it's fine just to downvote. It's info too! You're absolutely right that it is very much nicer for them to also provide a reason. But it's a small 'failing'! – Kenny Evitt Dec 20 '19 at 20:37