So I am working on a database for airports and i want to find the duration of flight. There is a table named flight that has id... dep_time(departure time), arr_time(arrival time) declared as time without time zone.
The problem is that one of the flights departs at 23:00:00 and arrives at 02:00:00 of the next day.
So in general i was using arr_time - dep_time but that gives me a negative result for the specific flight (-21:00:00).
So what i want to get to is that by chance I used - dep_time + arr_time and got the right result (03:00:00)... Can someone explain? I am so confused
(I dont want a solution cause I got it, I would like an explanation. Also I have to use time and not timevariable as it is specified in the project)
EDIT#1: Guys I dont want a solution for the problem, I have solved it. I want to know why there is a difference in the result while there shouldnt be.
The baseline for type time is one day. Internally - it is number of second from 0:0:0. It works simply when both values are from one day. But when these values are from different days, you can get negative value due overflow over maximum for this type (24 hours - it is difference between these two baselines). This error can be fixed by addition 24 hours:
db2=# select '02:00:00'::time - '23:00:00';
┌───────────┐
│ ?column? │
╞═══════════╡
│ -21:00:00 │
└───────────┘
(1 row)
db2=# select '02:00:00'::time - '23:00:00' + '24hours';
┌──────────┐
│ ?column? │
╞══════════╡
│ 03:00:00 │
└──────────┘
(1 row)
Same situation can be with dates in week, months. You can calculate in higher order (or in absolute values) or you have to fix distance in baselines.
So tue - mon = 1 .. (2 - 1), but Sun - Sat = -6 .. (0 - 6) these days are in different weeks, so you have to fix it -6 + 7 = 1
Related
I'm working in Julia with DataFrames, and want to filter some Date and DateTime columns. To do that I need the last day of the month previous to month of whenever a data job is run.
For example, if today's date is Date("2021-07-21"), I'd like to obtain 2021-06-30.
I do this in Redshift SQL all the time, which looks like this:
select last_day(current_date - interval '1 month');
┌────────────┐
│ last_day │
├────────────┤
│ 2021-06-30 │
└────────────┘
Before I remembered to check the Julia standard library Dates, I found some web tutorial that only mentioned the date floor/ceil functions:
using Dates
julia> floor(today(), Month) - Day(1)
2021-06-30
julia> typeof(ans)
Date
julia> floor(now(),Month) - Day(1)
2021-06-30T00:00:00
This works fine and I don't see how it could fail. However, the always excellent Julia docs describe the dedicated functions for this.
julia> lastdayofmonth(today() - Month(1))
2021-06-30
# maybe a leap year would cause a problem
julia> lastdayofmonth(Date("20200331","yyyymmdd") - Month(1))
2020-02-29
julia> lastdayofmonth(Date("20200229","yyyymmdd") + Month(1))
2020-03-31
There are many useful functions like firstdayofmonth(), dayofweek(), isleapyear(). Looks like everything is in order!
Edit: date arithmetic should be inside the function
Corrected the following error, I subtracted the month after finding the last day, works in postgres but not Julia Dates:
# WRONG, works only if prior month is shorter
lastdayofmonth(today()) - Month(1)
lastdayofmonth(Date("20210228", "yyyymmdd")) - Month(1)
2021-01-28
For some reason justify_interval(now() - '2013-02-14'::timestamptz) produces weird results:
postgres=# select justify_interval(concat(365*4 +1,' days')::interval); -[ RECORD 1 ]----+----------------
justify_interval | 4 years 21 days
I checked one year:
postgres=# select justify_interval('365 days'::interval);
justify_interval
------------------
1 year 5 days
So I went further:
postgres=# select justify_interval('360 days'::interval);
justify_interval
------------------
1 year
(1 row)
This behavior is not platform specific (tried several Linuxes, 9.2, 9.3, 9.6)
Why one year is 360 days?..
It seems that you are looking for something, which PostgreSQL calls a "symbolic" result that uses years and months, rather than just days, which is what the age(timestamp, timestamp) (and age(timestamp)) function(s) returns.
select age(now(), '2013-02-14'); -- 4 years 16:41:02.571547
select age(timestamp '2013-02-14'); -- 4 years
The - operator always returns the difference in days (at most). The justify_*() functions (and the *, /, <, > operators) always "cut" values to an average (i.e. 1 day is 24 hours and 1 month is 30 days) despite the fact that 1 day actually can contain 23-25 hours (just think of daylight saving time zones) and 1 month can contain 28-31 days (so the result depends on the actual start and end points of the range, which creates the interval).
accrding to docs:
justify_interval(interval) - Adjust interval using justify_days and
justify_hours, with additional sign adjustments
and further:
justify_days(interval) - Adjust interval so 30-day time periods
are represented as months
So 30*12=360
Not expected but obviously defined in docs...
Inspired by this question.
Is it possible to encode year, month and day (when year is negative) to the BC date in the simple way, without tricks?
Trying the direct way like
select make_date(-11,1,1);
ERROR: date field value out of range: -11-01-01
There are several alternatives like:
select make_date(1,1,1) - interval '11 years';
select format('%s-%s-%s BC', '0011','01','01')::date;
but obviously it is not the best approach.
So it seems like some kind of bug:
select extract(year from '0011-01-01 BC'::date);
╔═══════════╗
║ date_part ║
╠═══════════╣
║ -11 ║
╚═══════════╝
but using negative value of the year in the make_date function causing the error.
Tested on PostgreSQL 9.5
Yes, that seems like an oddity.
If you can come up with a patch for the pgsql-hackers mailing list, you've got chances to get it fixed.
I would like to calculate how many hours each employee has worked for a certain time period, based on information from this table:
start employee_id
2014-08-10 18:10:00 5
2014-08-10 13:30:00 7
2014-08-10 09:00:00 7
2014-08-09 23:55:00 4
2014-08-09 16:23:00 12
2014-08-09 03:59:00 9
2014-08-08 20:05:00 7
2014-08-08 13:00:00 8
Each employee replaces another employee and that's where his work is done, so there are no empty slots.
The desired format of the result would be the following:
employee_id total_minutes_worked
I'm trying to think of the best way to achieve this, so any help will be appreciated!
You can get the total time as:
select employee_id, sum(stop - start)
from (
select start, lead(start) over (order by start) as stop, employee_id
from t
) as x
group by employee_id;
It remains to format the time, but I assume this it not what puzzles you
you should use 'GroupBy' clause to first create a group of the same employee id
than you should calculate the time by checking the start time of work and end time of work in each slot.
(NOTE - you should maintain the start time and end time both of the employee in each slot of there shift)
I am building an app that deals with times and durations, and intersections between given units of time and start/end times in a database, for example:
Database:
Row # | start - end
Row 1 | 1:00 - 4:00
Row 2 | 3:00 - 6:00
I want to be able to select sums of time between two certain times, or GROUP BY an INTERVAL such that the returned recordset will have one row for each sum during a given interval, something like:
SELECT length( (start, end) ) WHERE (start, end) INTERSECTS (2:00,4:00)
(in this case (start,end) is a PERIOD which is a new data type in Postgres Temporal and pg9.2)
which would return
INTERVAL 3 HOURS
since Row 1 has two hours between 2:00 - 4:00 and Row 2 has one hour during that time.
further, i'd like to be able to:
SELECT "lower bound of start", length( (start, end) ) GROUP BY INTERVAL 1 HOUR
which i would like to return:
1:00 | 1
2:00 | 1
3:00 | 2
4:00 | 2
5:00 | 1
which shows one row for each hour during the given interval and the sum of time at the beginning of that interval
I think that the PERIOD type can be used for this, which is in Postgres Temporal and Postgres 9.2. However, these are not available on Heroku at this time as far as I can tell - So,
How can I enable these sorts of maths on Heroku?
Try running:
heroku addons:add heroku-postgresql:dev --version=9.2
That should give you the 9.2 version which has range types supported. As this is currently very alpha any feedback would be greatly appreciated at dod-feedback#heroku.com