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
Related
My working environment
PostgreSQL version: 10.9 (64 bits)
OS: Windows 10 (64 bits)
I need to find the week number of a given date in the current month. So unlike the ISO week number which is computed from the beginning of the year, here the computation is done from the beginning of the current month and therefore the result is a number between 1 and 5. Here are a few examples for June 2020:
Date in the current month Week number per current month
========================== ===============================
2020-06-01 -----> 1
2020-06-10 -----> 2
2020-06-19 -----> 3
2020-06-23 -----> 4
2020-06-23 -----> 5
I was reading the online documentation: Date/Time Functions and Operators It seems that there is no function providing directly what I'm looking for. So after a few successful tests, here is the solution that I found:
select
extract('week' from current_date) -
extract('week' from date_trunc('month', current_date))
+ 1;
I consider myself to be rather a beginner in using date functions, so just to make sure that I'm on the right track, do you think that this solution is correct? As I said, after a few tests it seems to me that it gets the job done.
The to_char() method offers such a feature:
W - week of month (1-5) (the first week starts on the first day of the month)
select to_char(current_date, 'W');
It returns a string value, but that can easily be cast to a number.
I need to generate a report on 28th of every month .
So for that I need to run an autosys job.
In that I have a query with the condition
validation_date >= (number of days since last run)
Could you please help me on this .How can I achieve this condition in DB2 ?
This is a monthly job.So I don't want to hard code my previous run date in the query .At the same time I need to get a condition which satisfies for all the months .
Note :
If the query is running on feb 28th ,then feb 28th is not included. I need to get data from january 28th(included) till feb 27th(included)
similarly for march 28th run ,I need to get data from feb 28th(included) till march 27th(included)...Thanks in advance.Please help
Consider putting your report generation in a procedure, and parameterizing the start and end dates. In other words, have something like this:
create procedure monthly_report(
start_date date,
end_date date
)
language sql
begin
... report queries here ...
end
Now you potentially have something much more flexible (depending on the report requirements). If, in the future, you want to run a report on a different day, or for a different length of time, you will be able to do that.
Once you design it this way, it also may be easier to set the dates in your job scheduling script, rather than in SQL. If you did it in SQL, you could do something like this:
call monthly_report(
(select
year(current timestamp - 2 months) ||'-'||
month(current timestamp - 2 months) ||'-'||
'28' from sysibm.sysdummy1
),
(select
year(current timestamp - 1 month) ||'-'||
month(current timestamp - 1 month) ||'-'||
'27' from sysibm.sysdummy1
)
)
You may need to tweak it to handle some edge cases (I'm not exactly sure if you care what happens if it runs on the 29th of the month, and if so, how to handle it). But you get the basic approach.
You can use DAY() function that extracts day of month from date and you can use it for triggering job. for example where day(param)=28.
other two parameters can be calculated with date calculation , here is example for trigger , date_to value and date_from value
select day(timestamp_format(20170228,'yyyyMMdd') ),timestamp_format(20170228,'yyyyMMdd')- 1 DAY,timestamp_format(20170228,'yyyyMMdd') -1 month from sysibm.sysdummy1;
if your parameter/column is date/timestamp you can remove timestamp_format(20170228,'yyyyMMdd') function and just put your column/parameter
I have read in this online PostgreSQL documentation... http://www.postgresql.org/docs/9.4/static/datatype-datetime.html#INTERVAL-STYLE-OUTPUT-TABLE
in the point 8.5.5 something about how to tweak the default Interval Output. . I mean the default interval is shown like this...
00:00:00.000 (if the timedifference is lower than a day or month or year)
1 day 00:00:00.000 (if the timedifference reaches days, but is lower than a month or a year)
1 month 1 day 00:00:00.000 (if the timediffence reaches months, but is lower than a year)
1 year 1 month 1 day 00:00:00.000 (if it reaches years, months, days)
it evens uses plurarl cases (years, mons, days) when their values are greater than one.
All these variations make difficult to any other app when SELECTing (query) this interval values (as text) to convert it to a proper time. So I would like postgresql to always show year, month n days, even if their value are 0 (it could be even better if it could show the date part of the interval like this... 01-11-30, adding zeros to the left side when values are less than ten)
I know I can change the interval to text, using to_char() but I really would like to avoid that, I would like some good fellow postgresql programmer to tell me if it is true that there is a way to tweak the Interval Output as is said in the postgresql documentation.
Thanks Advanced.
PD: two more links about the subject
https://my.vertica.com/docs/7.1.x/HTML/Content/Authoring/SQLReferenceManual/Statements/SET/SETDATESTYLE.htm
http://my.vertica.com/docs/6.1.x/HTML/index.htm#13874.htm
You can set the interval output style, but only to one of a few pre-defined formats that are unambigious on input, and that PostgreSQL knows how to parse back into intervals. Per the documentation these are the SQL standard interval format, two variants of PostgreSQL specific syntax, and iso_8601 intervals.
If you want something familiar and easy to parse, consider using:
SET intervalstyle = 'iso_8601'
and using an off-the-shelf parser for ISO1601 intervals.
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
I need to change the week start date from Monday to Saturday in PostgreSQL. I have tried SET DATEFIRST 6; but it doesn't work in PostgreSQL. Please suggest solution for this.
It appears that DATEFIRST is a thing in Microsoft Transact-SQL.
I don't believe Postgres has any exact equivalent, but you should be able to approximate it.
Postgres supports extracting various parts of a TIMESTAMP via the EXTRACT function. For your purposes, you would want to use either DOW or ISODOW.
DOW numbers Sunday (0) through Saturday (6), while ISODOW, which adheres to the ISO 8601 standard, numbers Monday (1) through Sunday (7).
From the Postgres doc:
This:
SELECT EXTRACT(DOW FROM TIMESTAMP '2001-02-18 20:38:40');
Returns 0, while this:
SELECT EXTRACT(ISODOW FROM TIMESTAMP '2001-02-18 20:38:40');
Returns 7.
So you would use a version of EXTRACT in your queries to get the day of the week number. If you're going to use it in many queries, I would recommend creating a function which would centralize the query in one spot, and return the number transposed as you would like such that it started on Saturday (the transposition would vary depending on which numbering method you used in EXTRACT). Then you could simply call that function in any SELECT and it would return the transposed number.
You can just add +x, where x is the offset between postgres dow and what you want to achieve.
For example:
You want Sunday to be the first day of the week. 2018-06-03 is a Sunday and you want to extract the dow of it:
SELECT EXTRACT(DOW FROM DATE '2018-06-03')+1;
returns 1
That is probably the reason why postgres dow yields 0 for Sunday. Would it be 7, then
SELECT EXTRACT(DOW FROM DATE '2018-06-03')+1;
would return 8.