How to get time zone name as text Postgres Rails - ruby-on-rails

I have data imported into Rails as timestampz
startDate="2022-01-27 09:05:43 -0800"
I want to get the name from pg_timezone_names using the utc_offset field in Rails. I would get the offset using something like offset = startDate.localtime.formatted_offset(false).slice!(0, 3).to_i
Background:
Postgres:
select * from pg_timezone_names
In Rails
sql = "select * from pg_timezone_names"
pg_timezone_names = ActiveRecord::Base.connection.execute(sql).to_a
pg_timezone_names: [
{"name"=>"America/Ensenada", "abbrev"=>"PST", "utc_offset"=>"PT-8H", "is_dst"=>false},
{"name"=>"US/Pacific", "abbrev"=>"PST", "utc_offset"=>"PT-8H", "is_dst"=>false},
{"name"=>"America/Los_Angeles", "abbrev"=>"PST", "utc_offset"=>"PT-8H", "is_dst"=>false},
{"name"=>"Pacific/Pitcairn", "abbrev"=>"-08", "utc_offset"=>"PT-8H", "is_dst"=>false},
{"name"=>"Etc/GMT+8", "abbrev"=>"-08", "utc_offset"=>"PT-8H", "is_dst"=>false}
{"name"=>"NZ-CHAT", "abbrev"=>"+1345", "utc_offset"=>"PT13H45M", "is_dst"=>true},
Can I get utc_offset in the format that Postgres has into Rail? That would be much easier to use.
In summary, I have a timestampz and from the time zone want to get it as text. I know this has been beat to death, but it is confusing to many.
Use case. Data from Withings Blood Pressure Monitor device which sends data to Withings Health Mate app which send it to iOS Health—all automagically (but can take minutes to hours). In iOS Health App transfer all iOS Health Data to desktop and using my Rails app process and add to database where the data is presented in tables and graphs. Second line of post is an example of the raw time data taken in PST.
A new blog post that came several days after initial posting: PostgreSQL Timestamps and Timezones: What You Need to Know—and What You Don’t . Haven't absorbed it all yet.

Related

Getting a different result from query with active records

I have tables with UTC dates. When trying to get the day of week by using dow in PostgreSQL, I get the wrong day if the hours flow to the next day (and I need the right dow).
I created a fiddle to show the problem:
http://sqlfiddle.com/#!15/9aa9e/11
If I run the queries locally on my pgAdmin, it will return the correct dow. But on fiddle and from rails, I get the wrong dow. Any ideas?
Ok, so I understood that pgAdmin does it's own dow magic based on my timezone, and when rails sends that, it obviously doesn't happen.
The system I work on relies on the fact that rails does it's conversion magic for UTC datetimes back and forth, which work great if you don't use local postgreSQL timezone related functions such as DOW. What I did not is that it worked fine if I gave the dow the right offset. So here's my solution to the problem if anyone else needs it:
utc_diff = Time.current.time_zone.utc_offset/60/60
# making sure the diff is either + or - (minus is automatic)
utc_diff = utc_diff < 0 ? utc_diff : "+#{utc_diff}"
dow_part = "EXTRACT(DOW FROM punches.punched_in_at at time zone 'UTC#{utc_diff}') as dow"
So there you have it, hope it helps others.

SQLITE strange timestamp and IOS

I'm trying to display a simple tableview in IOS with data from Sqlite. My database date is stored as a timestamp. I thought was an unix timestamps but if i try to use dateWithTimeIntervalSince1970 i've really strange result.
Examples of date rows stored:
1352208510267
1352208512266
1352208514266
1352208516266
1352208530266
1352208532265
Use a query like this
SELECT datetime(timestamp, 'unixepoch') from YOURTABLENAME
WHERE id = someId;
This should convert it to some readable value.
Have a look here
I found the answer here. I compared the results with the previous answers:
SELECT strftime('%Y-%m-%d %H:%M:%S', datetime(ZDATE+978307200, 'unixepoch', 'localtime')), datetime(ZDATE, 'unixepoch', 'localtime') FROM ZTABLE
The query with the adjustment for Apple's epoch (Jan 1 2001) gives me the correct date:
"2015-09-29 20:50:51", "1984-09-28 20:50:51"
"2015-09-29 21:03:10", "1984-09-28 21:03:10"
"2015-09-29 21:25:30", "1984-09-28 21:25:30"
Unix timestamps are defined as the number of seconds since Jan 1 1970.
Just now, this would be about 1365525702.
Your values are one thousand times larger, i.e., they are measured in milliseconds.
Decide whether you actually need the millisecond precision, and then add * 1000 or / 1000 at the appropriate places.

get time of Different Timezone

My task: I am going to run a contest world wide at my website. A problem setter will set problems from a specific area of the world setting a time and date of starting time of the contest. I have to show that time correctly all over the world so the the contest starts at a time everywhere of the world.
My Idea : I planed to get the time from the problem setter of his time zone using server site language like php time(), & will store to database converting to timezone= zero (0). And who are going to attend the contest I'll just add hour(s) of that time zone with my database time.
Need help: I have no Idea how to convert that timestamps to timezone 'zero', even how can I get the ±hour(s) of current timezone?
Thank you...
Step 1:
Let the user choose his timezone. You could fill a dropdown with values from this site: http://php.net/manual/en/timezones.php
Step 2:
Convert the timezone to servertime
$timezone_client = new DateTimeZone('America/Denver');
$timezone_server = new DateTimeZone('Pacific/Nauru');
$datetime = new DateTime('2013-01-25 12:00:00', timezone_client);
$datetime->setTimezone($timezone_server);
echo $datetime->format('Y-m-d H:i:s');
Timezone 0 = "UTC" (sometimes called GMT)
Your system / language will have a Timezone class, which provides difference to GMT/UTC

Rails. How to store time of day (for schedule)?

I'm writing an app that keeps track of school classes.
I need to store the schedule. For example: Monday-Friday from 8:am-11am.
I was thinking about using a simple string column but I'm going to need to make time calculations later.
For example, I need to store a representation of 8am, such as start_at:8am end_at:11am
So how should I store the time? What datatype should I use? Should I store start time and number of seconds or minutes and then calculate from there? or is there an easier way?
I use MySQL for production and SQLite for development.
I made an app recently that had to tackle this problem. I decided to store open_at and closed_at in seconds from midnight in a simple business hour model. ActiveSupport includes this handy helper for finding out the time in seconds since midnight:
Time.now.seconds_since_midnight
This way I can do a simple query to find out if a venue is open:
BusinessHour.where("open_at > ? and close_at < ?", Time.now.seconds_since_midnight, Time.now.seconds_since_midnight)
Any tips for making this better would be appreciated =)
If you're using Postgresql you can use a time column type which is just the time of day and no date. You can then query
Event.where("start_time > '10:00:00' and end_time < '12:00:00'")
Maybe MySQL has something similar
Check out the gem 'tod' for Rails 4 or Time_of_Day for Rails 3. They both solve the problem of storing time in a database while using an an Active Record model.
SQL has a time data type but Ruby does not. Active Record addresses this difference by representing time attributes using Ruby’s Time class on the canonical date 2000-01-01. All Time attributes are arbitrarily assigned the same dates. While the attributes can be compared with one another without an issue, (the dates are the same), errors arise when you attempt to compare them with other Time instances. Simply using Time.parse on a string like ”10:05” adds today’s date to the output.
Lailson Bandeira created a created solution for this problem, the Time_of_Day gem for Rails 3. Unfortunately the gem is no longer maintained. Use Jack Christensen’s ‘tod’ gem instead. It works like a charm.
This ruby gem converts time of day to seconds since midnight and back. The seconds value is stored in the database and can be used for calculations and validations.
Define the time of day attributes:
class BusinessHour < ActiveRecord::Base
time_of_day_attr :opening, :closing
end
Converts time of day to seconds since midnight when a string was set:
business_hour = BusinessHour.new(opening: '9:00', closing: '17:00')
business_hour.opening
=> 32400
business_hour.closing
=> 61200
To convert back to time of day:
TimeOfDayAttr.l(business_hour.opening)
=> '9:00'
TimeOfDayAttr.l(business_hour.closing)
=> '17:00'
You could also omit minutes at full hour:
TimeOfDayAttr.l(business_hour.opening, omit_minutes_at_full_hour: true)
=> '9'
I would store the starting hour and the duration within the database, using two integer columns.
By retrieving both values, you could convert the starting hour as in (assuming that you know the day already:
# assuming date is the date of the day, datetime will hold the start time
datetime = date.change({:hour => your_stored_hour_value , :min => 0 , :sec => 0 })
# calculating the end time
end_time = datetime + your_stored_duration.seconds
Otherwise, hava a look at Chronic. The gem makes handling time a little bit easier. Note that the changemethod is part of rails, and not available in plain Ruby.
The documentation on DateTime for plain Ruby can be found here.
Also, whatever you do, don't start storing your dates/time in 12-hour format, you can use I18nin Rails to convert the time:
I18n.l Time.now, :format => "%I.%m %p", :locale => :"en"
I18n.l Time.now + 12.hours, :format => "%I.%m %p", :locale => :"en"
You can also get from this notation, that you can store you duration in hours, if you want, you can then convert them rather easily by:
your_stored_value.hours
if stored as an integer, that is.
Suggestion:
Don’t worry about a specific datatype for that. A simple solution would be:
In the database, add an integer type column for start_time and another for end_time. Each will store the number of minutes since midnight.
Ex: 8:30am would be stored as 510 (8*60+30)
In the form, create a select field (dropdown) that displays all available times in time format:Ex.: 10am, 10:30am and so on.
But the actual field values that get saved in the database are their integer equivalents:
Ex: 600, 630 and so on (following the example above)
I assume you are using some kind of database for this. If you are using MySQL or Postgresql, you can use the datetime column type, which Ruby/Rails will automatically convert to/from a Time object when reading/writing to the database. I'm not sure if sqlite has something similar, but I imagine it probably does.
From the SQLite 3 website,
"SQLite does not have a storage class set aside for storing dates and/or times. Instead, the built-in Date And Time Functions of SQLite are capable of storing dates and times as TEXT, REAL, or INTEGER values:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Applications can chose to store dates and times in any of these formats and freely convert between formats using the built-in date and time functions."
You can then manipulate the values using the Date and Time functions outlined here.

Find all data that were created between 9 am and 4pm Rails 3.2.1 and postgreSQL

I have a requirement to display all data that were inserted in between 9 am and 5 pm ignoring dates.
I have tried
.where(created_at: Time.parse("9am")..Time.parse("5pm"))
*Because Time.parse results in current data and time. So this display only today's result between 9 am and 5 pm.But I need all the data that were entered in between 9am and 5pm *
I tried to solve using time data field in database. Database stores correctly but when we query through rails the year 01-01-2000 was appended in time.
Although it is a very simple problem, I am stuck.
Please help me to figure out this problem.
PostgreSQL defines a function EXTRACT described here: http://www.postgresql.org/docs/current/interactive/functions-datetime.html
You might be able to query using something like the following:
SELECT * FROM (modelname) WHERE EXTRACT(HOUR FROM created_at) > (minhour) AND EXTRACT(HOUR FROM created_at) < (maxhour);

Resources