SAS - Comparison of Hours - sas

I'm new to SAS and can't seem to compare hours. Let me explain :
I have a Date/Time (format : ddmmmaa:hh:mm:ss) variable that I reformatted (in format TOD8 : hh:mm:ss) to only have the time.
With this specific time, I want to put it into a time slot. So if the time is between such and such time, I give him a time slot.
The problem that arises for me is that I cannot compare the time. Here is my code:
data test;
set WORK.TABLE;
if 'hour'n > '09:00:00't and 'hour'n < '09:59:59't then 'time slot'n=0910;
else if 'hour'n > '10:00:00't then 'time slot'n=1011;
else 'time slot'n=-1;
run;
This gives me the result :
Hour | time slot
------------------------
08:06:00 | 1011
09:30:00 | 1011
11:00:00 | 1011
I think it comes from the type but I can't find any documentation that allows me to solve this problem.
If you have an idea or something that could help me understand this result it will help me a lot. Thanks in advance

The problem is that you applied a format considering it changed the stored value. That's a wrong statement: a format just applies a "display" pattern, no more.
And this is why you can change the format to what you want without losing any information :)
To extract a time from a datetime, use the timepart function.
Then you'll be able to compare this value against other times:
data test;
set work.table;
attrib extracted_hours format=tod5.;
extracted_hours = timepart(your_datetime);
if '09:00:00't <= extracted_hours < '10:00:00't then 'time slot'n = 0910;
else if '10:00:00't <= extracted_hours < '11:00:0't then 'time slot'n=1011;
else 'time slot'n=-1;
run;

Related

Convert a number column into a time format in Power BI

I'm looking for a way to convert a decimal number into a valid HH:mm:ss format.
I'm importing data from an SQL database.
One of the columns in my database is labelled Actual Start Time.
The values in my database are stored in the following decimal format:
73758 // which translates to 07:27:58
114436 // which translates to 11:44:36
I cannot simply convert this Actual Start Time column into a Time format in my Power BI import as it returns errors for some values, saying it doesn't recognise 73758 as a valid 'time'. It needs to have a leading zero for cases such as 73758.
To combat this, I created a new Text column with the following code to append a leading zero:
Column = FORMAT([Actual Start Time], "000000")
This returns the following results:
073758
114436
-- which is perfect. Exactly what I needed.
I now want to convert these values into a Time.
Simply changing the data type field to Time doesn't do anything, returning:
Cannot convert value '073758' of type Text to type Date.
So I created another column with the following code:
Column 2 = FORMAT(TIME(LEFT([Column], 2), MID([Column], 3, 2), RIGHT([Column], 2)), "HH:mm:ss")
To pass the values 07, 37 and 58 into a TIME format.
This returns the following:
_______________________________________
| Actual Start Date | Column | Column 2 |
|_______________________________________|
| 73758 | 073758 | 07:37:58 |
| 114436 | 114436 | 11:44:36 |
Which is what I wanted but is there any other way of doing this? I want to ideally do it in one step without creating additional columns.
You could use a variable as suggested by Aldert or you can replace Column by the format function:
Time Format = FORMAT(
TIME(
LEFT(FORMAT([Actual Start Time],"000000"),2),
MID(FORMAT([Actual Start Time],"000000"),3,2),
RIGHT([Actual Start Time],2)),
"hh:mm:ss")
Edit:
If you want to do this in Power query, you can create a customer column with the following calculation:
Time.FromText(
if Text.Length([Actual Start Time])=5 then Text.PadStart( [Actual Start Time],6,"0")
else [Actual Start Time])
Once this column is created you can drop the old column, so that you only have one time column in the data. Hope this helps.
I, on purpose show you the concept of variables so you can use this in future with more complex queries.
TimeC =
var timeStr = FORMAT([Actual Start Time], "000000")
return FORMAT(TIME(LEFT([timeStr], 2), MID([timeStr], 3, 2), RIGHT([timeStr], 2)), "HH:mm:ss")

Redshift regexp_substr - extract data from a JSON type format

