Files
racalmas/lib/calcms/time.pm

587 lines
14 KiB
Perl

use warnings "all";
use strict;
use Time::Local;
use DateTime;
use Date::Calc;
use Date::Manip;
use POSIX qw(strftime);
use config;
package time;
use Data::Dumper;
use utf8;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
format_datetime format_time
date_format time_format
datetime_to_time time_to_datetime time_to_date
datetime_to_date
add_days_to_datetime add_hours_to_datetime add_minutes_to_datetime
add_days_to_date
datetime_to_array date_to_array array_to_date array_to_datetime array_to_time array_to_time_hm
date_cond time_cond check_date check_time check_datetime check_year_month
datetime_to_rfc822 get_datetime datetime_to_utc datetime_to_utc_datetime
get_duration get_duration_seconds
get_durations get_names get_all_names get_weekdays weekday_index
$names
);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
our $names={
'de' =>{
months =>['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'],
months_abbr =>['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'],
weekdays =>['Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag','Sonntag'],
weekdays_abbr =>['Mo','Di','Mi','Do','Fr','Sa','So'],
},
'en' =>{
months =>['January','February','March','April','May','June','Jule','August','September','October','November','December'],
months_abbr =>['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
weekdays =>['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],
weekdays_abbr =>['Mo','Tu','We','Th','Fr','Sa','Su'],
},
};
our $durations=[
0, 5,10,15,20,30,40,45,50,60,70,75,80,90,100,105,110,115,120,135,150,165,180,195,210,225,240,300,360,420,480,540,600,660,720,1440
];
sub get_names{
my $language=shift||'en';
return $time::names->{$language};
}
sub get_all_names{
return $time::names;
}
sub get_durations{
return $time::durations;
}
#TODO: build from datenames
our $weekday_index={
'0' => 0,
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
'6' => 6,
'Mo'=> 0,
'Tu'=> 1,
'Di'=> 1,
'We'=> 2,
'Mi'=> 2,
'Th'=> 3,
'Do'=> 3,
'Fr'=> 4,
'Sa'=> 5,
'Su'=> 6,
'So'=> 6
};
sub get_weekdays{
return{
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => 4,
5 => 5,
6 => 6,
'Mo'=>0,
'Tu'=>1,
'Di'=>1,
'We'=>2,
'Mi'=>2,
'Th'=>3,
'Do'=>3,
'Fr'=>4,
'Sa'=>5,
'Su'=>6,
'So'=>6
};
}
#deprecated, for wordpress sync
sub format_datetime{
my $datetime=shift;
return $datetime if ($datetime eq '');
return add_hours_to_datetime($datetime,0);
};
#deprecated
sub format_time{
my $t=$_[0];
my $year =$t->[5]+1900;
my $month =$t->[4]+1;
$month ='0'.$month if(length($month)==1);
my $day =$t->[3];
$day ='0'.$day if(length($day)==1);
my $hour =$t->[2];
$hour ='0'.$hour if(length($hour)==1);
my $minute =$t->[1];
$minute ='0'.$minute if(length($minute)==1);
return [$day,$month,$year,$hour,$minute];
};
# convert datetime to unix time
sub datetime_to_time{
my $datetime=$_[0];
# print $datetime."\n";
if ($datetime=~/(\d\d\d\d)\-(\d+)\-(\d+)[T\s](\d+)\:(\d+)(\:(\d+))?/){
my $year=$1;
my $month=$2-1;
my $day=$3;
my $hour=$4;
my $minute=$5;
my $second=$8||0;
return Time::Local::timelocal($second,$minute,$hour,$day,$month,$year);
}else{
print STDERR "datetime_to_time: no valid date time found! ($datetime )\n";
return -1;
}
};
#get rfc822 datetime string from datetime string
sub datetime_to_rfc822{
my $datetime=$_[0];
my $time=datetime_to_time($datetime);
return POSIX::strftime("%a, %d %b %Y %H:%M:%S %z", localtime($time));
}
#get seconds from epoch
sub datetime_to_utc{
my $datetime=shift;
my $time_zone=shift;
$datetime=get_datetime($datetime, $time_zone);
return $datetime->epoch();
}
# get full utc datetime including timezone offset
sub datetime_to_utc_datetime{
my $datetime=shift;
my $time_zone=shift;
$datetime=get_datetime($datetime, $time_zone);
return $datetime->format_cldr("yyyy-MM-ddTHH:mm:ssZZZZZ");
}
#add hours to datetime string
sub add_hours_to_datetime{
my $datetime=shift;
my $hours=shift;
return time_to_datetime(datetime_to_time($datetime)+(3600*$hours));
};
#add minutes to datetime string
sub add_minutes_to_datetime{
my $datetime=shift;
my $minutes=shift;
return time_to_datetime(datetime_to_time($datetime)+(60*$minutes));
};
#add days to datetime string
sub add_days_to_datetime{
my $datetime=shift;
my $days=shift;
my $time=datetime_to_array($datetime);
#print STDERR Dumper($time);
($time->[0], $time->[1], $time->[2]) =Date::Calc::Add_Delta_Days($time->[0]+0, $time->[1]+0, $time->[2]+0, $days);
return array_to_datetime($time);
}
sub add_days_to_date{
my $datetime=shift;
my $days=shift;
my $date=date_to_array($datetime);
($date->[0], $date->[1], $date->[2]) =Date::Calc::Add_Delta_Days($date->[0]+0, $date->[1]+0, $date->[2]+0, $days);
return array_to_date($date);
}
# convert unix time to datetime format
sub time_to_datetime{
my $time=shift;
$time=time() unless((defined $time) && ($time ne''));
my @t=localtime($time);
return sprintf('%04d-%02d-%02d %02d:%02d:%02d', $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);
};
# convert unix time to date format
sub time_to_date{
my $time=shift;
$time=time() unless((defined $time) && ($time ne''));
my @t=localtime($time);
return sprintf('%04d-%02d-%02d', $t[5]+1900, $t[4]+1, $t[3]);
};
# convert datetime to a array of date/time values
sub datetime_to_array{
my $datetime=$_[0]||'';
if ($datetime=~/(\d\d\d\d)\-(\d+)\-(\d+)([T\s]+(\d+)\:(\d+)(\:(\d+))?)?/){
my $year=$1;
my $month=$2;
my $day=$3;
my $hour=$5||'00';
my $minute=$6||'00';
my $second=$8||'00';
return [$year,$month,$day,$hour,$minute,$second];
}
return undef;
};
# convert datetime to date
sub datetime_to_date{
my $datetime=$_[0]||'';
if ($datetime=~/(\d\d\d\d)\-(\d+)\-(\d+)/){
my $year=$1;
my $month=$2;
my $day=$3;
return sprintf("%04d-%02d-%02d",$year,$month,$day);
}
return undef;
};
#convert datetime array or single value to datetime string
sub array_to_datetime{
my $date =shift;
if(ref($date)eq'ARRAY'){
return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $date->[0], $date->[1], $date->[2], $date->[3], $date->[4], $date->[5]);
}
my $month =shift;
my $day =shift;
my $hour =shift||'0';
my $minute =shift||'0';
my $second =shift||'0';
return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $date, $month, $day, $hour, $minute, $second);
}
#convert date array or single values to date string
sub array_to_date{
my $date =shift;
if(ref($date)eq'ARRAY'){
return sprintf("%04d-%02d-%02d", $date->[0], $date->[1], $date->[2]);
}
my $month=shift;
my $day =shift;
return sprintf("%04d-%02d-%02d", $date, $month, $day);
}
sub array_to_time{
my $date =shift;
if(ref($date)eq'ARRAY'){
return sprintf("%02d:%02d:%02d", $date->[3], $date->[4], $date->[5]);
}
my $minute = shift||0;
my $second = shift||0;
return sprintf("%02d:%02d:%02d", $date, $minute, $second);
}
sub array_to_time_hm{
my $date =shift;
if(ref($date)eq'ARRAY'){
return sprintf("%02d:%02d", $date->[3], $date->[4]);
}
my $minute = shift||0;
return sprintf("%02d:%02d", $date, $minute);
}
# get number of days between two days
sub days_between{
my $today=$_[0];
my $date=$_[1];
my $delta_days=eval{Date::Calc::Delta_Days(
$today->[0],$today->[1],$today->[2],
$date->[0], $date->[1], $date->[2]
)};
return $delta_days;
}
sub dayOfYear{
my $datetime=$_[0];
if ($datetime=~/(\d\d\d\d)\-(\d+)\-(\d+)/){
my $year = $1;
my $month = $2;
my $day = $3;
return Date::Calc::Day_of_Year($year,$month,$day);
}
return undef;
}
# get duration in minutes
sub get_duration{
my $start = shift;
my $end = shift;
my $timezone= shift;
$start=time::get_datetime($start, $timezone);
$end =time::get_datetime($end, $timezone);
my $duration=$end->epoch()-$start->epoch();
return $duration/60;
}
# get duration in seconds
sub get_duration_seconds{
my $start = shift;
my $end = shift;
my $timezone= shift||'UTC';
$start=time::get_datetime($start, $timezone);
$end =time::get_datetime($end, $timezone);
my $duration=$end->epoch()-$start->epoch();
return $duration;
}
# convert date string to a array of date values
sub date_to_array{
my $datetime=$_[0];
if ($datetime=~/(\d\d\d\d)\-(\d+)\-(\d+)/){
my $year = $1;
my $month = $2;
my $day = $3;
return [$year,$month,$day];
}
return undef;
};
# parse date string and return date string
# pass 'today', return '' on parse error
sub date_cond{
my $date=shift;
return '' if ($date eq'');
if ($date=~/(\d\d\d\d)\-(\d\d?)\-(\d\d?)/){
my $year = $1;
my $month = $2;
my $day = $3;
return sprintf("%04d-%02d-%02d", $year, $month, $day);
}
return 'today' if ($date eq 'today');
return '';
};
#parse time and return time string hh:mm:ss
#return hh:00 if time is 'now'
sub time_cond{
my $time = shift;
return '' if ($time eq'');
if ($time=~/(\d\d?)\:(\d\d?)(\:(\d\d))?/){
my $hour=$1;
my $minute=$2;
my $second=$4||'00';
return sprintf("%02d:%02d:%02d", $hour, $minute, $second);
}
if ($time eq 'now'){
my $date=datetime_to_array(time_to_datetime(time()));
my $hour=$date->[3]-2;
$hour=0 if ($hour<0);
$time=sprintf("%02d:00",$hour);
return $time;
}
return '';
};
#parse date and time string and return yyyy-mm-ddThh:mm:ss
sub datetime_cond{
my $datetime = shift;
return '' if ($datetime eq'');
(my $date,my $time)=split /[ T]/,$datetime;
$date=time::date_cond($date);
return '' if ($date eq'');
$time=time::time_cond($time);
return '' if ($time eq'');
return $date.'T'.$time;
}
sub check_date{
my $date=shift;
return "" if((!defined $date) || ($date eq ''));
if($date=~/(\d\d\d\d)\-(\d\d?)\-(\d\d?)/){
return $1.'-'.$2.'-'.$3;
}elsif($date=~/(\d\d?)\.(\d\d?)\.(\d\d\d\d)/){
return $3.'-'.$2.'-'.$1;
}
return $date if ($date eq'today' || $date eq'tomorrow' || $date eq'yesterday');
return -1;
#error("no valid date format given!");
};
sub check_time{
my $time=shift;
return "" if((!defined $time) || ($time eq ''));
return $time if(($time eq 'now') || ($time eq 'future'));
if($time=~/(\d\d?)\:(\d\d?)/){
return $1.':'.$2
}
return -1;
};
sub check_datetime{
my $date=shift;
return "" if((!defined $date) || ($date eq ''));
if($date=~/(\d\d\d\d)\-(\d\d?)\-(\d\d?)[T ](\d\d?)\:(\d\d?)/){
return sprintf("%04d-%02d-%02dT%02d:%02d",$1,$2,$3,$4,$5);
}
return -1;
};
sub check_year_month{
my $date=shift;
return -1 unless(defined $date);
return $date if($date eq '');
if($date=~/(\d\d\d\d)\-(\d\d?)/){
return $1.'-'.$2.'-'.$3;
}
return -1;
};
#TODO: remove config dependency
sub date_time_format{
my $datetime=shift;
my $language=shift || $config::config->{date}->{language} || 'en';
if (defined $datetime && $datetime=~/(\d\d\d\d)\-(\d\d?)\-(\d\d?)[\sT](\d\d?\:\d\d?)/){
my $time=$4;
my $day=$3;
my $month=$2;
my $year=$1;
$month=$time::names->{$language}->{months_abbr}->[$month-1]||'';
return "$day. $month $year $time";
}
return $datetime;
}
#format datetime to date string
#TODO: remove config dependency
sub date_format{
my $datetime=shift;
my $language=shift || $config::config->{date}->{language} || 'en';
if (defined $datetime && $datetime=~/(\d\d\d\d)\-(\d\d?)\-(\d\d?)/){
my $day=$3;
my $month=$2;
my $year=$1;
$month=$time::names->{$language}->{months_abbr}->[$month-1]||'';
return "$day. $month $year";
}
return $datetime;
};
#format datetime to time string
sub time_format{
my $datetime=shift;
if (defined $datetime && $datetime=~/(\d\d?\:\d\d?)/){
return $1;
}
return $datetime;
};
#get offset from given time_zone
sub utc_offset{
my $time_zone=shift;
$a=DateTime->now();
$a->set_time_zone($time_zone);
return $a->strftime("%z");
}
#get weekday from (yyyy,mm,dd)
sub weekday{
my ($year,$month,$day)=@_;
my $time = Time::Local::timelocal(0,0,0,$day,$month-1,$year);
return (localtime($time))[6];
}
#get current date, related to starting day_starting_hour
#TODO: remove config dependency
sub get_event_date{
my $config=shift;
$config=$config::config unless defined $config;
my $datetime=time::time_to_datetime(time());
my $hour=(time::datetime_to_array($datetime))->[3];
#today: between 0:00 and starting_hour show last day
if ($hour < $config->{date}->{day_starting_hour}){
my $date=time::datetime_to_array(time::add_hours_to_datetime($datetime,-24));
return $date->[0].'-'.$date->[1].'-'.$date->[2];
}else{
#today: between starting_hour and end of day show current day
my $date=time::datetime_to_array(time::time_to_datetime(time()));
return $date->[0]."-".$date->[1]."-".$date->[2];
}
}
#get datetime object from datetime string
sub get_datetime{
my $datetime=shift;
my $timezone=shift;
return unless defined $datetime;
return if $datetime eq '';
my @l = @{time::datetime_to_array($datetime)};
return undef if scalar(@l)==0;
# catch invalid datees
$datetime=undef;
eval{
$datetime=DateTime->new(
year =>$l[0],
month =>$l[1],
day =>$l[2],
hour =>$l[3],
minute =>$l[4],
second =>$l[5],
time_zone=> $timezone
);
};
return undef unless defined $datetime;
$datetime->set_locale('de_DE');
return $datetime;
}
#get list of nth weekday in month from start to end
sub get_nth_weekday_in_month{
my $start=shift; # datetime string
my $end=shift; # datetime string
my $nth=shift; # every nth week of month
my $weekday=shift; # weekday [0..6,'Mo'-'Su','Mo'-'Fr']
my $weekdays=time::get_weekdays();
$weekday=$weekdays->{$weekday+1};
my $dates=[];
if ($start=~/(\d\d\d\d)-(\d\d)-(\d\d)[ T](\d\d)\:(\d\d)/){
my $hour=int($4);
my $min=int($5);
my $sec=0;
my @date = Date::Manip::ParseRecur("0:1*$nth:$weekday:$hour:$min:$sec", "", $start, $end);
for my $date (@date){
if ($date=~/(\d\d\d\d)(\d\d)(\d\d)(\d\d)\:(\d\d)\:(\d\d)/){
push @$dates,"$1-$2-$3 $4:$5:$6";
}
}
}
return $dates;
}
#do not delete last line!
1;