Convert Military Time Separated by Pipes into Standard Time - sql

I need some help converting military time separated by a pipe into standard time. In addition I would like to know if it's possible to decode the pipe into a day of the week.
When I query for a customers hours of operation I am presented with the following result:
|0900|1800|0900|1800|0900|1800|0900|1800|0900|1800|0900|1300||
The first pipe equals Monday Open, second pipe equals Monday Closed. The third pipe equals Tuesday Open, the fourth Tuesday Closed etc. etc.
What I would like to see is something like
Monday: 9:00am - 6:00pm,
Tuesday: 9:00am - 6:00pm,
Wednesday: 9:00am - 6:00pm,
Thursday: 9:00am - 6:00pm,
Friday: 9:00am - 6:00pm,
Saturday: 9:00am - 1:00pm,
Sunday: Closed.
Is this possible to convert in Oracle?
select hours_of_operation
from customer_listing
where listing_id = '255990748'

Here is a SQLFiddle to get you started. The first day would be:
select 'Monday: '||
to_char(to_date(substr(hours_of_operation,2,4),'HH24MI'),'HH12:MIAM')
||'-' ||
to_char(to_date(substr(hours_of_operation,7,4),'HH24MI'),'HH12:MIAM')
from test
Then just add on, and move the substring function indexes.
UPDATE: I just realized this will only work for fixed fields. If you are missing a day, it will fail. That really requires a function to be written to handle some of the parsing logic.

Related

Oracle - How to convert Date represented by NUMBER(6,0) format

I've got data from our third party partner and every date column is coded in this NUMBER(6,0) format:
118346
118347
118348
118351
119013
119035
119049
119051
118339
118353
119019
119028
119029
119031
None of the last 3 digits are more than 365, so I reckon 118339 must mean 2018 + 339 days, which is December 5, 2018: '2018-12-05'. I've never encountered this kind of format before, so I'm a bit helpless how to handle it. Is this some standardized format? Can I use some built-in convert function or should I just manually cut and convert it using some arithmetics?
I would like to sort my rows grouping by weeks, so maybe I shouldn't even convert it, but for some reason I feel converting to a date type would be more elegant. Which approach is the better?
EDIT: I've just checked my excel version of the data, and this format is in fact working as I've imagined. So the question stands.
This seems to be Excel's 1900-based internal representation of dates. Assuming your interpretation is right, you can convert to a normal date with a bit of manipulation:
-- CTE for sample values
with your_table (num) as (
select *
from table(sys.odcinumberlist(118339, 118346, 118347, 118348, 118351, 119013, 119035,
119049, 119051, 118339, 118353, 119019, 119028, 119029, 119031))
)
-- actual query
select num,
date '1899-12-31'
+ floor(num/1000) * interval '1' year
+ mod(num, 1000) * interval '1' day as converted
from your_table;
NUM CONVERTED
---------- ----------
118339 2018-12-05
118346 2018-12-12
118347 2018-12-13
118348 2018-12-14
118351 2018-12-17
119013 2019-01-13
119035 2019-02-04
119049 2019-02-18
119051 2019-02-20
118339 2018-12-05
118353 2018-12-19
119019 2019-01-19
119028 2019-01-28
119029 2019-01-29
119031 2019-01-31
This treats the first three digits - obtained with floor(num/1000) - as the number of years, offset from 1900. Those are multiplied by a single year interval value, to give 118 or 199 years. Then it treats the last three digits - from mod(num, 1000) - as the number of days into that year, by multiplying by a single day interval. Both are then added to the fixed date 1899-12-31. (You could use 1900-01-01 instead but then you have to subtract a day at the end...)

PLSQL - How to find Monday and Friday of the week of a given date

