use Display;
use Utils;
-our @EXPORT = qw (
+our @EXPORT = qw(
Add
Age
Compare
YMDHMS
timestamp
ymdhms
+ MDYHMS2SQLDatetime
);
my @months = (
my $SECS_IN_DAY = $SECS_IN_HOUR * 24;
# Forwards
-sub Today2SQLDatetime ();
-sub DateToEpoch ($);
-sub EpochToDate ($);
+sub Today2SQLDatetime();
+sub DateToEpoch($);
+sub EpochToDate($);
-sub ymdhms {
+sub ymdhms(;$) {
my ($time) = @_;
$time ||= time;
return $year, $mon, $mday, $hour, $min, $sec;
} # ymdhms
-sub julian ($$$) {
+sub julian($$$) {
my ($year, $month, $day) = @_;
my $days = 0;
my $m = 1;
- foreach (@months) {
+ for (@months) {
last if $m >= $month;
$m++;
$days += $_;
- } # foreach
+ } # for
return $days + $day;
} # julian
-sub _is_leap_year ($) {
+sub _is_leap_year($) {
my ($year) = @_;
-
+
return 0 if $year % 4;
return 1 if $year % 100;
return 0 if $year % 400;
-
+
return 1;
} # _is_leap_year
-sub Add ($%) {
+sub Add($%) {
my ($datetime, %parms) = @_;
-
+
=pod
=head2 Add ($datetime, %parms)
'days',
'months',
);
-
- foreach (keys %parms) {
+
+ for (keys %parms) {
unless (InArray ($_, @validKeys)) {
croak "Invalid key in DateUtils::Add: $_";
} # unless
- } # foreach
-
+ } # for
+
my $epochTime = DateToEpoch $datetime;
-
+
my $amount = 0;
-
+
$parms{seconds} ||= 0;
$parms{minutes} ||= 0;
$parms{hours} ||= 0;
$parms{days} ||= 0;
-
+
$amount += $parms{days} * $SECS_IN_DAY;
$amount += $parms{hours} * $SECS_IN_HOUR;
$amount += $parms{minutes} * $SECS_IN_MIN;
$amount += $parms{seconds};
-
+
$epochTime += $amount;
$datetime = EpochToDate $epochTime;
-
+
if ($parms{month}) {
my $years = $parms{month} / 12;
my $months = $parms{month} % 12;
-
+
my $month = substr $datetime, 5, 2;
-
+
$years += ($month + $months) / 12;
substr ($datetime, 5, 2) = ($month + $months) % 12;
-
+
substr ($datetime, 0, 4) = substr ($datetime, 0, 4) + $years;
} # if
-
+
return $datetime;
} # Add
-sub Age ($) {
+sub Age($) {
my ($timestamp) = @_;
=pod
my $leap_days = 0;
for (my $i = $timestamp_year; $i < $today_year; $i++) {
-
$leap_days++ if $i % 4 == 0;
} # for
} # if
} # Age
-sub Compare ($$) {
+sub Compare($$) {
my ($date1, $date2) = @_;
-
+
=pod
-=head2 Compare ($date2, $date2)
+=head2 Compare ($date1, $date2)
Compares two datetimes returning -1 if $date1 < $date2, 0 if equal or 1 if
$date1 > $date2
return DateToEpoch ($date1) <=> DateToEpoch ($date2);
} # Compare
-sub DateToEpoch ($) {
+sub DateToEpoch($) {
my ($date) = @_;
-
+
=pod
=head2 DateToEpoch ($datetime)
my $hour = substr $date, 11, 2;
my $minute = substr $date, 14, 2;
my $seconds = substr $date, 17, 2;
-
+
my $days;
for (my $i = 1970; $i < $year; $i++) {
$days += _is_leap_year ($i) ? 366 : 365;
} # for
-
+
my @monthDays = (
0,
31,
304,
334,
);
-
+
$days += $monthDays[$month - 1];
-
- $days++
- if _is_leap_year ($year) and $month > 2;
-
- $days += $day - 1;
-
+
+ $days++ if _is_leap_year ($year) and $month > 2;
+
+ $days += $day - 1;
+
return ($days * $SECS_IN_DAY)
+ ($hour * $SECS_IN_HOUR)
+ ($minute * $SECS_IN_MIN)
+ $seconds;
} # DateToEpoch
-sub EpochToDate ($) {
+sub EpochToDate($) {
my ($epoch) = @_;
-
+
=pod
=head2 EpochToDate ($epoch)
=cut
- my $year = 1970;
my ($month, $day, $hour, $minute, $seconds);
+
+ my $year = 1970;
my $leapYearSecs = 366 * $SECS_IN_DAY;
my $yearSecs = $leapYearSecs - $SECS_IN_DAY;
-
+
while () {
my $amount = _is_leap_year ($year) ? $leapYearSecs : $yearSecs;
-
- last
- if $amount > $epoch;
-
+
+ last if $amount > $epoch;
+
$epoch -= $amount;
$year++;
} # while
-
+
my $leapYearAdjustment = _is_leap_year ($year) ? 1 : 0;
-
+
if ($epoch >= (334 + $leapYearAdjustment) * $SECS_IN_DAY) {
$month = '12';
$epoch -= (334 + $leapYearAdjustment) * $SECS_IN_DAY;
$epoch = $epoch % $SECS_IN_HOUR;
$minute = int ($epoch / $SECS_IN_MIN);
$seconds = $epoch % $SECS_IN_MIN;
-
+
$day = "0$day" if $day < 10;
$hour = "0$hour" if $hour < 10;
$minute = "0$minute" if $minute < 10;
$seconds = "0$seconds" if $seconds < 10;
-
+
return "$year-$month-$day $hour:$minute:$seconds";
} # EpochToDate
-sub UTCTime ($) {
+sub UTCTime($) {
my ($datetime) = @_;
-
+
=pod
=head2 UTCTime ($epoch)
my ($sec, $min, $hour, $mday, $mon, $year) = gmtime (
DateToEpoch ($datetime) - (timegm (@localtime) - timelocal (@localtime))
);
-
+
$year += 1900;
$mon++;
- $sec = '0' . $sec if $sec < 10;
- $min = '0' . $min if $min < 10;
- $hour = '0' . $hour if $hour < 10;
+ $sec = '0' . $sec if $sec < 10;
+ $min = '0' . $min if $min < 10;
+ $hour = '0' . $hour if $hour < 10;
$mon = '0' . $mon if $mon < 10;
$mday = '0' . $mday if $mday < 10;
-
+
return "$year-$mon-${mday}T$hour:$min:${sec}Z";
} # UTCTime
-sub UTC2Localtime ($) {
+sub UTC2Localtime($) {
my ($utcdatetime) = @_;
-
+
# If the field does not look like a UTC time then just return it.
return $utcdatetime unless $utcdatetime =~ /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/;
my @localtime = localtime;
- return EpochToDate (
+ return EpochToDate(
DateToEpoch ($utcdatetime) + (timegm (@localtime) - timelocal (@localtime))
);
} # UTC2Localtime
-sub FormatDate ($) {
- my ($date) = @_;
+sub FormatDate($;$) {
+ my ($date, $separator) = @_;
=pod
-=head2 FormatDate ($date)
+=head2 FormatDate ($date, $separator)
Formats date
Date in YYYYMMDD
+=tiem $separator
+
+If specified, indicates that $date has separators (e.g. 2021-07-04).
+
=back
=for html </blockquote>
=cut
- return substr ($date, 4, 2)
- . "/"
- . substr ($date, 6, 2)
- . "/"
- . substr ($date, 0, 4);
+ unless ($separator) {
+ return substr($date, 4, 2) . '/'
+ . substr($date, 6, 2) . '/'
+ . substr($date, 0, 4);
+ } else {
+ return substr($date, 5, 2)
+ . '/'
+ . substr($date, 8, 2)
+ . '/'
+ . substr($date, 0, 4);
+ } # if
} # FormatDate
-sub FormatTime ($) {
+sub FormatTime($) {
my ($time) = @_;
=pod
my $AmPm = $hours > 12 ? "Pm" : "Am";
$hours = $hours - 12 if $hours > 12;
-
+
$hours = "0$hours" if length $hours == 1;
return "$hours:$minutes $AmPm";
} # FormatTime
-sub MDY (;$) {
+sub MDY(;$) {
my ($time) = @_;
=pod
return "$mon/$mday/$year";
} # MDY
-sub SQLDatetime2UnixDatetime ($) {
+sub SQLDatetime2UnixDatetime($) {
my ($sqldatetime) = @_;
=pod
return $months{$month} . " $day, $year \@ $time";
} # SQLDatetime2UnixDatetime
-sub SubtractDays ($$) {
+sub SubtractDays($$) {
my ($timestamp, $nbr_of_days) = @_;
=pod
my $month = substr $timestamp, 5, 2;
my $day = substr $timestamp, 8, 2;
+ # We are not properly accounting for leap days but this is just a rough
+ # estimate anyway
+ if ($nbr_of_days > 365) {
+ $year -= int $nbr_of_days / 365;
+
+ $nbr_of_days = $nbr_of_days % 365;
+ } # if
+
# Convert to Julian
my $days = julian $year, $month, $day;
return $year . "-" . $month . "-" . $days . substr $timestamp, 10;
} # SubtractDays
-sub Today2SQLDatetime () {
+sub Today2SQLDatetime() {
=pod
=cut
- return UnixDatetime2SQLDatetime (scalar (localtime));
+ return UnixDatetime2SQLDatetime(scalar localtime);
} # Today2SQLDatetime
-sub UnixDatetime2SQLDatetime ($) {
+sub UnixDatetime2SQLDatetime($) {
my ($datetime) = @_;
=pod
unless ($months{$month_name}) {
$month_name = substr $datetime, 8, 3;
} # unless
-
+
my $month = $months{$month_name};
my $time = substr $datetime, 11, 8;
warning "Year undefined for $orig_datetime\nReturning today's date";
return Today2SQLDatetime;
} # unless
-
+
unless ($month) {
warning "Month undefined for $orig_datetime\nReturning today's date";
return Today2SQLDatetime;
} # unless
-
+
unless ($day) {
warning "Day undefined for $orig_datetime\nReturning today's date";
return Today2SQLDatetime;
return "$year-$month-$day $time";
} # UnixDatetime2SQLDatetime
-sub YMD (;$) {
+sub YMD(;$) {
my ($time) = @_;
=pod
return "$year$mon$mday";
} # YMD
-sub YMDHM (;$) {
+sub YMDHM(;$) {
my ($time) = @_;
=pod
return "$year$mon$mday\@$hour:$min";
} # YMDHM
-sub YMDHMS (;$) {
+sub YMDHMS(;$) {
my ($time) = @_;
=pod
return "$year$mon$mday\@$hour:$min:$sec";
} # YMDHMS
-sub timestamp (;$) {
+sub timestamp(;$) {
my ($time) = @_;
=pod