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.
Related
I found strange date codes in a SQL database used by an old iOS app called Memo Lite. The column was labeled LMT, that might be an abbreviation for last modified time. How are they constructed and how can they be converted to readable formats, like yyyy-mm-dd HH:mm:ss?
I am aware of both Unix time and how Google Sheets handles time.
Example of date/time codes:
357931095.942149 = 2012-05-05
330432567.859129 = 2011-06-22
293964817.803674 = 2010-04-26
I don't know if the format has time, it looks so but it is not showed in the app.
Date/time format codes, reference example:
https://support.google.com/docs/answer/3094139?hl=en
A little math shows it's seconds since an epoch. Not the usual 1970-01-01, but 2001-01-01.
2001-01-01 + 293964817 seconds = 2010-04-25 08:53:37
2001-01-01 + 330432567 seconds = 2011-06-22 10:49:27
2001-01-01 + 357931095 seconds = 2012-05-05 17:18:15
The decimal portion is microseconds. For example, 293964817.803674 is 2010-04-25 08:53:37.803674.
You mentioned it's an iOS app, so it's likely CFAbsoluteTime.
I'm building an iOS app where I want to retrieve all the values from my database between two dates that the user picks. So for example, I want all the rows from the 1st of March to the 5th of March. Would look something like
SELECT * FROM MAIN WHERE DATE = '01/03/2020' AND ENDS ='05/03/2020'
So from that I would hope to retrieve all data from the 1st,2nd,3rd,4th and 5th of march. Any ideas on how to do this?
Thank you
Try to use comparison operators like:
DATE >= '01/03/2020' AND DATE <= '05/03/2020'
There are two issues:
Date types:
As Datatypes In SQLite Version 3 says:
2.2. Date and Time Datatype
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.
So storing dates in a dd/MM/yyyy format (using the DateFormatter capitalization convention) is problematic because in the absence of a native date type, it’s going to store them as strings, and therefore all comparisons will be done alphabetically, not chronologically, sorting values like 03/10/2009 (or nonsense strings like 02foobar, for that matter) in between the strings 01/05/2020 and 05/05/2020.
If, however you store them as yyyy-MM-dd, then it just so happens that alphabetical comparisons will yield chronologically correct comparisons, too.
SQL syntax:
Once you have your dates in your database in a format that is comparable, then if you have all of your dates in a single column, you can use the BETWEEN syntax. For example, let’s say you stored all of your dates in yyyy-MM-dd format, then you could do things like:
SELECT * FROM main WHERE date BETWEEN '2020-03-01' AND '2020-03-05';
But needless to say, you can’t use this pattern (or any comparison operators other than equality) as long as your dates are stored in dd/MM/yyyy format.
If you want to show all the data that has values of column "date" between this two dates then:
Select *
from MAIN
where `date` between '01.03.2020' and '05.03.2020';
If you want to show all the data that has values of column "ends" between this two dates then:
Select *
from MAIN
where ends between '01.03.2020' and '05.03.2020';
If you want to show all the data that has values of columns "date" and "ends" between this two dates then:
Select *
from MAIN
where ends between '01.03.2020' and '05.03.2020'
and `date` between '01.03.2020' and '05.03.2020';
Here is a demo
my table has 3 columns: data type timestamp,
|created_At | final_time| duracion(difference between created at and final_time)
| | |
the column difference should save the difference in hours and minutes, in this format HH:MM
this is my controller:
def horario
horario.update(duracion: params[:duracion]) // this params is "00:59"
end
but in the table Horarios, in column duracion i have this:
2017-12-24 03:59:00
so i want to save 00:59 (59 minutes) but postgres save all current date and add 3 hours more.
i want to save so in the future i will be able tu sum column duracion. Or should i change data type for this column? In this case which datatype you recomend me for rails to save HH:MM??
thanks.
Rails 5 supports PostgreSQL's interval type to some extent. You can create interval columns in the usual way and they will be properly represented in db/schema.rb. You can also assign them values in the usual way so you can say things like:
model.some_interval = '6 hours'
and get 06:00:00 inside the database. However, there is nothing in Ruby or Rails that properly represents a time interval (we only have various timestamp and date classes) so when that interval comes out of the database, you'll have a string on your hands, i.e:
> model = Model.find(some_id)
> model.some_interval.class
=> String
so you might end up having to manually parse some strings in Ruby. For simple intervals like '6 hours', this will be easy but it won't be so easy with more complicated intervals like '6 years 23 days 11 hours'.
If you'll only be working with your time intervals inside the database then interval would be natural and easy, you can say things like:
select some_timestamp + some_interval
and
where some_timestamp + some_interval < some_other_timestamp
and everything will work nicely.
However, if you need to work with the intervals back in Ruby then you'd probably be better off storing the interval as a number of seconds in an integer column (or whatever resolution you need). Then you could say things like:
where some_timestamp + (some_interval_in_seconds || 'seconds')::interval < some_other_timestamp
inside the database and
some_time + model.some_interval_in_seconds
back in Ruby.
In any case, strings are probably the wrong approach unless you really like parsing strings everywhere all the time.
As others already pointed out, Rails handles the Postgres Interval type as a string. A string that, unfortunately, is not easy to parse.
If you do this:
u = Users.select('edited_at - created_at as time_dif')
puts u.first['time_dif']
You can get something like 168 days 12:51:20.851115. Ugly right?
Well, using Ruby to convert this string into an useful number is not easy, but you can use Postgres to do the job for you. You will need to do a plain SQL query though, but it's the best method I've found so far:
query = ActiveRecord::Base.connection.execute("
SELECT EXTRACT(epoch FROM time_dif)/3600 as hours_dif
FROM
(
SELECT (edited_at - created_at) as time_dif
FROM users
) AS MainQuery
")
In this example, Postgres' EXTRACT function will convert the Interval type into a number which represents the total seconds of the interval. If you divide this number by 3600 you will get the different in hours as in the example above.
Then, if you want to iterate over the results:
query.each do |r|
puts r['hours_dif']
end
You could save duracion as a float type, where duracion would equal something like final_time - created_at and this value would be the difference in seconds. You can then perform arithmetic with these values and always convert back to minutes, hours, or whatever you need.
I'm using Tableau Desktop, my data are like this:
KPI,date,monthValue
coffee break,01/06/2015,10.50
coffee break,01/07/2015,8.30
and I want to build a table like this
KPI, year(date), last value
coffee time, 2015, 8.30
How can I set a calculated field in order to show me the last value available in that year? I tried to do:
LOOKUP([MonthValue], LAST())
But it didn't work and tells me 'cannot mix aggregate and non-aggregate', so I did:
LOOKUP(sum([MonthValue]), LAST())
But it didn't work too. How should I proceed?
If you are using Tableau 9 then you can do this with an LOD calc that looks for the max value in your date field and then checks if the current date value is the same as the max date value.
[Date] == {fixed: max([Date])}
As you can see in the example below when you use the calc as a filter you will only get the last row from your example above.
UPDATE: to get the values per year you can do something like:
Here I am using a table calculation to find the max date per year and then ranking those dates and filtering down to the latest date in each year (which will be the one that has a rank equal to 1).
!max date is WINDOW_MAX(ATTR(Date))
!rank is RANK(Date)
You need to make sure that the table calculations are computer in the correct way (in this case across the values of each year).
For some reason:
Analytic.where({:ga_date.gte => '2010-09-01'}).count() # greater than or equal to
gives back 0, but
Analytic.where({:ga_date.gte => Time.parse('2010-09-01')}).count()
gives back 230, which is the number of records (documents).
Actually, the first line on the top works in another case, so it is quite strange.
Can only the date be compared, because if it is
Analytic.where({:ga_date.lte => Time.parse('2010-09-10')}).count() # less than or equal to
then all the records with date 2010-09-10 will not be counted because Time.parse('2010-09-10') will give 2010-09-10 00:00:00, so the records will all have to be 2010-09-09 before the midnight. In other words, 2010-09-10 2am won't be included because 2am is not "less than or equal to" 00:00:00. It can be hacked by using
Analytic.where({:ga_date.lte => Time.parse('2010-09-10 23:59:59')}).count()
but it is kind of ugly. If there is a way to compare by date only like the first line of code in this post?
I think that you have two separate issues here.
Different data types
The following two lines are not equivalent. The first is a string comparison. The second is a comparison with a date object.
Analytic.where({:ga_date.gte => '2010-09-01'}).count()
Analytic.where({:ga_date.gte => Time.parse('2010-09-01')}).count()
I think you have figured this out, but it's important to be clear here. If you are storing date objects in the DB, you need to perform comparisons with date objects.
MongoDB will compare types and data.
Mismatch date storage
You are storing dates that have information for hours, minutes and seconds. However, you don't like the following notation:
:ga_date.lte => Time.parse('2010-09-10 23:59:59')
The workaround here is to use $lt and the day after.
:ga_date.lt => (Time.parse('2010-09-10') + 1.day) # or (60 * 60 * 24)
to add,
it is not strangely works, its coincidentally works when it just happens the string representation of the date happens to also lexicographically be 'greater than' the other date
other issue,
try to use only as much data fields as needed
if you meant it to be "within the calendar day",
what I usually like is to call beginning_of_day in both cases to equalize
this has the effect of neutralizing the minutes
else if you really meant within a 24h strike zone,
use ActiveSupport's '+ 1.day'