Help much appreciated - I have a field in Redshift giving data of the form:
{\"frequencyCapList\":[{\"frequencyCapped\":true,\"frequencyCapPeriodCount\":1,\"frequencyCapPeriodType\":\"DAYS\",\"frequencyCapCount\":501}]}
What I would like to do is parse this cleanly as the output of a Redshift query into some columns like:
Frequency Cap Period Count | Frequency Cap Period Type | Frequency Cap Count
1 | DAYS | 501
I believe I need to use the regexp_subst function to achieve this but I cannot work out the syntax to get the required output :(
Thanks in advance for any assistance,
Carter
Here you go
select json_extract_path_text(json_extract_array_element_text(json_extract_path_text(replace('{\"frequencyCapList\":[{\"frequencyCapped\":true,\"frequencyCapPeriodCount\":1,\"frequencyCapPeriodType\":\"DAYS\",\"frequencyCapCount\":501}]}','\\',''),'frequencyCapList'),0),'frequencyCapPeriodCount');
just replace the last string with each one you want to extract!

juliandate to normaldate in redshift

I have date like 117106, 117107 in an column which is of numeric type in redshift data base. Understood that the format is in Julian format. I wanted to change it to normal date format like yyyymmdd.
I tried applying the function to the column and it returns the value as below
select to_date(117106) - result 4393-07-10
Please help.
Thanks in advance
Here is how it is done.
The way it works is the first 3 digits is the century julian offset, and the last 3 are the day offset:
select dateadd(day,117106 % 1000,dateadd(year,(117106 /1000),convert(datetime,'01/01/1900')))-1
If I’ve made a bad assumption please comment and I’ll refocus my answer.
Thank you Rahul for the help.
I haven't tried the solution provided.However i have implemented the below solution as below to convert it into date format
trim(cast(to_char(dateadd(days,cast(right(x)as bigint)
+ datediff(days,'1900-01-02',to_date(cast(left((1900+(x/1000)),4) as char(4)) || '-01' || '-01','yyyy-mm-dd')),'1900-01-01'),
'YYYYMMDD')as decimal),0) as x
Can generate_series() to cover the julian day range you need and then use standard date functions
with julian_day as (
select generate_series as julian_day,
to_date(generate_series, 'J') as gregorian_date
from generate_series((2459865 - ( 10 * 365)), (2459865 + (10 * 365)), 1)
)
select
julian_day,
gregorian_date,
to_char(gregorian_date, 'IYYY') as iso_year,
date_part(year, gregorian_date) as year,
...
from julian_day

QCustomPlot display time in HH:MM:SS

I was wondering either it is possible in the QCustomPlot library to change display format of the data on one of the axis. In my application on the X axis I have time in seconds and I would like to display the steps in HH:MM:SS instead. As an alternative I am thinking of changing the display only from seconds to minutes to hours depending on the X lenght and updating the label from Time [s] to [min] to [hour]. But I would avoid that if its possible to do it the way I described. I Would appreciate all help!
When using:
customPlot->xAxis->setTickLabelType(QCPAxis::ltDateTime);
customPlot->xAxis->setDateTimeFormat("hh:mm:ss");
My timeline starts from hour 1 instead of 0:
Is there a way to fix this?
You can use setTickLabelType() and setDateTimeFormat:
plot->xAxis->setTickLabelType(QCPAxis::ltDateTime);
plot->xAxis->setDateTimeFormat("hh:mm:ss");
The format string is built according to the the format string of QDateTime::toString().
// Создаем формат отображения дискретных отсчетов времени захвата мгновенного курса судна
QSharedPointer<QCPAxisTickerDateTime> dateTicker(new QCPAxisTickerDateTime);
// Установка формата отображения времени захвата мгновенного курса судна
dateTicker->setDateTimeFormat("hh:mm:ss");
// Передаем вектор подписей в график
m_QCustomPlot->yAxis->setTicker(dateTicker);

What is the best way to populate a load file for a date lookup dimension table?

Informix 11.70.TC4:
I have an SQL dimension table which is used for looking up a date (pk_date) and returning another date (plus1, plus2 or plus3_months) to the client, depending on whether the user selects a "1","2" or a "3".
The table schema is as follows:
TABLE date_lookup
(
pk_date DATE,
plus1_months DATE,
plus2_months DATE,
plus3_months DATE
);
UNIQUE INDEX on date_lookup(pk_date);
I have a load file (pipe delimited) containing dates from 01-28-2012 to 03-31-2014.
The following is an example of the load file:
01-28-2012|02-28-2012|03-28-2012|04-28-2012|
01-29-2012|02-29-2012|03-29-2012|04-29-2012|
01-30-2012|02-29-2012|03-30-2012|04-30-2012|
01-31-2012|02-29-2012|03-31-2012|04-30-2012|
...
03-31-2014|04-30-2014|05-31-2014|06-30-2014|
........................................................................................
EDIT : Sir Jonathan's SQL statement using DATE(pk_date + n UNITS MONTH on 11.70.TC5 worked!
I generated a load file with pk_date's from 01-28-2012 to 12-31-2020, and plus1, plus2 & plus3_months NULL. Loaded this into date_lookup table, then executed the update statement below:
UPDATE date_lookup
SET plus1_months = DATE(pk_date + 1 UNITS MONTH),
plus2_months = DATE(pk_date + 2 UNITS MONTH),
plus3_months = DATE(pk_date + 3 UNITS MONTH);
Apparently, DATE() was able to convert pk_date to DATETIME, do the math with TC5's new algorithm, and return the result in DATE format!
.........................................................................................
The rules for this dimension table are:
If pk_date has 31 days in its month and plus1, plus2 or plus3_months only have 28, 29, or 30 days, then let plus1, plus2 or plus3 equal the last day of that month.
If pk_date has 30 days in its month and plus1, plus2 or plus3 has 28 or 29 days in its month, let them equal the last valid date of those month, and so on.
All other dates fall on the same day of the following month.
My question is: What is the best way to automatically generate pk_dates past 03-31-2014 following the above rules? Can I accomplish this with an SQL script, "sed", C program?
EDIT: I mentioned sed because I already have more than two years worth of data and
could perhaps model the rest after this data, or perhaps a tool like awk is better?
The best technique would be to upgrade to 11.70.TC5 (on 32-bit Windows; generally to 11.70.xC5 or later) and use an expression such as:
SELECT DATE(given_date + n UNITS MONTH)
FROM Wherever
...
The DATETIME code was modified between 11.70.xC4 and 11.70.xC5 to generate dates according to the rules you outline when the dates are as described and you use the + n UNITS MONTH or equivalent notation.
This obviates the need for a table at all. Clearly, though, all your clients would also have to be on 11.70.xC5 too.
Maybe you can update your development machine to 11.70.xC5 and then use this property to generate the data for the table on your development machine, and distribute the data to your clients.
If upgrading at least someone to 11.70.xC5 is not an option, then consider the Perl script suggestion.
Can it be done with SQL? Probably, but it would be excruciating. Ditto for C, and I think 'no' is the answer for sed.
However, a couple of dozen lines of perl seems to produce what you need:
#!/usr/bin/perl
use strict;
use warnings;
use DateTime;
my #dates;
# parse arguments
while (my $datep = shift){
my ($m,$d,$y) = split('-', $datep);
push(#dates, DateTime->new(year => $y, month => $m, day => $d))
|| die "Cannot parse date $!\n";
}
open(STDOUT, ">", "output.unl") || die "Unable to create output file.";
my ($date, $end) = #dates;
while( $date < $end ){
my #row = ($date->mdy('-')); # start with pk_date
for my $mth ( qw[ 1 2 3 ] ){
my $fut_d = $date->clone->add(months => $mth);
until (
($fut_d->month == $date->month + $mth
&& $fut_d->year == $date->year) ||
($fut_d->month == $date->month + $mth - 12
&& $fut_d->year > $date->year)
){
$fut_d->subtract(days => 1); # step back until criteria met
}
push(#row, $fut_d->mdy('-'));
}
print STDOUT join("|", #row, "\n");
$date->add(days => 1);
}
Save that as futuredates.pl, chmod +x it and execute like this:
$ futuredates.pl 04-01-2014 12-31-2020
That seems to do the trick for me.