Start and end date of previous quarter in perl - perl

I am new to Perl and I am trying to figure out how to get the start and end date of the previous quarter. For example:
Jan 2nd, 2020 - The output should be 20191001, 20191231
July 27th, 2020 - The output should be 20200401, 20200630
Thanks in advance for all the help and guidance.

use DateTime qw( );
my $prev_quarter_start =
DateTime
->now( time_zone => 'local' )
->set_time_zone('floating') # Use this when dealing with dates.
->truncate( to => 'quarter' )
->subtract( months => 3 );
my $prev_quarter_end =
$prev_quarter_start
->clone
->add( months => 3 )
->subtract( days => 1 );
say $prev_quarter_start ->ymd('');
say $prev_quarter_end->ymd('');
Requires DateTime 1.32.

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

Is there a way in dart to calculate the date for the last week as a maximum by describing popular words

i am using the following code
DateFormat.yMMMMEEEEd("en_US").format((myDateTime)
that give me the following output (Date of writing my question)
Tuesday June 21 , 2022
well , now i don't want the previous format look like the previous output UNLESS if there is one week back as a maximum Period
for example i am looking for Format to Auto describe days of the week by (names) like following.
Assuming today is Tuesday
output => 'now' (if 5 mins as maximum ) else output => 'Today'
else:
output => 'yesterday' (if there one day back )
output => 'Sunday'
output => 'Saturday'
output => 'Friday'
output => 'Thursday'
output => 'Wednesday'
NOW finally we arrive to same day whish is Tuesday that means 1 week passed so i need output like my first format in my question
output => 'Tuesday June 21 , 2022'
And so
output => 'Tuesday June 21 , 2022'
output => 'Monday June 20 , 2022'
output => 'Sunday June 19 , 2022' ...... and so
in other words i only care of showing a week back in
their names only : now(if 5 mins as maximum) till A week back in
their names else DateFormat.yMMMMEEEEd("en_US").format((myDateTime)
what is the easiest and best way to do it . thanks

Generate Series of month and years

How do I generate a series of month and year dates which I can use as a parameter to pass to other data tables.
For example, I am currently using:
MonthYearSelector = GENERATESERIES(DATE(2019,1,1), DATE(2019,12,1),30)
However, this generates the following dates:
01 January 2019
31 January 2019
02 March 2019
...
What I want is the following list:
01 January 2019
01 February 2019
01 March 2019
....
MonthYearSelector = GENERATESERIES(DATE(2019,1,1), DATE(2019,12,1),30)
How about something like this?
MonthYearSelector =
VAR Years = SELECTCOLUMNS( {2018, 2019}, "Year", [Value] )
VAR Months = SELECTCOLUMNS( GENERATESERIES(1, 12, 1), "Month", [Value] )
RETURN
ADDCOLUMNS(
CROSSJOIN( Years, Months ),
"Date", DATE( [Year], [Month], 1 )
)
In the above, I use SELECTCOLUMNS just to rename the default Value column name.
Try this out.. It's basically give you start of the month & End of the Month... your choice to use..
Start of Month Dates =
GENERATE (
GENERATESERIES(1,48),
VAR inc = [Value]
RETURN ROW (
"date", DATE(2017,inc,1),
"Month End",EOMONTH(DATE(2017,inc,1),0)
)
)
Check this for details

Perl Date::Parse - how to correctly parse dates between 1901 and 1969

Background
I am using Perl to parse dates and datetimes input by users who aren't too careful with their formatting. The Perl module Date::Parse seems great because it handles most cases I need to handle.
Except datetimes between 1901-01-01 00:00:00 and 1968-12-31 23:59:59, as I found out today. For those datetimes, Date::Parse str2time adds an extra 100 years when it parses the datetime to epoch time.
Code
Here is the code I am using to parse the datetimes:
#!/usr/bin/perl
#---------------------------------------------------------------------
# format_date.pl
#
# format variable date inputs
#---------------------------------------------------------------------
use strict;
use warnings;
use Date::Parse;
use DateTime;
my $DEFAULT_TIME_ZONE = "GMT";
my #dates = (
"1899-06-24 09:44:00",
"1900-12-31 23:59:59",
"1901-01-01 00:00:00",
"1960-12-31 23:59:59",
"1966-06-24 09:44:00",
"1968-12-31 23:59:59",
"1969-01-01 00:00:00",
"1969-12-31 23:59:59",
"1970-01-01 00:00:01",
"2000-01-01 00:00:00",
"2017-06-24 23:59:59",
"2018-06-24 09:44:00",
"2238-06-24 09:44:00"
);
foreach my $string (#dates) {
# format datetime field from any valid datetime input
# default time zone is used if timezone is not included in string
my $epoch = str2time( $string, $DEFAULT_TIME_ZONE );
# error if date is not correctly parsed
if ( !$epoch ) {
die("ERROR ====> invalid datetime ($string), "
. "datetime format should be YYYY-MM-DD HH:MM:SS");
}
my $date = DateTime->from_epoch( epoch => $epoch );
printf( "formatting datetime: value = %20s, epoch = %20u, "
. "date = %20s\n", $string, $epoch, $date );
}
exit 0;
Side note: I need to improve my error handling because the valid date 1970-01-01 00:00:00 will throw an error.
Output
The additional 100 years for dates between 1901 and 1969 can be seen in the output:
formatting datetime: value = 1899-06-24 09:44:00, epoch = 18446744071484095456, date = 1899-06-24T09:44:00
formatting datetime: value = 1900-12-31 23:59:59, epoch = 18446744071532098815, date = 1900-12-31T23:59:59
formatting datetime: value = 1901-01-01 00:00:00, epoch = 978307200, date = 2001-01-01T00:00:00
formatting datetime: value = 1960-12-31 23:59:59, epoch = 2871763199, date = 2060-12-31T23:59:59
formatting datetime: value = 1966-06-24 09:44:00, epoch = 3044598240, date = 2066-06-24T09:44:00
formatting datetime: value = 1968-12-31 23:59:59, epoch = 3124223999, date = 2068-12-31T23:59:59
formatting datetime: value = 1969-01-01 00:00:00, epoch = 18446744073678015616, date = 1969-01-01T00:00:00
formatting datetime: value = 1969-12-31 23:59:59, epoch = 18446744073709551615, date = 1969-12-31T23:59:59
formatting datetime: value = 1970-01-01 00:00:01, epoch = 1, date = 1970-01-01T00:00:01
formatting datetime: value = 2000-01-01 00:00:00, epoch = 946684800, date = 2000-01-01T00:00:00
formatting datetime: value = 2017-06-24 23:59:59, epoch = 1498348799, date = 2017-06-24T23:59:59
formatting datetime: value = 2018-06-24 09:44:00, epoch = 1529833440, date = 2018-06-24T09:44:00
formatting datetime: value = 2238-06-24 09:44:00, epoch = 8472332640, date = 2238-06-24T09:44:00
Additional notes
The Date::Parse documentation suggests it can handle dates at least as old at 1901-01-01. The Time::Local documentation suggest it should be able handle dates even older.
Question
How should I handle this oddity? Is there a better way to parse variable input formats suing Perl?
Edit: examples of multiple date formats
Input can be in multiple formats. Here is an array of examples:
my #dates = (
"2018-02-20 00:00:00",
"20180220",
"02/20/2018",
"02/20/18", # interpreted as 1918-02-20
"2018-02-20"
);
The underlying issue was answered by tangent.
The problem is with Date::Parse - see this issue. Full answer on perlmonks – tangent
Solution 1
My solution is to use Date::Parse strptime instead of str2time.
Date::Parse strptime parse the date into an array ( $ss, $mm, $hh, $day, $month, $year, $zone ). That allows the year to be converted back to a 4-digit year using:
if ( $year < 1000 ) { $year += 1900; }
The date is then passed into DateTime->new().
Solution 2 (better)
Based on discussion with thanos on perlmonks, I explored using the Date::Manip module to parse datetimes. This simplified parsing variable inputs to as little as one line. It even handles 2-digit years correctly. Here is a snippet of the code:
say UnixDate( ParseDate($_), '%Y-%m-%d %T' ) for (#dates);
See example scripts and output on perlmonks.
Just to add another possible solution using module Date::Manip.
use Date::Manip;
use use feature 'say';
foreach my $datestr (#dates) {
my $epochSecs = UnixDate($datestr,'%s');
my $date = UnixDate( ParseDateString("epoch $epochSecs"), "%Y-%m-%d %T");
say "Date value = ".$datestr.", epoch = ".$epochSecs.", date = " .$date;
}
Hope this helps, BR.
Epoch time is the number of seconds since 1970-01-01T00:00:00Z. The date your are trying to convert to epoch time is earlier than this.
Why are you using two different date-time libraries? If you want a DateTime object, use a DateTime module.
use DateTime::Format::DateParse qw( );
for my $dt_str (#dates) {
my $dt = DateTime::Format::DateParse->parse_datetime($dt_str, $DEFAULT_TIME_ZONE)
or die(...);
...
}
Produces:
1899-06-24 09:44:00 => 3799-06-24T09:44:00 <- doh!
1900-12-31 23:59:59 => 3800-12-31T23:59:59 <- doh!
1901-01-01 00:00:00 => 1901-01-01T00:00:00
1960-12-31 23:59:59 => 1960-12-31T23:59:59
1966-06-24 09:44:00 => 1966-06-24T09:44:00
1968-12-31 23:59:59 => 1968-12-31T23:59:59
1969-01-01 00:00:00 => 1969-01-01T00:00:00
1969-12-31 23:59:59 => 1969-12-31T23:59:59
1970-01-01 00:00:01 => 1970-01-01T00:00:01
2000-01-01 00:00:00 => 2000-01-01T00:00:00
2017-06-24 23:59:59 => 2017-06-24T23:59:59
2018-06-24 09:44:00 => 2018-06-24T09:44:00
2238-06-24 09:44:00 => 2238-06-24T09:44:00
2018-02-20 00:00:00 => 2018-02-20T00:00:00
20180220 => 2018-02-20T00:00:00
02/20/2018 => 2018-02-20T00:00:00
02/20/18 => 1918-02-20T00:00:00
2018-02-20 => 2018-02-20T00:00:00
Let's avoid DateParse entirely.
use DateTime::Format::Strptime qw( );
use List::MoreUtils qw( first_result );
my #patterns = (
'%Y-%m-%d %H:%M:%S',
'%Y-%m-%d',
'%Y%m%d',
'%m/%d/%Y',
'%m/%d/%y',
);
my #formats =
map {
DateTime::Format::Strptime->new(
pattern => $_,
time_zone => $DEFAULT_TIME_ZONE,
on_error => 'undef',
)
}
#patterns;
for my $dt_str (#dates) {
my $dt = first_result { $_->parse_datetime($dt_str) } #formats
or die(...);
...
}
Produces:
1899-06-24 09:44:00 => 1899-06-24T09:44:00
1900-12-31 23:59:59 => 1900-12-31T23:59:59
1901-01-01 00:00:00 => 1901-01-01T00:00:00
1960-12-31 23:59:59 => 1960-12-31T23:59:59
1966-06-24 09:44:00 => 1966-06-24T09:44:00
1968-12-31 23:59:59 => 1968-12-31T23:59:59
1969-01-01 00:00:00 => 1969-01-01T00:00:00
1969-12-31 23:59:59 => 1969-12-31T23:59:59
1970-01-01 00:00:01 => 1970-01-01T00:00:01
2000-01-01 00:00:00 => 2000-01-01T00:00:00
2017-06-24 23:59:59 => 2017-06-24T23:59:59
2018-06-24 09:44:00 => 2018-06-24T09:44:00
2238-06-24 09:44:00 => 2238-06-24T09:44:00
2018-02-20 00:00:00 => 2018-02-20T00:00:00
20180220 => 2018-02-20T00:00:00
02/20/2018 => 2018-02-20T00:00:00
02/20/18 => 2018-02-20T00:00:00
2018-02-20 => 2018-02-20T00:00:00

