current year and quantity days in month - date

I have two questions:
How can I get current year (not date) in haskell ?
How can I get quantity days in some month some year ? For example 04.2011 has got 30 days.

This will give you the year, month and day:
import Data.Time.Clock
import Data.Time.Calendar
date :: IO (Integer,Int,Int) -- :: (year,month,day)
date = getCurrentTime >>= return . toGregorian . utctDay
Source: http://www.haskell.org/haskellwiki/Date
There's a function in Date.Time.Calendar called gregorianMonthLength with type Integer -> Int -> Int.
It takes a year and a month as arguments, returns the number of days, just like you need.
http://www.haskell.org/ghc/docs/7.0.2/html/libraries/time-1.2.0.3/Data-Time-Calendar.html
A full example:
import Data.Time.Clock
import Data.Time.Calendar
date :: IO (Integer,Int,Int) -- :: (year,month,day)
date = getCurrentTime >>= return . toGregorian . utctDay
main = do
(year, month, day) <- date
putStrLn $ "Days in this month: " ++ (show $ gregorianMonthLength year month)

Related

Date listing at postgresql

and date(p.date_of_sale) <= current_date
I try this code and I got an answer like that.
.
But an error is shown like that.
.
Please watch 2 screenshots because I am not fluent in English and I don't know how to explain with text. That's why I add 2 screenshots.
Your problem comes from to_char(p.date_of_sale, 'yyyy "-week" iw') where
iw = week number of ISO 8601 week-numbering year (01–53; the first Thursday of the year is in week 1)
whereas yyyy = the year on 4 digits (not the ISO8601 year)
These two parameters are sometimes not consistent for instance for 2023 January the 1st :
SELECT to_char('20230101' :: date, 'yyyy') => 2023
SELECT to_char('20230101' :: date, 'iw') => 52
If you want to be consistent, you can either :
select to_char('20230101' :: date, 'YYYY"-week" w') => 2023-week 1
or
select to_char('20230101' :: date, 'IYYY"-week" iw') => 2022-week 52 (ISO8601 year and week)
see dbfiddle

write a function that generates a list of last days of each month for the past n months from current date

