dbush
dbush

Reputation: 223699

Converting timezone string, i.e. US/Eastern, to offset

I'm looking for a method in pure Ruby of taking a timezone string such as "US/Eastern" and using it with a string representation of a timestamp to convert into a timestamp with timezone.

All I've found so far is strptime which supports a short timezone name like "EST" or a timezone offset like "-0500", but not a full timezone string.

I need to be able to run this as part of a Logstash ruby filter. I have some JSON that contains timestamps with no timezone that looks like this:

{
 "event": {
    "created": "2021-02-15_11-26-29",
  },
  "Accounts": [
    {
      "Name": "operator",
      "Caption": "SERVER\\operator",
      "Domain": "SERVER",
      "PasswordChangeable": "False",
      "PasswordRequired": "True",
      "PasswordExpires": "False",
      "Disabled": "False",
      "Lockout": "False",
      "LocalAccount": "True",
      "FullName": "operator",
      "Status": "OK",
      "LastLogon": "07/08/2020 2:14:13 PM"
    },
    ...
  ]
}

For the event.created field I can just use a date filter:

    date {
        match => [ "[event][created]", "yyyy-MM-dd_HH-mm-ss" ]
        timezone => "${TIMEZONE}"
        target => "[event][created]"
    }

Where ${TIMEZONE} is an environment variable holding the full timezone name, i.e. "US/Eastern". But for the Acounts.LastLogin field I can't use a date filter because it resides in a list of variable length, so I have to resort to a ruby filter. The closest I was able to come was this:

    ruby {
        code => 'event.get("[Accounts]").each_index {|x|
                    tz = "-0500"
                    last_logon_str = event.get("[Accounts][#{x}][LastLogon]")
                    last_logon = DateTime.strptime(last_logon_str + " " + tz, "%m/%d/%Y %I:%M:%S %p %z")
                    event.set("[users][#{x}][last_logon]", last_logon.strftime("%Y-%m-%dT%H:%M:%S%z"))
                 }'
    }

But of course this is using a hardcoded timezone offset and not the variable containing the full name.

The docs I looked at for the Time object at https://ruby-doc.org/core-2.6/Time.html stated that a Time object can be created using a timezone:

Or a timezone object:

tz = timezone("Europe/Athens") # Eastern European Time, UTC+2
Time.new(2002, 10, 31, 2, 2, 2, tz) #=> 2002-10-31 02:02:02 +0200

Which I could then use to extract the offset, but I couldn't find a reference to timezone anywhere.

What's the best way to handle this?

Upvotes: 1

Views: 344

Answers (1)

Badger
Badger

Reputation: 4072

timezone is part of the TZInfo class. You need to require it. The following code

    ruby {
        code => '
            require "tzinfo"
            tz = TZInfo::Timezone.get(ENV["TIMEZONE"])
            event.set("offset", tz.observed_utc_offset())
        '
    }

gets me "offset" => -18000, when $TIMEZONE is "US/Eastern".

Upvotes: 1

Related Questions