AnFi
AnFi

Reputation: 10903

Calculate number of days/weeks/months/years begins between two dates

How to calculate then (integer) number of days/weeks/months/years beginning between two dates?

Dates are provided in epoch seconds as provided by the time function. These examples show times formatted according to ISO 8601.

1 day begin  between 2014-08-24T23:59:59+0200 and 2014-08-25T00:00:01+0200   
0 day begins between 2014-08-25T00:00:01+0200 and 2014-08-25T23:59:59+0200   

Upvotes: 0

Views: 2194

Answers (1)

ikegami
ikegami

Reputation: 385764

To find the number of day/week/month/year starts between timestamps DT1 and DT2 using DateTime,

  1. Find the timestamp for the first second of the day/week/month/year of which DT1 is a part.
  2. Find the timestamp for the first second of the day/week/month/year of which DT2 is a part.
  3. Find the differences in days/weeks/months/years between those two timestamps.

use DateTime qw( );

# Or maybe << time_zone => 'local' >>?
my $dt1 = DateTime->from_epoch( epoch => ..., time_zone => '+0200' );
my $dt2 = DateTime->from_epoch( epoch => ..., time_zone => '+0200' );

# Some days in some time zones don't have a midnight, so switch to 'floating'.
# before truncating. The dts must all be in the same time zone beforehand.
my $date1 = $dt1->clone;
my $date2 = $dt2->clone;
$_->set_time_zone('floating')->truncate( to => 'day' )
   for $date1, $date2;

my $day_starts = $date2->delta_days($date1)->in_units('days');

my $week_starts = do {                   # Sunday starts
   my $date1_week_start = $date1->clone;
   my $date2_week_start = $date2->clone;

   $_->subtract( days => $_->day_of_week % 7 )
      for $date1_week_start, $date2_week_start;

   $date2_week_start->delta_days($date1_week_start)->in_units('weeks')
};

my $month_starts = do {
   my $date1_month_start = $date1->clone;
   my $date2_month_start = $date2->clone;

   $_->truncate( to => 'month' )
      for $date1_month_start, $date2_month_start;

   $date2_month_start->delta_md($date1_month_start)->in_units('months')
};

my $year_starts = abs( $date2->year - $date1->year );

printf("%d years, %d months, %d weeks and %d days begin between %s and %s\n",
   $year_starts,
   $month_starts,
   $week_starts,
   $day_starts,
   $date1->ymd,
   $date2->ymd,
);

my $dt1 = DateTime->new( year => 2014, month => 8, day => 23 );
my $dt2 = DateTime->new( year => 2014, month => 8, day => 24 );

gives

0 years, 0 months, 1 weeks and 1 days begin between 2014-08-23 and 2014-08-24

and

my $dt1 = DateTime->new( year => 2014, month => 1, day => 31 );
my $dt2 = DateTime->new( year => 2014, month => 2, day =>  1 );

gives

0 years, 1 months, 0 weeks and 1 days begin between 2014-01-31 and 2014-02-01

Notes:

  • I assume there are no days missing between the dates in question.
  • It doesn't matter if the earlier time stamp is in $dt1 or $dt2.

Upvotes: 2

Related Questions