I am trying to create a list of the last days of each month for the past n months from the current date but not including current month
I tried different approaches:
def last_n_month_end(n_months):
"""
Returns a list of the last n month end dates
"""
return [datetime.date.today().replace(day=1) - datetime.timedelta(days=1) - datetime.timedelta(days=30*i) for i in range(n_months)]
somehow this partly works if each every month only has 30 days and also not work in databricks pyspark. It returns AttributeError: 'method_descriptor' object has no attribute 'today'
I also tried the approach mentioned in Generate a sequence of the last days of all previous N months with a given month
def previous_month_ends(date, months):
year, month, day = [int(x) for x in date.split('-')]
d = datetime.date(year, month, day)
t = datetime.timedelta(1)
s = datetime.date(year, month, 1)
return [(x - t).strftime('%Y-%m-%d')
for m in range(months - 1, -1, -1)
for x in (datetime.date(s.year, s.month - m, s.day) if s.month > m else \
datetime.date(s.year - 1, s.month - (m - 12), s.day),)]
but I am not getting it correctly.
I also tried:
df = spark.createDataFrame([(1,)],['id'])
days = df.withColumn('last_dates', explode(expr('sequence(last_day(add_months(current_date(),-3)), last_day(add_months(current_date(), -1)), interval 1 month)')))
I got the last three months (Sep, oct, nov), but all of them are the 30th but Oct has Oct 31st. However, it gives me the correct last days when I put more than 3.
What I am trying to get is this:
(last days of the last 4 months not including last_day of current_date)
daterange = ['2022-08-31','2022-09-30','2022-10-31','2022-11-30']
Not sure if this is the best or optimal way to do it, but this does it...
Requires the following package since datetime does not seem to have anyway to subtract months as far as I know without hardcoding the number of days or weeks. Not sure, so don't quote me on this....
Package Installation:
pip install python-dateutil
Edit: There was a misunderstanding from my end. I had assumed that all dates were required and not just the month ends. Anyways hope the updated code might help. Still not the most optimal, but easy to understand I guess..
# import datetime package
from datetime import date, timedelta
from dateutil.relativedelta import relativedelta
def previous_month_ends(months_to_subtract):
# get first day of current month
first_day_of_current_month = date.today().replace(day=1)
print(f"First Day of Current Month: {first_day_of_current_month}")
# Calculate and previous month's Last date
date_range_list = [first_day_of_current_month - relativedelta(days=1)]
cur_iter = 1
while cur_iter < months_to_subtract:
# Calculate First Day of previous months relative to first day of current month
cur_iter_fdom = first_day_of_current_month - relativedelta(months=cur_iter)
# Subtract one day to get the last day of previous month
cur_iter_ldom = cur_iter_fdom - relativedelta(days=1)
# Append to the list
date_range_list.append(cur_iter_ldom)
# Increment Counter
cur_iter+=1
return date_range_list
print(previous_month_ends(3))
Function to calculate date list between 2 dates:
Calculate the first of current month.
Calculate start and end dates and then loop through them to get the list of dates.
I have ignored the date argument, since I have assumed that it will be for current date. alternatively it can be added following your own code which should work perfectly.
# import datetime package
from datetime import date, timedelta
from dateutil.relativedelta import relativedelta
def gen_date_list(months_to_subtract):
# get first day of current month
first_day_of_current_month = date.today().replace(day=1)
print(f"First Day of Current Month: {first_day_of_current_month}")
start_date = first_day_of_current_month - relativedelta(months=months_to_subtract)
end_date = first_day_of_current_month - relativedelta(days=1)
print(f"Start Date: {start_date}")
print(f"End Date: {end_date}")
date_range_list = [start_date]
cur_iter_date = start_date
while cur_iter_date < end_date:
cur_iter_date += timedelta(days=1)
date_range_list.append(cur_iter_date)
# print(date_range_list)
return date_range_list
print(gen_date_list(3))
Hope it helps...Edits/Comments are welcome - I am learning myself...
I just thought a work around I can use since my last codes work:
df = spark.createDataFrame([(1,)],['id'])
days = df.withColumn('last_dates', explode(expr('sequence(last_day(add_months(current_date(),-3)), last_day(add_months(current_date(), -1)), interval 1 month)')))
is to enter -4 and just remove the last_date that I do not need days.pop(0) that should give me the list of needed last_dates.
from datetime import datetime, timedelta
def get_last_dates(n_months):
'''
generates a list of lastdates for each month for the past n months
Param:
n_months = number of months back
'''
last_dates = [] # initiate an empty list
for i in range(n_months):
last_dates.append((datetime.today() - timedelta(days=i*30)).replace(day=1) - timedelta(days=1))
return last_dates
This should give you a more accurate last_days

Create list of dates from start/end date in Haskell