Perl DateTime "is_dst()" method not working correctly

I'm trying to use the is_dst() method in the DateTime module to determine whether a daylight savings transition is occurring.
I started by writing a very basic example that I was sure would work, but for some reason I'm getting unexpected results.
Example:
#!/usr/bin/perl
use strict;
use warnings;
use DateTime;
my $dt1 = DateTime->new(
'year' => 2015,
'month' => 3 ,
'day' => 8 ,
'hour' => 3 ,
);
my $dt2 = DateTime->new(
'year' => 2015,
'month' => 3 ,
'day' => 7 ,
'hour' => 3 ,
);
print $dt1."\n";
print $dt2."\n";
print $dt1->is_dst()."\n";
print $dt2->is_dst()."\n";
I started with a date that I knew was a daylight savings transition: Sunday, March 8, 2015. I chose 3 AM because I knew that the daylight savings transition would have already occured at that point in time.
Then I took a date that I knew was before the daylight savings transition: Saturday, March 7, 2015 also at 3 AM.
Then I print the two dates and their corresponding DST flags.
Output:
2015-03-08T03:00:00
2015-03-07T03:00:00
0
0
The two dates print exactly as expected, but for some reason even though the first date occurs during daylight savings time, and the second date occurs before daylight savings time, the DST flag is not set for both of them.
Why is this not working correctly? Am I missing something?
You have to explicitly set the time zone:
The default time zone for new DateTime objects, except where stated otherwise, is the "floating" time zone...A floating datetime is one which is not anchored to any particular time zone.
For example:
use strict;
use warnings;
use DateTime;
my $dt1 = DateTime->new(
'year' => 2015,
'month' => 3,
'day' => 8,
'hour' => 3,
'time_zone' => 'America/New_York'
);
my $dt2 = DateTime->new(
'year' => 2015,
'month' => 3,
'day' => 7,
'hour' => 3,
'time_zone' => 'America/New_York'
);
print $dt1."\n";
print $dt2."\n";
print $dt1->is_dst()."\n";
print $dt2->is_dst()."\n";
Output:
2015-03-08T03:00:00
2015-03-07T03:00:00
1
0