I have spent days trying to figure this out to no avail, so hopefully someone can help me. I have a queried date set which contains several fields including a column of dates. What I want to do is create a new field in my query that tells what the Monday and Friday is for the week of that row's particular date.
So for example; if the date in one of my rows is "1/16/18",
the new field should indicate "1/15/18 - 1/19/18".
So basically I need to be able to extract the Monday date (1/15/18) and the Friday date (1/19/18) of the week of 1/16/18 and then concatenate the two with a dash ( - ) in between. I need to do this for every row.
How on earth do I do this? I've been struggling just to figure out how to find the Monday or Friday of the given date...
Assuming that your column is of type date, you can use trunc to get the first day of the week (monday) and then add 4 days to get the friday.
For example:
with yourTable(d) as (select sysdate from dual)
select trunc(d, 'iw'), trunc(d, 'iw') + 4
from yourTable
To format the date as a string in the needed format, you can use to_char; for example:
with yourTable(d) as (select sysdate from dual)
select to_char(trunc(d, 'iw'), 'dd/mm/yy') ||'-'|| to_char(trunc(d, 'iw') + 4, 'dd/mm/yy')
from yourTable
gives
15/01/2018-19/01/18
There may be a simpler, canonical Oracle method to this but you can still reduce it to a simple calculation on your own either way. I'm going to assume you're dealing with only dates falling Monday through Friday. If you do need to deal with weekend dates then you might have to be more explicit about which logical week they should be attached to.
<date> - (to_char(<date>, 'D') - 2) -- Monday
<date> + (6 - to_char(<date>, 'D')) -- Friday
In principle all you need to do is add/subtract the appropriate number of days based on the current day of week (from 1 - 7). There are some implicit casts going on in there and it would probably be wise to handle those better. You might also want to check into NLS settings to make sure you can rely on to_char() using Sunday as the first day of week.
https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm
You can also use the NEXT_DAY function, as in:
SELECT TRUNC(NEXT_DAY(SYSDATE, 'MON')) - INTERVAL '7' DAY AS PREV_MONDAY,
TRUNC(NEXT_DAY(SYSDATE, 'FRI')) AS NEXT_FRIDAY
FROM DUAL;
Note that using the above, on weekends the Monday will be the Monday preceding the current date, and the Friday will be the Friday following the current date, i.e. there will be 11 days between the two days.
You can also use
SELECT TRUNC(NEXT_DAY(SYSDATE, 'MON')) - INTERVAL '7' DAY AS PREV_MONDAY,
TRUNC(NEXT_DAY(SYSDATE, 'MON')) - INTERVAL '3' DAY AS NEXT_FRIDAY
FROM DUAL;
in which case the Monday and Friday will always be from the same week, but if SYSDATE is on a weekend the Monday and Friday returned will be from the PREVIOUS week.

Represent date/time periods

I'm working on a booking platform which has several different rates. These rates are determined by the time of day, day of week, and day of year. Here are some examples of the interval types involved:
Monday to Friday, 9am to 5pm
Saturday and Sunday, 12am to 9am
Saturday and Sunday, 9am to 5pm
Saturday and Sunday, 5pm to 12am
December 23rd & 24th, anytime
December 26th & 27th, anytime
What is the best way to represent this, such that it's possible to query for the different effective rates on any given day?
At the moment, the way I've done is using two array type columns, days_of_week[] and hours_of_day[], populating them with the days/hours each rate applies. To account for special cases like December, I also have fields valid_from and invalid_after, however this requires a new entry for each year.
I've had a look at the datetime functions for intervals and such here but haven't seen anything that looks like it could solve this.
why not just listing them in where clause? eg for first sample:
t=# select now(),extract('dow' from now()) between 1 and 5 and now()::time between '09:00' and '17:00';
now | ?column?
-------------------------------+----------
2017-11-27 16:56:01.544642+00 | t
so you take (extract('dow' from now()) between 1 and 5 and now()::time between '09:00' and '17:00') to brackets and add same brackets over OR...
You can addthem all to a function with timestamptz as argument and return true of false to use in where clause

Oracle SQL - exclude weekends from date range query

I have a query were i pull data between 2 dates using the following.
AND TRLRACT.trndte BETWEEN (TRUNC(sysdate -3) + 02.5/24) AND (TRUNC(sysdate) + 2.5/24)
is there any way to have it exclude Saturday and Sunday when pulling data
You can check for day of the week in several ways, for example with
to_char(trndte, 'Dy') not in ('Sat', 'Sun')
(ignoring issues of NLS language). However, your days seem to start and end at 2:30 am, is something at 2 am on a Monday actually considered to be "Sunday"? If so, you should test trndte - 2.5/24 instead of trndte itself.

Aggregating postgresql rows by date

I have records with values like: date, hour, value. Aggregating whole day is easy, i just group by date. My problem is that i need to aggregate records from whole days with specific start/end time. In example when start time is 9 a.m. then i have records:
- from monday 9 a.m. to tuesday 8 a.m (grouped in one record)
- from tuesday 9 a.m. to wednesday 8 a.m. (grouped in one record)
and so on.
Thanks, for any ideas.
I'm going to assume your hour field is an INT, but regardless you should be able to adapt this...
GROUP BY
CASE WHEN hour >= 9 THEN date ELSE date - 1 END
This essentially treats any hour before 9am as being part of the previous day.
GROUP BY date_trunc('day',date+(hour-9)*interval '1h') or something like that?