i will manage my calender about a simply script which is moving calender items 60 minutes further.
For this feature is take this Google Apps Script:
function myFunction() {
var cal = CalendarApp.getCalendarById("myCalendar#gmail.com");
cal.createEvent("TTIITTEELL", new Date("02/06/2018 18:00:00"), new Date("02/06/2018 19:00:00"));
var events = cal.getEvents(new Date("02/05/2018"), new Date("02/07/2018"));
for (var i=0;i<events.length;i++) {
if (events[i].getTitle() == "TTIITTEELL") {
var t = events[i].getEndTime();
var text = new Date(events[i].getEndTime()+.........);
}
}
}
The script is running, but i donĀ“t find the logig to create a new Time.
When i take a "+" it is calculation a minus and so - here are some examples:
Take: +5 = from: Tue Feb 06 2018 19:00:00 GMT+0100 (MEZ) --> to: Tue Feb 06 2018 18:55:00 GMT+0100 (MEZ)
Take: -5 = from: Tue Feb 06 2018 19:00:00 GMT+0100 (MEZ) --> to: Tue Feb 06 2018 18:59:59 GMT+0100 (MEZ)
Take: +60 = from: Tue Feb 06 2018 19:00:00 GMT+0100 (MEZ) --> to: Invalid Date
Take: -60*60*24*1000*1000 = from: Tue Feb 06 2018 19:00:00 GMT+0100 (MEZ) --> to: Wed May 13 2015 20:00:00 GMT+0200 (MESZ)
Take: +60*60*24*1000*1000 = from: Tue Feb 06 2018 19:00:00 GMT+0100 (MEZ) --> to: Invalid Date
Where is my mistake?
How about this answer? In your script, events[i].getEndTime() is an object for date. So when the number is added to the object, it dosn't become the result what you want. When you want the addition and subtraction, you can use the following script. Please modify as follows.
From :
var t = events[i].getEndTime();
var text = new Date(events[i].getEndTime()+.........);
To :
In this case, as a sample, I set the unit of +5, -5, +60, -60 to "minutes".
var num = 5; // Please input 5, -5, 60, -60, ...
var t = events[i].getEndTime().getTime();
var text = new Date(t + num * 60 * 1000);
If I misunderstand your question, I'm sorry.
Related
kdb mortals/gods!!
I have an array of datetime string but in a different format
> leads[`firstConversion]
"Wed May 20 2020 08:56:54 GMT-0700 (PDT)"
"Wed May 20 2020 08:56:56 GMT-0700 (PDT)"
"Wed May 20 2020 08:56:56 GMT-0700 (PDT)"
"Wed May 20 2020 08:56:56 GMT-0700 (PDT)"
"Wed May 20 2020 08:56:57 GMT-0700 (PDT)"
"Wed May 20 2020 08:56:58 GMT-0700 (PDT)"
"Wed May 20 2020 08:56:58 GMT-0700 (PDT)"
"Wed May 20 2020 08:56:59 GMT-0700 (PDT)"
"Wed May 20 2020 08:57:00 GMT-0700 (PDT)"
"Wed May 20 2020 08:57:01 GMT-0700 (PDT)"
"Wed May 20 2020 09:06:32 GMT-0700 (PDT)"
"Wed May 20 2020 09:06:32 GMT-0700 (PDT)"
"Wed May 20 2020 09:06:33 GMT-0700 (PDT)"
"Wed May 20 2020 09:06:33 GMT-0700 (PDT)"
"Wed May 20 2020 09:06:35 GMT-0700 (PDT)"
"Wed May 20 2020 09:06:35 GMT-0700 (PDT)"
"Wed May 20 2020 09:07:07 GMT-0700 (PDT)"
"Wed May 20 2020 09:07:09 GMT-0700 (PDT)"
"Wed May 20 2020 09:07:09 GMT-0700 (PDT)"
"Wed May 20 2020 09:07:10 GMT-0700 (PDT)"
what would be the best way to convert them into native kdb timestamp 2020.05.20D09:07:10.0000?
Depending on how predictable/consistent the indices of the relevant part of each string is.. something like the below
q)x!"P"$4_'x
"Wed May 20 2020 08:56:54 GMT-0700 (PDT)"| 2020.05.20D08:56:54.000000000
"Wed May 20 2020 08:56:56 GMT-0700 (PDT)"| 2020.05.20D08:56:56.000000000
"Wed May 20 2020 08:56:56 GMT-0700 (PDT)"| 2020.05.20D08:56:56.000000000
"Wed May 20 2020 08:56:56 GMT-0700 (PDT)"| 2020.05.20D08:56:56.000000000
"Wed May 20 2020 08:56:57 GMT-0700 (PDT)"| 2020.05.20D08:56:57.000000000
q)
q)// or
q)
q)i:4+til -4+count first x
q)x!"P"$x[;i]
"Wed May 20 2020 08:56:54 GMT-0700 (PDT)"| 2020.05.20D08:56:54.000000000
"Wed May 20 2020 08:56:56 GMT-0700 (PDT)"| 2020.05.20D08:56:56.000000000
"Wed May 20 2020 08:56:56 GMT-0700 (PDT)"| 2020.05.20D08:56:56.000000000
"Wed May 20 2020 08:56:56 GMT-0700 (PDT)"| 2020.05.20D08:56:56.000000000
"Wed May 20 2020 08:56:57 GMT-0700 (PDT)"| 2020.05.20D08:56:57.000000000
q)
q)x:2000000#x
q)
q)\ts "P"$4_'x
495 161554832
q)\ts "P"$x[;i]
538 161554768
You could use the .qdate library https://code.kx.com/developer/libraries/date-parser/
It can parse to UTC or leave in original timezone:
q).qdate.resolve["%a %b %d %Y %T %z"] "Wed May 20 2020 09:07:10 GMT-0700 (PDT)"
2020.05.20D16:07:10.000000000
q).qdate.resolve["%a %b %d %Y %T"] "Wed May 20 2020 09:07:10 GMT-0700 (PDT)"
2020.05.20D09:07:10.000000000
Here's one way:
q)t:("Wed May 20 2020 09:07:09 GMT-0700 (PDT)";"Wed May 20 2020 09:07:10 GMT-0700 (PDT)");
q)update stamp:"P"$" "0:(date;month;year;time) from flip `month`date`year`time!(" SIIT";" ")0:t
month date year time stamp
----------------------------------------------------------
May 20 2020 09:07:09.000 2020.05.20D09:07:09.000000000
May 20 2020 09:07:10.000 2020.05.20D09:07:10.000000000
scala> val dates = filtering1.map(x => (format.parse(x._1),format.parse(x._2)))
dates: org.apache.spark.rdd.RDD[(java.util.Date, java.util.Date)] = MapPartitionsRDD[7] at map at <console>:34
stores below values
scala> dates.collect
res0: Array[(java.util.Date, java.util.Date)] = Array((Sat Jun 30 23:42:00 IST 2018,Thu Jul 04 15:10:00 IST 2019), (Sat Jun 30 23:37:00 IST 2018,Sun Jul 01 14:44:00 IST 2018), (Sat Jun 30 23:13:00 IST 2018,Sun Feb 28 23:34:00 IST 219), (Sat Jun 30 22:58:00 IST 2018,Mon Jul 01 18:22:00 IST 2019), (Sat Jun 30 22:36:00 IST 2018,Mon Jul 01 16:01:00 IST 2019), (Sat Jun 30 21:53:00 IST 2018,Tue Jul 02 10:36:00 IST 2019), (Sat Jun 30 21:42:00 IST 2018,Sun Jun 30 23:25:00 IST 2019), (Sat Jun 30 21:36:00 IST 2018,Mon Jul 01 16:47:00 IST 2019), (Sat Jun 30 21:16:00 IST 2018,Mon Jul 01 18:18:00 IST 2019), (Sat Jun 30 21:10:00 IST 2018,Thu Jul 04 12:25:00 IST 2019), (Sat Jun 30 21:02:00 IST 2018,Sat Dec 01 17:29:00 IST 2018), (Sat Jun 30 20:54:00 IST 2018,Mon Jul 01 15:51:00 IST 2019), (Sat Jun 30 ...
But how to perform operation so the difference in dates, is grouped together, gives value in minutes.
I have command , it does not give me desired output, what changes should be made?
val time_diff = dates.map(x => (x._2.getTime()-x._1.getTime())/(60*1000)%60)
what is (60*1000)%60) values represent?
getTime gives milliseconds, so dividing by 1000.0 gives seconds and dividing by 1000.0*60 gives minutes. Be aware that dividing a Long by an Int gives you another Long, so you are truncating the resulting minutes to the next lowest integer. Adding modulus 60, % 60, simply wraps the minutes to 0-59, so if you had a 90 minutes difference, that would be 1 hour 30 minutes, and the result of your calculation would just be 30.
val t = System.currentTimeMillis
val x = new java.util.Date(t)
val y = new java.util.Date(t + 10000) // ten seconds later
(y.getTime - x.getTime) / (1000.0 * 60) // 0.167
(y.getTime - x.getTime) / (1000 * 60) // 0 !
First problem when you subtract two times, time might go negative.
Second, getTime returns value in miliseconds.
1000ms = 1 second
So, first there is need to divide it by 1000 to get time in seconds. To get in minutes,divide it again by 60.
Since you require result in minutes.
val time_diff = dates.map(x => (x._2.getTime()-x._1.getTime())/(60*1000))
Is there a safe way to defer the creation of an Observable<T>, but upon creation cache it for a period of time before it must create it again?
Observable.cachedDefer(() -> createExpensiveFiniteObservable().cache(), 5, TimeUnit.MINUTES);
I have data sets that are expensive to construct and I want them cached long enough to support a process, but let them expire approximately between each run.
I've added the functionality to do this to rxjava-extras. The code below depends on rxjava-extras 0.6.8-RC2 or later (which is on Maven Central).
Run the main method below and you will see these results which seem to match the behaviour you desire (a reset of the cache whenever the time gap to next subscribe is >=5 seconds):
source emits Tue Oct 13 21:00:16 AEDT 2015
Tue Oct 13 21:00:16 AEDT 2015
Tue Oct 13 21:00:16 AEDT 2015
Tue Oct 13 21:00:16 AEDT 2015
Tue Oct 13 21:00:16 AEDT 2015
Tue Oct 13 21:00:16 AEDT 2015
source emits Tue Oct 13 21:00:31 AEDT 2015
Tue Oct 13 21:00:31 AEDT 2015
Tue Oct 13 21:00:31 AEDT 2015
Tue Oct 13 21:00:31 AEDT 2015
Tue Oct 13 21:00:31 AEDT 2015
Tue Oct 13 21:00:31 AEDT 2015
source emits Tue Oct 13 21:00:46 AEDT 2015
Tue Oct 13 21:00:46 AEDT 2015
Tue Oct 13 21:00:46 AEDT 2015
...
Main method:
public static void main(String[] args) throws InterruptedException {
Observable<Date> source = Observable
.defer(() ->
Observable
.just(new Date())
.doOnNext(
d -> System.out.println("source emits " + d)));
CloseableObservableWithReset<Date> cached =
Obs.cache(source, 5, TimeUnit.SECONDS, Schedulers.computation());
Observable<Date> o = cached
.observable()
.doOnSubscribe(() -> cached.reset());
for (int i = 0; i < 30; i++) {
o.doOnNext(System.out::println).subscribe();
Thread.sleep((i % 5 + 1)*1000);
}
cached.close();
}
Note that to reset the cache on every emission as well then where you see
.doOnSubscribe(() -> cached.reset())
put
.doOnSubscribe(() -> cached.reset())
.doOnNext(x -> cached.reset())
I'm trying to pipe several perl programs together, and from everything I've read, piped programs are supposed to all open and run in parallel. That doesn't appear to be the case with whatever it is that I did. Here is the simplified version:
./video
#!/usr/bin/env perl
my $i = 0;
while($i<10){
my $time = localtime(time);
print "VID: $time $i\n";
sleep 1;
$i++;
}
./controller
#!/usr/bin/env perl
while(my $line = <STDIN>){
my $time = localtime(time);
print "CTRL: $time $line";
}
./pipes
#!/usr/bin/env perl
open(my $controller, "|./controller") || die "Can't fork: $!";
open(STDOUT, ">&", $controller);
open(my $video, "|./video") || die "Can't fork: $!";
print STDERR "All processes started\n";
I tried executing it two ways, but both resulted in the same output:
<16:34:21> rswhiting#Minas-Tirith:~/code/Pipes $ ./pipes
All processes started
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:22 2014 0
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:23 2014 1
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:24 2014 2
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:25 2014 3
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:26 2014 4
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:27 2014 5
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:28 2014 6
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:29 2014 7
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:30 2014 8
CTRL: Sun Apr 20 16:34:32 2014 VID: Sun Apr 20 16:34:31 2014 9
<16:34:49> rob#Minas-Tirith:~/code/Pipes $ ./video | ./controller
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:15 2014 0
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:16 2014 1
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:17 2014 2
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:18 2014 3
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:19 2014 4
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:20 2014 5
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:21 2014 6
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:22 2014 7
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:23 2014 8
CTRL: Sun Apr 20 16:35:25 2014 VID: Sun Apr 20 16:35:24 2014 9
<16:35:25> rob#Minas-Tirith:~/code/Pipes $
The timestamps from the video program increment as they should, but the time that the control program receives them is identical (after the video program has ended). How do I make the controller receive the data as it is produced instead of after the fact?
It's because of STDOUT buffering in the video program. print is line-buffered only if it goes to an interactive terminal. Otherwise it uses a much bigger buffer, and the accumulated output is emitted in one big chunk when video exits. Try flushing after each print or use autoflush.
$| = 1; # Enables autoflush
By the way I don't get why you open a pipe TO video, it does not read anything. It should be
system "./video";
If you have a program that you can't modify but does not autoflush, you are in trouble. Except, you're not. You can use a pseudoterminal instead of a pipe. I've never done it. But chapter 64 of the book "The UXIX Programming Interface" is about pseudoterminals.
So I would like to use function localtime(), but I'm having problems with getting first and last day of last month properly. Right now I have working functionality, but I bet there is a better way to solve this.
use Time::Piece;
use Time::Seconds;
$start_of_month = localtime();
while($start_of_month->mday < 10) {
$start_of_month += ONE_DAY;
}
$start_of_month -= ONE_MONTH; # Subtract one month to get previous month. "ONE_MONTH" is defined by Time::Seconds
$end_of_month = $start_of_month; # Copy start_of_month to end_of_month as they both have same year and month.
# Subtract day from $start_of_month until mday is the first day of the month.
while($start_of_month->mday != 1) {
$start_of_month -= ONE_DAY;
}
# Silly workaround to bring $end_of_month to last day of the month as Time::Piece object does not have good way to change mday.
while($end_of_month->mday != $start_of_month->month_last_day) {
$end_of_month += ONE_DAY;
}
$period_start = $start_of_month->dmy("."); # End result has to be same!
Can anyone give me a better way of handling this?
Don't rely on Time::Piece and constants in Time::Seconds for date manipulation
The following was my suggested simplification of the OP's date manipulation using Time::Piece and Time::Seconds. IF this worked on overloaded operators, it might actually work as intended, but as ikegami pointed out, this isn't guaranteed. So I tested below.
If you want to go the math route, at least you could simplify things a little:
use strict;
use warnings;
use Time::Piece;
use Time::Seconds;
my $date_start = localtime();
$date_start -= ONE_MONTH;
$date_start -= ($date_start->mday - 1) * ONE_DAY;
my $date_end = $date_start + ($date_start->month_last_day - 1) * ONE_DAY;
print $date_start , "\n"; # Prints Mar 1st (at least today it does)
print $date_end , "\n"; # Prints Mar 31st
I'd consider using a different module for this, like Date::Calc or DateTime, but this might work for your purposes.
Testing the above solution - many failures
I created a script the below script that loops through every date for a year starting at January 15th, showing every range where the above code does not work as expected.
use strict;
use warnings;
use Time::Piece;
use Time::Seconds;
my $t = 1389812400; # Wed 2014-Jan-15 7pm GMT. 11am PST
my $t_max = 1421348400; # Thu 2015-Jan-15 7pm GMT. 11am PST
my %prev_month = map {$_ => ($_ - 1) || 12} (1..12);
my $fail = '';
while ($t <= $t_max) {
$t += 60; # Increment by 1 minute
# Testing potentially overloaded math of Time::Piece & Time::Seconds
my $start = my $src = localtime($t);
$start -= ONE_MONTH;
$start -= ($start->mday - 1) * ONE_DAY;
if ($start->mon != $prev_month{$src->mon}) {
print "From ($t) $src -> $start\n" if !$fail;
$fail = " To ($t) $src -> $start\n\n";
} elsif ($fail) {
print $fail;
$fail = '';
}
}
The below is the output of this script with comments inserted to explain why each range fails:
# ONE_MONTH is exactly 2_629_744 seconds, or 30.437 days.
# ONE_MONTH is too short for January
From (1391193000) Fri Jan 31 10:30:00 2014 -> Wed Jan 1 00:00:56 2014
To (1391241540) Fri Jan 31 23:59:00 2014 -> Wed Jan 1 13:29:56 2014
# ONE_MONTH is too long for February
From (1393660800) Sat Mar 1 00:00:00 2014 -> Wed Jan 1 13:30:56 2014
To (1393871340) Mon Mar 3 10:29:00 2014 -> Wed Jan 1 23:59:56 2014
# ONE_MONTH is too short for March
From (1396290600) Mon Mar 31 11:30:00 2014 -> Sat Mar 1 00:00:56 2014
To (1396335540) Mon Mar 31 23:59:00 2014 -> Sat Mar 1 12:29:56 2014
# ONE_DAY is 86_400 seconds, or 24 hours.
# March 9th is only 23 hours long due to DST, ONE_DAY goes to far.
From (1397064600) Wed Apr 9 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397068140) Wed Apr 9 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397151000) Thu Apr 10 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397154540) Thu Apr 10 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397237400) Fri Apr 11 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397240940) Fri Apr 11 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397323800) Sat Apr 12 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397327340) Sat Apr 12 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397410200) Sun Apr 13 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397413740) Sun Apr 13 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397496600) Mon Apr 14 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397500140) Mon Apr 14 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397583000) Tue Apr 15 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397586540) Tue Apr 15 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397669400) Wed Apr 16 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397672940) Wed Apr 16 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397755800) Thu Apr 17 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397759340) Thu Apr 17 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397842200) Fri Apr 18 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397845740) Fri Apr 18 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1397928600) Sat Apr 19 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1397932140) Sat Apr 19 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398015000) Sun Apr 20 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398018540) Sun Apr 20 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398101400) Mon Apr 21 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398104940) Mon Apr 21 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398187800) Tue Apr 22 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398191340) Tue Apr 22 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398274200) Wed Apr 23 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398277740) Wed Apr 23 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398360600) Thu Apr 24 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398364140) Thu Apr 24 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398447000) Fri Apr 25 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398450540) Fri Apr 25 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398533400) Sat Apr 26 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398536940) Sat Apr 26 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398619800) Sun Apr 27 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398623340) Sun Apr 27 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398706200) Mon Apr 28 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398709740) Mon Apr 28 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398792600) Tue Apr 29 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398796140) Tue Apr 29 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
From (1398879000) Wed Apr 30 10:30:00 2014 -> Fri Feb 28 23:00:56 2014
To (1398882540) Wed Apr 30 11:29:00 2014 -> Fri Feb 28 23:59:56 2014
# ONE_MONTH is too long for April
From (1398927600) Thu May 1 00:00:00 2014 -> Sat Mar 1 12:30:56 2014
To (1398965340) Thu May 1 10:29:00 2014 -> Sat Mar 1 22:59:56 2014
# ONE_MONTH is too short for May
From (1401557400) Sat May 31 10:30:00 2014 -> Thu May 1 00:00:56 2014
To (1401605940) Sat May 31 23:59:00 2014 -> Thu May 1 13:29:56 2014
# ONE_MONTH is too long for June
From (1404198000) Tue Jul 1 00:00:00 2014 -> Thu May 1 13:30:56 2014
To (1404235740) Tue Jul 1 10:29:00 2014 -> Thu May 1 23:59:56 2014
# ONE_MONTH is too short for July
From (1406827800) Thu Jul 31 10:30:00 2014 -> Tue Jul 1 00:00:56 2014
To (1406876340) Thu Jul 31 23:59:00 2014 -> Tue Jul 1 13:29:56 2014
# ONE_MONTH is too short for August
From (1409506200) Sun Aug 31 10:30:00 2014 -> Fri Aug 1 00:00:56 2014
To (1409554740) Sun Aug 31 23:59:00 2014 -> Fri Aug 1 13:29:56 2014
# ONE_MONTH is too long for September
From (1412146800) Wed Oct 1 00:00:00 2014 -> Fri Aug 1 13:30:56 2014
To (1412184540) Wed Oct 1 10:29:00 2014 -> Fri Aug 1 23:59:56 2014
# ONE_MONTH is too short for October
From (1414776600) Fri Oct 31 10:30:00 2014 -> Wed Oct 1 00:00:56 2014
To (1414825140) Fri Oct 31 23:59:00 2014 -> Wed Oct 1 13:29:56 2014
# ONE_MONTH is too long for November
From (1417420800) Mon Dec 1 00:00:00 2014 -> Wed Oct 1 14:30:56 2014
To (1417454940) Mon Dec 1 09:29:00 2014 -> Wed Oct 1 23:59:56 2014
# ONE_MONTH is too short for December
From (1420050600) Wed Dec 31 10:30:00 2014 -> Mon Dec 1 00:00:56 2014
To (1420099140) Wed Dec 31 23:59:00 2014 -> Mon Dec 1 13:29:56 2014
Alternative using Time::Piece->add_months? Nope
Time::Piece has two functions, add_months and add_years intended for date calculations. Unfortunately, the documentation states:
Note that there is some "strange" behaviour when adding and subtracting months at the ends of months. Generally when the resulting month is shorter than the starting month then the number of overlap days is added. For example subtracting a month from 2008-03-31 will not result in 2008-02-31 as this is an impossible date. Instead you will get 2008-03-02. This appears to be consistent with other date manipulation tools.
The below code fully demonstrates this behavior for the timezone PST.
use strict;
use warnings;
use Time::Piece;
my $t = localtime(1420012800);
print $t->add_months($_),"\n" for (0..12)
Output:
Wed Dec 31 00:00:00 2014
Sat Jan 31 00:00:00 2015
Tue Mar 3 00:00:00 2015
Tue Mar 31 00:00:00 2015
Fri May 1 00:00:00 2015
Sun May 31 00:00:00 2015
Wed Jul 1 00:00:00 2015
Fri Jul 31 00:00:00 2015
Mon Aug 31 00:00:00 2015
Thu Oct 1 00:00:00 2015
Sat Oct 31 00:00:00 2015
Tue Dec 1 00:00:00 2015
Thu Dec 31 00:00:00 2015
Now, it is kind of nice how this function is able to accurately cycle back to the same date a year later, but there are lots of unfavorable months until then.
Conclusion
The constants in Time::Seconds are just that, constants. They are exact numbers of seconds meant to represent periods of time. There is no operator overloading to facilitate fancy date manipulation. Instead, these values are simply good for mathematical comparisons.
To manipulate specific dates, I'd advise using Date::Calc, DateTime, or any of the other modules suggested in this question.
A less OO, but alternate solution:
use POSIX qw(mktime);
my #now = localtime;
# mday = 1, month = month - 1
my $date_start = mktime(#now[0 .. 2], 1, $now[4] - 1, #now[5 .. 8]);
# mday = 0, the 0th day of this month == last day of prior month
my $date_end = mktime(#now[0 .. 2], 0, #now[4 .. 8]);
print scalar localtime $date_start, "\n";
print scalar localtime $date_end, "\n";
This hiccups with daylight saving time; if you don't care about time-of-day you could set $now[2] to 12 noon and hope no country declares night to be day and day to be night:
my #now = (0, 0, 12, (localtime)[3..8]);
I don't trust code that uses Time::Piece. It relies on overloading operators to make it look like you're doing it wrong ($time += ONE_DAY; looks like you're adding a constant) when you're actually doing it right. Maybe. It's hard to tell. You must have intimate knowledge of the guts of the module to know if you're doing it right.
DateTime solution:
my $dt = DateTime
->now( time_zone => 'local' )
->set_time_zone('floating') # Do this when you want to date arithmetic.
->truncate( to => 'day' );
$dt->set( day => 1 )->subtract( days => 1 );
my $last = $dt->ymd('-');
$dt->set( day => 1 );
my $first = $dt->ymd('-');
say "$first .. $last";
Using the Time::Seconds definition of ONE_MONTH gives you a solution that is wrong for several days a year. It is the average length of a month in seconds, and is equal to about 30.4 days. Subtracting that from 1 March, for instance, gives you a date in late January.
However the first day of the previous month can be calculated simply from the month and day fields returned by localtime. Converting this into a Time::Piece object lets us calculate the last day of the same month.
use strict;
use warnings;
use Time::Piece;
my ($m, $y) = (localtime)[4,5];
$y += 1900;
if ($m == 0) {
$m = 11;
$y -= 1;
}
my $period_start = sprintf '%02d.%02d.%04d', 1, $m, $y;
my $period_end = do {
my $tp = Time::Piece->strptime($period_start, '%d.%m.%Y');
sprintf '%02d.%02d.%04d', $tp->month_last_day, $m, $y;
};
print $period_start, "\n";
print $period_end, "\n";
output
01.03.2014
31.03.2014
Sorry if I did not understood property but: DaysInMonth (check coment)
my #monthDays= qw( 31 28 31 30 31 30 31 31 30 31 30 31 );
sub MonthDays {
my $month= shift(#_);
my $year= #_ ? shift(#_) : 1900+(localtime())[5];
if( $year <= 1752 ) {
# Note: Although September 1752 only had 19 days,
# they were numbered 1,2,14..30!
return 19 if 1752 == $year && 9 == $month;
return 29 if 2 == $month && 0 == $year % 4;
} else {
return 29 if 2 == $month and
0 == $year%4 && 0 != $year%100 || 0 == $year%400;
}
return $monthDays[$month-1];
}
If you wish easy data to seconds then take look Time::Local
$time = timelocal( $sec, $min, $hour, $mday, $mon, $year );