Starting from the following date range:
startDate = "2020-01-01"
endDate = "2021-01-01"
What would be the most appropriate way to create a list of dates, say, weekly, from start to end?
result = ["2020-01-01", "2020-01-08", "2020-01-15", "2020-01-22"] -- and so on until 2021-01-01
import Data.Time.Calendar
main :: IO ()
main = print [fromGregorian 2020 1 1, fromGregorian 2020 1 8 .. fromGregorian 2021 1 1]
[2020-01-01,2020-01-08,2020-01-15,2020-01-22,2020-01-29,2020-02-05,2020-02-12,2020-02-19,2020-02-26,2020-03-04,2020-03-11,2020-03-18,2020-03-25,2020-04-01,2020-04-08,2020-04-15,2020-04-22,2020-04-29,2020-05-06,2020-05-13,2020-05-20,2020-05-27,2020-06-03,2020-06-10,2020-06-17,2020-06-24,2020-07-01,2020-07-08,2020-07-15,2020-07-22,2020-07-29,2020-08-05,2020-08-12,2020-08-19,2020-08-26,2020-09-02,2020-09-09,2020-09-16,2020-09-23,2020-09-30,2020-10-07,2020-10-14,2020-10-21,2020-10-28,2020-11-04,2020-11-11,2020-11-18,2020-11-25,2020-12-02,2020-12-09,2020-12-16,2020-12-23,2020-12-30]
[I'm not really a fan of this Show instance BTW, as that's totally not sensible Haskell code...]
you can use (fromGregonorianValid,addDays) from Data.Time.Calendar
import Data.Time.Calendar
import Data.Time
getDates :: String -> String -> [String]
getDates from to
| null jdateFrom || null jdateTo = error "error in dates"
| otherwise = map show [dateFrom,addDays 7 dateFrom..dateTo]
where
jdateFrom = getDate from
jdateTo = getDate to
(Just dateFrom) = getDate from
(Just dateTo) = getDate to
getDate dateStr = parseTimeM True defaultTimeLocale "%Y-%-m-%-d" dateStr :: Maybe Day
> getDates "2020-01-01" "2021-01-01"
["2020-01-01","2020-01-08","2020-01-15","2020-01-22","2020-01-29","2020-02-05","2020-02-12","2020-02-19","2020-02-26","2020-03-04","2020-03-11","2020-03-18","2020-03-25","2020-04-01","2020-04-08","2020-04-15","2020-04-22","2020-04-29","2020-05-06","2020-05-13","2020-05-20","2020-05-27","2020-06-03","2020-06-10","2020-06-17","2020-06-24","2020-07-01","2020-07-08","2020-07-15","2020-07-22","2020-07-29","2020-08-05","2020-08-12","2020-08-19","2020-08-26","2020-09-02","2020-09-09","2020-09-16","2020-09-23","2020-09-30","2020-10-07","2020-10-14","2020-10-21","2020-10-28","2020-11-04","2020-11-11","2020-11-18","2020-11-25","2020-12-02","2020-12-09","2020-12-16","2020-12-23","2020-12-30"]

Parse a user input string into Day type and subtract two dates in Haskell

I'm new to Haskell and I need some help. I will like to create a function that takes in a user's input in the format yyyy, mm, dd and convert it to type Day in order to use diffDays.
This is what I tried:
today :: IO (Integer, Int, Int)
today = getCurrentTime >>= return . toGregorian . utctDay
getDiffDays' :: IO Integer
getDiffDays' = do
putStr "What is your birthdate (year, month, day)?: "
dateOfBirth <- getLine
let dob = read dateOfBirth :: Day
return diffDays today dob
I think you want something below,
import Data.Time.Calender
import Data.List (intercalate)
replace :: String -> String
replace src = intercalate "-" $ words $ filter (/= ',') src
main :: IO ()
main = do
-- Example input: 2018, 11, 12
dayString <- getLine
let day = read (replace dayString) :: Day
-- Example output: 2018-11-12
print day
the problem was that Day expect to read of format YYYY-MM-DD but YYYY, MM, DD

How do you concisely create a Date in Purescript, when you know statically that the year + month + date are valid

Data.Date.canonicalDate constructs a Date value, but you need a Year, Month and Day value as arguments:
Since Month is known statically, you can just hard-code it: e.g. June
Year and Day can't be hard-coded, though, even though you know them statically. You have to call toEnum, and that only gives you a Maybe Year / Maybe Day.
My current solution is this, which seems like a crazy hack:
hackyMakeDate :: Int -> Month -> Int -> Date
hackyMakeDate year month day = fromMaybe (canonicalDate bottom bottom bottom) maybeDate
where
maybeDate = do
year' <- toEnum year
day' <- toEnum day
pure $ canonicalDate year' month day'
Is there a simpler way?
If you're ok with just crashing when year and/or day are out of range (a decision I strongly urge you to rethink), then you can use fromJust (which is a partial function) along with unsafePartial to hide the partiality:
makeDate :: Int -> Month -> Int -> Date
makeDate year month day =
unsafePartial $ fromJust $
canonicalDate <$> toEnum year <#> month <*> toEnum day
Alternatively, you can opt to not hide the partiality:
partialMakeDate :: Partial => Int -> Month -> Int -> Date
partialMakeDate year month day =
fromJust $
canonicalDate <$> toEnum year <#> month <*> toEnum day
This way, at least your consumers will know that the function is really partial.