Time difference in SQLite - sqlite

Here comes a head scratcher.
Using the expression:
cast((julianday(arrtime)-julianday(deptime))*24*60 as integer)
to calculate the difference of 2021-05-01 00:19 and 2021-05-01 01:29, gives me 69 minutes?
I can do better than that!
Any idea how to get around?

The problem with the value that you get is that julianday() returns a not exactly accurate floating point number and after the calculations and before casting to an integer, the result is 69.999999850988.
This value, when casting is applied will be truncated to the integer 69.
One solution would be to round the result to an integer instead of casting:
ROUND((julianday(arrtime)-julianday(deptime)) * 24 * 60)
or, since your dates do not contain seconds, use strftime() with '%s' as the format, which returns the number of seconds since 1970-01-01 00:00:00:
(strftime('%s', arrtime) - strftime('%s', deptime)) / 60
See a simplified demo.

Related

Timestamp field in a dbf file (dBase 7 format) is not making sense

I've looked at both [1] and [2] and I'm completely confused (and since the dbf file is a version
4 file, [1] should apply well). For one thing why does [1] state that the timestamp's date portion is the # of days since 1/1/4713 BC? That's just very puzzling. Secondly, assuming that it is the # of days since 4713 BC, I'm having some trouble with the value I am getting.
First off, my dbf file has a timestamp field which has an 8 byte long value. The actual
date is 2000/8/16 17:21:41. In the dbf file, the 8 byte sequence is as follows
0x42ccb20e0340df00.
From [1], it says the first 4 bytes are for the date, and 2nd 4 bytes for the time. If the original
byte sequence is actually little-endian (0x42ccb20e) then that should be 0x0eb2cc42 which
comes to the value of 246598722. So date is 0x0eb2cc42 (246598722) and time is 0x00df4003
(14630915).
I must be missing something here or calculating something wrong. 246598722 is equivalent to 675612 years(assuming 1yr = 365 days, as adding leap years would confuse me..and shouldn't really be that much off).
From [2], I shouldn't use 01/01/4173bc as the basis but 12/31/1899 (well, 1/1/1900). But then, the date value I have isn't even in the range of what [2] shows.
Now if I take the actual value (2000/8/16) and use [1] and [2], I get the following:
method [1]: 2450501 days : (2000 - -4713) * 365 + (8 * 30) + 16
method [2]: 36756 days : [100 * 365 + 8 * 30 + 16] (over counting the # of days)
The dbf file isn't corrupted (otherwise, if I look at the timestamp in dBase, it'd crap out
and display something crazy).
I've thought of using big-endian, but that makes even less sense as the values are even larger. I've even thought of the possibility that it's actually the # of seconds elapsed since either date, but that makes the values with even less sense. i.e. 246598722 = # of seconds elapsed (counting back from 2000/8/16) will make the base year as 1812. (calculations: 246898722 / (3600 * 365) = 187.8985, so 2000 - 187.8985 = 1812.1015)
Can someone point out where I'm doing this wrong?
Thanks!
[1] - https://www.dbase.com/Knowledgebase/INT/db7_file_fmt.htm
[2] - Convert dBase Timestamp
For any dBASE questions, I would recommend to go to the dBASE newsgroups, they have a very helpful and knowledgeable community.
I've finally found the answer thanks to [3].
Basically, the timestamp 8 byte sequence is used as a whole with the following notes:
It's stored in big-endian.
The last byte is not used.
It's a Julian Day Number.
So in my case, it's 0x42ccb20e0340df00 and truncating the last byte,
I get 0x42ccb20e0340df.
Then the following python code gets the correct info:
import datetime
base = 0x42cc418ba99a00
frm_date = int('42ccb20e0340df', 16)
final_ts = (frm_date - base) / 500
final_date = datetime.datetime.utcfromtimestamp(final_ts)
which outputs 2000-8-16 17:21:41 and some milliseconds, which I just ignore.
So I'm guessing the theory is that the above code moves the 'base' date to
1970/1/1 from 1/1/1, which helps since utcfromtimestamp() doesn't
work with any value prior to 1970/1/1.
My confusion stems from the fact it doesn't use 4713BC as the
base year, instead it uses 1/1/1, though I'm still trying to figure out how to get the value 0x42cc418ba99a00 for 1970/1/1.
[3] - https://stackoverflow.com/a/60424157/10860403

MomentJS.diff is not returning the correct number of months

I'm receiving from a certain API this timestamp, 1580844574000, which is 02/04/2020. When I run the below output,
moment().diff(moment(1580844574000), 'months')
I get 1 instead of 2, considering that today's date is April 2, 2020. I've also tried,
moment('04/02/2020').diff(moment(1580844574000), 'months') and I still get 1 instead of 2.
Is there something that I am doing wrong? I've put together a JSFiddle, where you can see the output is returning 1 instead of 2.
Thanks!
This is because February 4 is not a full 2 months before April 2. Moment truncates the decimal places to return an integer by default (as opposed to rounding). From the moment docs:
By default, moment#diff will truncate the result to zero decimal places, returning an integer. If you want a floating point number, pass true as the third argument. Before 2.0.0, moment#diff returned a number rounded to the nearest integer, not a truncated number.
So passing true as the third argument will give you the decimal places as well:
moment('04/02/2020').diff(moment(1580844574000), 'months', true)
// returns 1.9131457940991838
If you want to ignore the date part, you could use Moment's month() function and use normal subtraction:
moment('04/02/2020').month() - moment(1580844574000).month()
// returns 2

How to convert decimal to binary?

How to convert the decimal number "18.25" to binary? I've been confused by the decimal points .25.
Just like you divide this 18 by 2 repeatedly to form a decimal representation for it, you need to do the reverse to convert the decimal part of the number to binary. You need to multiply that decimal portion of the number by 2 repeatedly until it gives a standalone digit. The result(product) of the first multiplication will be the input to the second multiplication and this continues until we reach a stagnant steady integer value.
So, in your case, the 18.25's decimal part is 0.25.
Let's begin by multiplying it with 2.
0.25*2=0.5 // 0
0.5*2=1.0 // 1
Hunt finishes as we end up with the product coming as a standalone integer.
Also, the decimal to binary conversion of 18 is (10010)base 2. This you can easily calculate as you know it,mentioned in the question.
Hence, the decimal representation for 18.25 will be (10010.01)base 2---see,serially 01 in the order unlike the numbers where we traverse from bottom to top!
I hope it is clear.
with recursiveCTE(num) as (
select &EnterNum num from dual
union all
select trunc(num/2) from recursiveCTE
where trunc(num/2)> 0
),
ref as (SELECT num, mod(num, 2) bin_remainder from recursiveCTE)
select reverse(to_char(replace(wm_concat(bin_remainder), ','))) binary_num from ref;

Calculating wage by hours worked

Hey all, i am trying to figure out how to calculate the wage for an employee when they clock out. This is the code i am currently using:
Dim theStartTime As Date
Dim theEndTime As Date
Dim totalTime As String
theStartTime = "16:11:06"
theEndTime = "18:22:01"
totalTime = Format(CDbl((theEndTime - theStartTime) * 24), "#0.0")
So workable hours would be: 2h 11m
Right now, with my calculation code above, i get 2.2. What would i need to add in order to get it to calculate the correct time of 2:11 instead of 2:20?
David
Note that 2.2 hours is not 2:20, it's 2:12.
Change
Format(CDbl((theEndTime - theStartTime) * 24), "#0.0")
to
Format(theEndTime - theStartTime, "h:mm")
You're getting the right value, just rounding it off when you print. theEndTime - theStartTime is a time span equal to the difference between the two times. As you discovered, multiplying it by 24 will give you the number of hours different. However, you then have to divide by 24 again to use date/time formatting.
Check out all the ways to format dates and time in VB6.
First, I highly suggest going to the .NET framework (with it's easy-to-use TimeSpan class) if possible.
But, dealing in VB6 you should be able to use the DATEDIFF function (and it's been many years since I've touched VB6 so the specific syntax might be a bit off
Dim iHours As Integer, iMins As Integer
iMins = DateDiff("n", theStartTime, theEndTime)
iHours = iMins / 60
iMins = iMins Mod 60
You should also try casting it to the Currency type which can represent all numeric values (within 4 digits to the left of decimal point and 15 digits to the right).
Format(CCur((theEndTime - theStartTime) * 24), "#0.00")

How do I convert an interval into a number of hours with postgres?

Say I have an interval like
4 days 10:00:00
in postgres. How do I convert that to a number of hours (106 in this case?) Is there a function or should I bite the bullet and do something like
extract(days, my_interval) * 24 + extract(hours, my_interval)
Probably the easiest way is:
SELECT EXTRACT(epoch FROM my_interval)/3600
If you want integer i.e. number of days:
SELECT (EXTRACT(epoch FROM (SELECT (NOW() - '2014-08-02 08:10:56')))/86400)::int
To get the number of days the easiest way would be:
SELECT EXTRACT(DAY FROM NOW() - '2014-08-02 08:10:56');
As far as I know it would return the same as:
SELECT (EXTRACT(epoch FROM (SELECT (NOW() - '2014-08-02 08:10:56')))/86400)::int;
select floor((date_part('epoch', order_time - '2016-09-05 00:00:00') / 3600)), count(*)
from od_a_week
group by floor((date_part('epoch', order_time - '2016-09-05 00:00:00') / 3600));
The ::int conversion follows the principle of rounding.
If you want a different result such as rounding down, you can use the corresponding math function such as floor.
If you convert table field:
Define the field so it contains seconds:
CREATE TABLE IF NOT EXISTS test (
...
field INTERVAL SECOND(0)
);
Extract the value. Remember to cast to int other wise you can get an unpleasant surprise once the intervals are big:
EXTRACT(EPOCH FROM field)::int
If you want to display your result only in date type after adding the interval then, should try this
Select (current_date + interval 'x day')::date;
I'm working with PostgreSQL 11, and I created a function to get the hours betweeen 2 differents timestamps
create function analysis.calcHours(datetime1 timestamp, datetime2 timestamp)
returns integer
language plpgsql as $$
declare
diff interval;
begin
diff = datetime2 - datetime1;
return (abs(extract(days from diff))*24 + abs(extract(hours from diff)))::integer;
end; $$;
select date 'now()' - date '1955-12-15';
Here is the simple query which calculates total no of days.

Resources