package ONO::Lib::DateTime::ToolBox;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################
use strict;
use ONO::Lib::Basic;
my $ZONE;
eval "use POSIX";
if (!$@) {
$ZONE = strftime("%Z", localtime());
}
sub timestamp {
#: Get UNIX time.
return time();
}
sub get {
#: Get date and / or time, including some conversion options
#:
#: A - no absolute time in -i mode
#: b - important stuff gets bold
#: d - date format EU (dd/mm/yyyy)
#: D - date format US (mm/dd/yyyy)
#: g - important stuff gets green
#: i - intelligent mode features human readable output
#: L - remove leading zeroes (unless it's midnight)
#: m - display time if date is current date
#: M - short 3 letter month name
#: n - round up to full minute (no seconds displayed in intelligent mode)
#: N - in intelligent mode
#: o - last online
#: r - short (dd. month)
#: R - short with optional year (dd. month yyyy if not current year)
#: s - stamp format 1 (dd/mm/yyyy \@ hh:mm)
#: S - stamp format 2 (yyyymmdd)
#: u - uppercase (first letter)
#: y - year
#: z - ?
#: Z - remove non-required zeroes
my (
$self,
$inputtime,
$timeoffset,
$options,
$lang
) = @_;
$inputtime =~ s~[^0-9]~~g;
if (length $inputtime == 8 && $inputtime =~ /^(1|2)/ && $options !~ /(r|R)/) {
$inputtime .= "000000";
}
if (!$inputtime) {
$inputtime = time;
}
# this only works with dates after 1000 AD
if ($inputtime > 10000000000000) {
$inputtime = &convert("","unix",$inputtime);
}
if (($ZONE eq "CEST" || $ZONE eq "CET") && $options =~ /z/) {
$timeoffset--;
}
my $at = "at";
my $before;
my $yesterday_at = "yesterday at";
my $today_at = "today at";
my $last_night_at = "last night at";
my $hour_ago = "hour ago";
my $hours_ago = "hours ago";
my $minutes_ago = "minutes ago";
my $seconds_ago = "seconds ago";
my $online_now = "online now";
my $last_online = "last online";
my $right_now = "right now";
if ($lang eq "de") {
$at = "um";
$before = "vor ";
$yesterday_at = "gestern um";
$today_at = "heute um";
$last_night_at = "letzte Nacht um";
$hour_ago = "Stunde";
$hours_ago = "Stunden";
$minutes_ago = "Minuten";
$seconds_ago = "Sekunden";
$online_now = "jetzt online";
$last_online = "zuletzt online";
$right_now = "gerade eben";
}
if ($lang eq "fr") {
$at = "à";
$before = "il y a ";
$yesterday_at = "hier à";
$today_at = "aujourd'hui à";
$last_night_at = "la huit passée à";
$hour_ago = "heure";
$hours_ago = "heures";
$minutes_ago = "minutes";
$seconds_ago = "secondes";
$online_now = "maintenant";
$last_online = "en ligne";
$right_now = "juste maintenant";
}
if ($lang eq "lu") {
$at = "um";
$before = "virun ";
$yesterday_at = "gëschter um";
$today_at = "haut um";
$last_night_at = "läscht Nuecht um";
$hour_ago = "Stonn";
$hours_ago = "Stonnen";
$minutes_ago = "Minutten";
$seconds_ago = "Sekonnen";
$online_now = "elo online";
$last_online = "fir d'läscht online";
$right_now = "grad elo";
}
my (
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday,$isdst
) = localtime($inputtime+(3600*$timeoffset));
$year = $year+1900;
$mon++;
my (
$sec2,$min2,$hour2,
$mday2,$mon2,$year2,
$wday2,$yday2,$isdst2
) = localtime(time+(3600*$timeoffset));
if (!$options || $options =~ /(T|t|d|D|s|S|m)/) {
if ($mon < 10 ) {$mon = "0$mon" }
if ($mday < 10 ) {$mday = "0$mday"}
if ($hour < 10 ) {$hour = "0$hour"}
if ($min < 10 ) {$min = "0$min" }
if ($sec < 10 ) {$sec = "0$sec" }
my $timestamp = time;
if (!$options) {
return ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$timestamp,$isdst);
}
if ($options =~ /L/) {
$hour =~ s~^0~~;
$hour =~ s~^\:~0\:~;
}
if ($options =~ /t/) {
return "$hour:$min";
}
if ($options =~ /T/) {
return "$hour:$min:$sec";
}
if ($options =~ /d/) {
return &check_zeros("$mday.$mon.$year",$options);
}
if ($options =~ /D/) {
return "$mon.$mday.$year";
}
if ($options =~ /s/) {
return "$mday.$mon.$year \@ $hour:$min";
}
if ($options =~ /S/) {
return "$year$mon$mday";
}
if ($options =~ /m/) {
my $time = &check_zeros("$mday.$mon.$year",$options);
if ($mday == $mday2 && $mon == $mon2+1 && $year == $year2+1900) {
$time = "$hour:$min:$sec";
if ($options =~ /b/) {
$time = "<strong>$time</strong>";
}
if ($options =~ /g/) {
$time = qq~<span class="green">$time</span>~;
}
}
return $time;
}
}
# intelligent mode - offers human readable output
if ($options =~ /i/) {
if ($min < 10) {
$min = "0$min";
}
$year2 = $year2+1900;
$mon2++;
my $month = &month_name(0,$mon,"",$lang);
if ($options =~ /M/) {
$month = substr($month,0,3);
}
my $time = "$month $mday, $year";
if ($lang =~ /^(de|fr|lu)$/) {
$time = "$mday. $month $year";
}
if ($options =~ /A/) {
my $diff = time() - $inputtime;
if ($diff < 60) {
$time = "$before $diff $minutes_ago";
}
if ($diff < 4) {
$time = "$right_now!";
}
} else {
if ($year == $year2) {
$time = "$month $mday $at $hour:$min";
if ($lang =~ /^(de|fr|lu)$/) {
$time = "$mday. $month $at $hour:$min";
}
}
my $yesterday = $mday2-1;
if ("$year-$mon-$mday" eq "$year2-$mon2-$yesterday") {
$time = "$yesterday_at $hour:$min";
}
if ("$year-$mon-$mday" eq "$year2-$mon2-$mday2") {
$time = "$today_at $hour:$min";
if ($hour < 6) {
$time = "$last_night_at $hour:$min";
}
if ($hour2 - $hour < 5) {
$time = $before.($hour2 - $hour)." $hours_ago";
}
if ($hour2 - $hour < 2) {
$time = $before.($hour2 - $hour)." $hour_ago";
}
if ($hour2 - $hour == 1 && ($min2 - $min) < 0) {
$time = $before.(60+$min2 - $min)." $minutes_ago";
}
if ($hour2 - $hour < 1) {
$time = $before.($min2 - $min)." $minutes_ago";
if ($min2 - $min < 1 && $options !~ /(n|o)/) {
$time = $before.($sec2 - $sec)." $seconds_ago";
if ($sec2 - $sec < 10) {
$time = "$right_now!";
}
}
if ($min2 - $min < 5 && $options =~ /(n|o)/) {
$time = "$online_now!";
}
}
}
}
if ($options =~ /o/) {
$time = qq~$last_online: <span class="bold">$time</span>~;
}
if ($options =~ /u/) {
$time = ucfirst $time;
}
if ($options =~ /N/) {
$time =~ s~ ~ ~g;
}
return $time;
}
if ($options =~ /(r|R)/) {
my $day = substr($inputtime,6,2);
$day =~ s~^0~~;
if ($options =~ /R/ && substr($inputtime,0,4) != $year2+1900) {
return "$day. ".&month_name("",substr($inputtime,4,2),"u",$lang)." ".substr($inputtime,0,4);
} else {
return "$day. ".&month_name("",substr($inputtime,4,2),"u",$lang);
}
}
if ($options =~ /y/) {
return $year;
}
}
sub check_zeros {
#: Check zeroes.
#:
#: -Z remove zeroes.
my ($time,$options) = @_;
if ($options =~ /Z/) {
$time =~ s~\.0~\.~g;
$time =~ s~^0~~;
}
return $time;
}
sub num {
#: Return year, mon ot mday
my (
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday,$isdst
) = localtime();
if ($_[1] eq "year") {
return $year+1900;
}
if ($_[1] eq "mon") {
return $mon+1;
}
if ($_[1] eq "mday") {
return $mday;
}
}
###############################################################################
# convert to "classic" or "unix"
###############################################################################
sub convert {
my (
$self,
$target,
$timestamp,
$switches,
$lang,
) = @_;
#: Convert time formats
#:
#: $lang only required for -m switch
#:
#: -3 shorter month name (3 chars)
#: -d dashes (yyyymmdd option)
#: -m month name ("date" target only)
#: -s slashes instead of periods
#: -S US only: slashes instead of periods
#: -u US time format
#: -U US time format detected on lang = en
#: -w add whitespaces
#: -Z eleminate zeros
my $return = $timestamp;
if ($switches =~ /U/ && $lang eq "en") {
$switches .= "u";
}
#: Target = "classic" : from 1285128905(10) to yyyymmddhhmmss(14)
if ($target eq "classic" && $timestamp < 19000000000000) {
my (
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday
) = &get("",$timestamp);
$return = "$year$mon$mday$hour$min$sec";
}
#: Target = "yyyymmdd" : from 1285128905(10) to yyyymmdd or yyyy-mm-dd (-d)
if ($target eq "yyyymmdd" && $timestamp < 19000000000000) {
my (
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday
) = &get("",$timestamp);
if ($switches =~ /d/) {
$return = "$year-$mon-$mday";
} else {
$return = "$year$mon$mday";
}
}
#: Target = "yymmdd" : from 1285128905(10) to yyyymmdd or yy-mm-dd (-d)
if ($target eq "yymmdd" && $timestamp < 19000000000000) {
my (
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday
) = &get("",$timestamp);
$year = substr($year,2,2);
if ($switches =~ /d/) {
$return = "$year-$mon-$mday";
} else {
$return = "$year$mon$mday";
}
}
#: Target = "unix" : from yyyymmddhhmmss(14) to 1285128905(10)
if ($target eq "unix" && length $timestamp == 8) {
$timestamp = "${timestamp}000000";
}
if ($target eq "unix" && $timestamp > 19000000000000) {
eval "use Time::Local";
if (!$@) {
$return = timelocal(substr($timestamp,12,2),substr($timestamp,10,2),substr($timestamp,8,2),substr($timestamp,6,2),substr($timestamp,4,2)-1,substr($timestamp,0,4));
}
}
#: Target = "slash" : from yyyymmdd to yyyy/mm/dd
if ($target eq "slash" && length $timestamp == 8) {
return substr($timestamp,0,4)."/".substr($timestamp,4,2)."/".substr($timestamp,6,2);
}
#: Target = "date" : from yyyymmdd to dd.mm.yyyy
if ($target eq "date" && length $timestamp == 8) {
$return = substr($timestamp,6,2).".".substr($timestamp,4,2).".".substr($timestamp,0,4);
my $is_us;
if ($switches =~ /u/) {
$return = substr($timestamp,4,2).".".substr($timestamp,6,2).".".substr($timestamp,0,4);
}
if (substr($timestamp,6,2) eq "00") {
$return = substr($timestamp,4,2).".".substr($timestamp,0,4);
if (substr($timestamp,4,2) eq "00") {
$return = substr($timestamp,0,4);
}
}
if ($switches =~ /m/ && substr($timestamp,4,2) ne "00") {
my $three;
if ($switches =~ /3/) {
$three = 3;
}
my $mon = &month_name("",substr($timestamp,4,2),"u$three",$lang);
$return = substr($timestamp,6,2).". ".$mon." ".substr($timestamp,0,4);
if ($switches =~ /u/) {
$return = $mon." ".substr($timestamp,6,2).", ".substr($timestamp,0,4);
}
}
if ($switches =~ /Z/) {
$return =~ s~^0~~g;
$return =~ s~\.0~\.~g;
$return =~ s~ 0~ ~g;
}
if ($switches =~ /s/ || ($switches =~ /S/ && $switches =~ /u/)) {
$return =~ s~\.~\/~g;
}
}
#: Target = "datetime" : from yyyymmddhhmmss(14) to dd.mm.yyyy hh:mm
if ($target eq "datetime" && length $timestamp == 14) {
$return = substr($timestamp,6,2).".".substr($timestamp,4,2).".".substr($timestamp,0,4)." ".substr($timestamp,8,2).":".substr($timestamp,10,2);
}
#: Target = "datetimesecs" : from yyyymmddhhmmss(14) to dd.mm.yyyy hh:mm:ss
if ($target eq "datetimesecs" && length $timestamp == 14) {
$return = substr($timestamp,6,2).".".substr($timestamp,4,2).".".substr($timestamp,0,4)." ".substr($timestamp,8,2).":".substr($timestamp,10,2).":".substr($timestamp,12,2);
}
#: Target = "datetimereverse" : from dd/mm/yyyy \@ hh:mm:ss to yyyymmddhhmmss
if ($target eq "datetimereverse") {
$timestamp =~ s~[^0-9\ \/\@\:]~~gi;
$timestamp =~ m~(.*?)/(.*?)/(.*?) \@ (.*?):(.*?):(.*)~;
$return = "$3$2$1$4$5$6";
}
#: Target = "time" / 6 : from hhmm to hh:mm
if ($target eq "time" && length $timestamp == 6) {
$return = substr($timestamp,0,2).":".substr($timestamp,2,2).":".substr($timestamp,4,2);
}
#: Target = "time" / 4 :
if ($target eq "time" && length $timestamp == 4) {
$return = substr($timestamp,0,2).":".substr($timestamp,2,2);
}
#: Target = "time" / 3 :
if ($target eq "time" && length $timestamp == 3) {
$return = substr($timestamp,0,1).":".substr($timestamp,1,2);
}
#: Target = "daymonyear" : from yyyymmdd to dd. Month yyyy
if ($target eq "daymonyear" && length $timestamp == 8) {
my $mon_switches = "u";
if ($switches =~ /3/) {
$mon_switches .= "3";
}
my $mon = &month_name("",substr($timestamp,4,2),$mon_switches,$lang);
if ($switches =~ /u/ || $switches =~ /U/ && $lang eq "en") {
my $day = substr($timestamp,6,2);
if ($switches =~ /Z/) {
$day =~ s~^0~~;
}
$return = "$mon $day, ".substr($timestamp,0,4);
} else {
$return = substr($timestamp,6,2).". $mon ".substr($timestamp,0,4);
if ($switches =~ /Z/) {
$return =~ s~^0~~;
}
}
}
if ($switches =~ /w/) {
$return =~ s~\.~\. ~g;
$return =~ s~\/~ \/ ~g;
}
return $return;
}
sub convert_ss2hhmmss {
#: Convert seconds to hhmmss
my $secs = $_[1];
my ($mins,$hours,$whilecounter);
while ($secs > 59 && $whilecounter < 8192) {
$whilecounter++;
$mins++;
$secs = $secs-60;
}
if (!$mins) {
$mins = 0;
}
if (length $secs < 2) {
$secs = "0$secs";
}
while ($mins > 59 && $whilecounter < 8192) {
$whilecounter++;
$hours++;
$mins = $mins-60;
}
if ($hours) {
if (length $mins < 2) {
$mins = "0$mins";
}
return "$hours:$mins:$secs";
} else {
return "$mins:$secs";
}
}
sub convert_hhmmss2ss {
#: Convert hhmmss to seconds
my $time = $_[1];
if ($time =~ /^(.*?):(.*?):(.*?)$/) {
$time = $1*60*60+$2*60+$3;
}
if ($time =~ /^(.*?):(.*?)$/) {
$time = $1*60+$2;
}
return $time;
}
sub secs_in_min {
#: Return 60
return 60;
}
sub secs_in_hour {
#: Return 60*60
return 60*60;
}
sub secs_in_day {
#: Return 60*60*24
return 60*60*24;
}
sub secs_in_week {
#: Return 60*60*24*7
return 60*60*24*7;
}
sub secs_in_month {
#: Return 60*60*24*31
return 60*60*24*31;
}
###############################################################################
# max_days_per_month
###############################################################################
sub max_days_per_month {
#: Return the max number of days per month, note that Feb is 29 days here.
return (
'31','29','31',
'30','31','30',
'31','31','30',
'31','30','31'
);
}
###############################################################################
# time logic
###############################################################################
sub logic2secs {
#: Convert m/h/d string to seconds
my $secs = $_[1];
if ($secs =~ s~m~~gi) {
$secs = $secs * &secs_in_min;
}
if ($secs =~ s~h~~gi) {
$secs = $secs * &secs_in_hour;
}
if ($secs =~ s~d~~gi) {
$secs = $secs * &secs_in_day;
}
$secs =~ s~[^0-9]~~g;
return $secs;
}
###############################################################################
# month names
###############################################################################
sub month_name {
#: Return month name,
#:
#: -3 abbreviated (3 chars)
#: -a ???
#: -j ???
#: -u ???
my (
$self,
$month,
$switches,
$lang,
) = @_;
my @name = (
'',
'january',
'february',
'march',
'april',
'may',
'june',
'july',
'august',
'september',
'october',
'november',
'december',
);
if ($lang eq "de") {
@name = (
'',
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember',
);
}
if ($lang eq "fr") {
@name = (
'',
'janvier',
'février',
'mars',
'avril',
'mai',
'juin',
'juillet',
'août',
'septembre',
'octobre',
'novembre',
'décembre',
);
}
if ($lang eq "lu") {
@name = (
'',
'Januar',
'Februar',
'März',
'Abrëll',
'Mee',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember',
);
}
if ($switches =~ /j/) {
shift @name;
}
my $res = $name[$month];
if ($switches =~ /3/) {
if ($res =~ /(ä|é|û)/) {
$res = substr($res,0,4);
} else {
$res = substr($res,0,3);
}
}
if ($switches =~ /a/) {
if ($switches =~ /u/) {
for (my $i = 0; $i < 13; $i++) {
$name[$i] = ucfirst $name[$i];
if ($switches =~ /3/) {
$name[$i] = substr($name[$i],0,3);
}
}
}
return @name;
} else {
if ($switches =~ /u/) {
$res = ucfirst $res;
}
return $res;
}
}
###############################################################################
# day names
###############################################################################
sub day_name {
#: Return day name.
#:
#: -a all names
#: -m monday is zero
#: -s short (3 chars)
#: -S short (2 chars)
#: -u uppercase first
my $switches = $_[1];
if ($_[3]) {
$switches = $_[3];
}
my @name = (
'sunday',
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday',
);
if ($_[2] eq "de") {
@name = (
'Sonntag',
'Montag',
'Dienstag',
'Mittwoch',
'Donnerstag',
'Freitag',
'Samstag',
'Sonntag',
);
}
if ($_[2] eq "fr") {
@name = (
'Dimanche',
'Lundi',
'Mardi',
'Mercredi',
'Jeudi',
'Vendredi',
'Samedi',
'Dimanche',
);
}
if ($_[2] eq "lu") {
@name = (
'Sonndeg',
'Méindeg',
'Dënschdeg',
'Mëttwoch',
'Donneschdeg',
'Freideg',
'Samschdeg',
'Sonndeg',
);
}
if ($switches =~ /u/ && (!$_[2] || $_[2] eq "en")) {
for (my $i = 0; $i < 8; $i++) {
$name[$i] = ucfirst $name[$i];
}
}
if ($switches =~ /(s|S)/) {
my $cut = 3;
if ($switches =~ /S/) {
$cut = 2;
}
for (my $i = 0; $i < 8; $i++) {
$name[$i] = substr($name[$i],0,$cut);
}
}
if ($switches =~ /m/) {
shift @name;
}
if ($switches =~ /a/) {
return @name;
} else {
return $name[$_[1]];
}
}
###############################################################################
# string
###############################################################################
sub string {
#: Return yyyymmddhhmmss string, which may be abbreviated (default = 8 chars).
my $num = $_[1];
if ($num < 1) {
$num = 8;
}
my (
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday,$isdst
) = localtime;
$year = $year+1900;
$mon++;
if ($mon < 10 ) {$mon = "0$mon" }
if ($mday < 10 ) {$mday = "0$mday"}
if ($hour < 10 ) {$hour = "0$hour"}
if ($min < 10 ) {$min = "0$min" }
if ($sec < 10 ) {$sec = "0$sec" }
return substr("$year$mon$mday$hour$min$sec",0,$num);
}
###############################################################################
# today
###############################################################################
sub today {
#: Return yyyymmdd.
return &string("",8);
}
sub todayhh {
#: Return yyyymmddhh.
return &string("",10);
}
sub today_std {
#: Return today.
#:
#: -d include day name
#: -m month name
my (
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday,$isdst
) = localtime();
$year = $year+1900;
my $DATE;
if ($_[1] =~ /d/) {
$DATE .= ucfirst &day_name("",$wday,"","su").", ";
}
if ($_[1] =~ /m/) {
$DATE .= &month_name("",$mon+1,"3u")." ";
} else {
$DATE .= ($mon+1)."/";
}
$DATE .= "$mday, $year";
return $DATE;
}
###############################################################################
# yesterday
###############################################################################
sub yesterday {
my ($self,$year,$mon,$mday) = @_;
#: Return yesterday's date.
#: See also tomorrow().
if (length $year == 8) {
$mday = substr($year,6,2);
$mon = substr($year,4,2);
$year = substr($year,0,4);
}
$mday--;
if ($mday < 1) {
$mon--;
$mday = 31;
}
if ($mday > 30 && ($mon == 4 || $mon == 6 || $mon == 9 || $mon == 11)) {
$mday = 30;
}
if ($mday > 28 && $mon == 2) {
$mday = 28;
}
if ($mon < 1) {
$year--;
$mon = 12;
$mday = 31;
}
($mon,$mday) = &add_leading_zero($mon,$mday);
return "$year$mon$mday";
}
sub add_leading_zero {
#: Add leading zero to mon and mday.
my ($mon,$mday) = @_;
if (length $mon < 2) {
$mon = "0$mon";
}
if (length $mday < 2) {
$mday = "0$mday";
}
return ($mon,$mday);
}
###############################################################################
# tomorrow
###############################################################################
sub tomorrow {
#: Return tomorrow's date.
#: See also yesterday().
my ($self,$year,$mon,$mday) = @_;
$mday++;
if ($mday > 30 || ($mday > 29 && ($mon == 4 || $mon == 6 || $mon == 9 || $mon == 11)) || ($mday > 27 && $mon == 2)) {
$mon++;
$mday = 1;
}
if ($mon > 12) {
$year++;
$mon = 1;
}
($mon,$mday) = &add_leading_zero($mon,$mday);
return "$year$mon$mday";
}
###############################################################################
# nextdays
###############################################################################
sub nextdays {
#: This returns the exact date of an upcoming next day (example: what's the date of next friday?).
my (
$self,
$year,$mon,$mday,
$weekday,
$target,
) = @_;
my $days_to_go = $target - $weekday;
# if weekdays match then we'll jump to the next week...
if ($days_to_go < 1) {
$days_to_go = 6;
}
$mday = $mday + $days_to_go;
my $days_in_month = 31;
if ($mon == 4 || $mon == 6 || $mon == 9 || $mon == 11) {
$days_in_month = 30;
}
if ($mon == 2) {
$days_in_month = 28;
}
if ($mday > $days_in_month) {
$mon++;
$mday = $mday - $days_in_month;
}
if ($mon > 12) {
$year++;
$mon = 1;
}
($mon,$mday) = &add_leading_zero($mon,$mday);
return "$year$mon$mday";
}
###############################################################################
# select date
###############################################################################
sub select_date_save {
#: Old version, used until Oct 2019, doesn't support date picker, better use select_date_saver() instead.
my (
$self,
$yyyy,
$mm,
$dd,
) = @_;
# turn any input into YYYYMMDD format
$yyyy = ONO::Lib::Basic->add_leading_zeroes($yyyy,4);
$mm = ONO::Lib::Basic->add_leading_zeroes($mm,2);
$dd = ONO::Lib::Basic->add_leading_zeroes($dd,2);
my $date = "$yyyy$mm$dd";
$date =~ s~[^0-9]~~g;
return $date;
}
sub select_date_saver {
# Save date, new version, also supports date picker.
my (
$self,
$name,
$vars_ref,
) = @_;
my %vars = %$vars_ref;
# classic select menu
$vars{"${name}_year"} = ONO::Lib::Basic->add_leading_zeroes($vars{"${name}_year"},4);
$vars{"${name}_month"} = ONO::Lib::Basic->add_leading_zeroes($vars{"${name}_month"},2);
$vars{"${name}_day"} = ONO::Lib::Basic->add_leading_zeroes($vars{"${name}_day"},2);
my $date = qq~$vars{"${name}_year"}$vars{"${name}_month"}$vars{"${name}_day"}~;
# use date picker, if selected
if (length $vars{"${name}_picker"} == 10 && $vars{"${name}_picker"} =~ /^(.*?)(\/|-)(.*?)(\/|-)(.*?)$/) {
if ($vars{"${name}_picker_format"} eq "ddmmyyyy") {
$date = "$5$3$1";
}
if ($vars{"${name}_picker_format"} eq "mmddyyyy") {
$date = "$5$1$3";
}
}
$date =~ s~[^0-9]~~g;
if (length $date != 8) {
$date = "";
}
return $date;
}
sub select_date {
my (
$self,
$name,
$from,
$to,
$default,
$lang,
$flags,
) = @_;
#: Date selector.
#:
#: $from and $to format: YYYY
#: $default format: YYYYMMDD
#:
#: -C compact (zero padding)
#: -d disabled
#: -E force use EU format
#: -j no jquery loading (prevent double loading, required for plupload compatibility for example)
#: -J no javascript loading (only if -P is used)
#: -m use month names
#: -n null is allowed
#: -P picker, make sure to use select_date_saver then
#: -r reverse years
#: -t today
#: -T add table code
#: -U force use US format
my ($NULL,$TODAY,$DIS,$PAD);
if ($flags =~ /n/) {
$NULL = qq~<option value=""></option><option value="">--</option>~;
}
if ($flags =~ /t/) {
$TODAY = qq~<option value="">today</option><option value="">--</option>~;
}
if ($flags =~ /d/) {
$DIS = " disabled";
}
if ($flags =~ /C/) {
$PAD = qq~ class="p0"~
}
my $YYYY = substr($default,0,4);
my $MM = substr($default,4,2);
my $DD = substr($default,6,2);
my ($DAY,$MON,$YEAR);
for (my $i = 1; $i < 200; $i++) {
my $j = $i;
if ($i < 10) {
$j = "0$i";
}
if ($i < 32) {
my $sel;
if ($DD == $i) {
$sel = " selected";
}
$DAY .= qq~<option value="$j"$sel>$i</option>~;
}
if ($i < 13) {
my $sel;
if ($MM == $i) {
$sel = " selected";
}
my $m = $i;
if ($flags =~ /m/) {
$m = &month_name(0,$i,"3u",$lang);
}
$MON .= qq~<option value="$j"$sel>$m</option>~;
}
my $y = $from-1+$i;
if ($y < $to+1) {
my $sel;
if ($YYYY == $y) {
$sel = " selected";
}
if ($flags =~ /r/) {
$YEAR = qq~<option value="$y"$sel>$y</option>$YEAR~;
} else {
$YEAR .= qq~<option value="$y"$sel>$y</option>~;
}
}
}
my $DATE = qq~<td$PAD><div class="select"><select name="${name}_day"$DIS>$NULL$DAY</select></div></td>
<td>/</td>
<td$PAD><div class="select"><select name="${name}_month"$DIS>$NULL$MON</select></div></td>
<td>/</td>
<td$PAD><div class="select"><select name="${name}_year"$DIS>$TODAY$NULL$YEAR</select></div></td>
~;
if (($lang eq "en" || $flags =~ /U/) && $flags !~ /E/) {
$DATE = qq~<td$PAD><div class="select"><select name="${name}_month"$DIS>$NULL$MON</select></div></td>
<td>/</td>
<td$PAD><div class="select"><select name="${name}_day"$DIS>$NULL$DAY</select></div></td>
<td>/</td>
<td$PAD><div class="select"><select name="${name}_year"$DIS>$TODAY$NULL$YEAR</select></div></td>
~;
# this doesn't make sense ???
# if ($flags =~ /m/) {
# $DATE = qq~<td$PAD><div class="select"><select name="${name}_month"$DIS>$NULL$MON</select></div></td>
# <td></td>
# <td$PAD><div class="select"><select name="${name}_day"$DIS>$NULL$DAY</select></div></td>
# <td>,</td>
# <td$PAD><div class="select"><select name="${name}_year"$DIS>$TODAY$NULL$YEAR</select></div></td>
# ~;
# }
}
if ($flags =~ /P/) {
my @FORMAT = ("$DD/$MM/$YYYY","dd/mm/yyyy","ddmmyyyy");
if (($lang eq "en" || $flags =~ /U/) && $flags !~ /E/) {
@FORMAT = ("$MM-$DD-$YYYY","mm-dd-yyyy","mmddyyyy");
}
if (!$MM || !$DD || !$YYYY) {
$FORMAT[0] = "";
}
my $datelang = "en";
if ($lang =~ /^(da|de|es|fi|fr|nl|pt)$/) {
$datelang = $lang;
}
if ($lang =~ /^(lu|lb)$/) {
$datelang = "de";
}
my $JS;
if ($flags !~ /J/) {
my $TODAY = &todayhh();
if ($flags !~ /j/) {
$JS .= qq~<script src="/ono/osr/javascript/jquery/v2/jquery.js?$TODAY"></script>~;
}
$JS .= qq~<link href="/ono/osr/javascript/datepicker/dist/css/datepicker.min.css?$TODAY" rel="stylesheet" type="text/css">
<script src="/ono/osr/javascript/datepicker/dist/js/datepicker.js?$TODAY"></script>
<script src="/ono/osr/javascript/datepicker/dist/js/i18n/datepicker.$datelang.js?$TODAY"></script>
~;
}
$DATE = qq~<td>
<a href="javascript:void(0);" onclick="onojs_tablecell('ono_cal_${name}_picker');onojs_hide('ono_cal_${name}_selector');
onojs_setvalue('ono_cal_${name}_picker_field','$FORMAT[0]');onojs_focus('ono_cal_${name}_picker_field');">
<img class="block24" src="/ono/osr/images/icons/crystal/32x32/apps/cal.png" alt="">
</a>
</td>
<td id="ono_cal_${name}_picker" class="p0 hide">
$JS
<input id="ono_cal_${name}_picker_field" type="text" name="${name}_picker" value="" data-language="$datelang" data-date-format="$FORMAT[1]" class="datepicker-here">
<input type="hidden" name="${name}_picker_format" value="$FORMAT[2]">
</td>
<td id="ono_cal_${name}_selector" class="p0"><table class="default_table">$DATE</table></td>
~;
}
if ($flags =~ /T/) {
$DATE = qq~<table class="default_table">$DATE</table>~;
}
return $DATE;
}
###############################################################################
# secs to hh:mm:ss
###############################################################################
sub secs_hhmmss {
#: Convert secs to hhmmss.
my $input = $_[1];
my $hour = 0;
my $min = 0;
my $sec = $input;
my $whilecounter;
while ($sec > 59 && $whilecounter < 1024) {
$whilecounter++;
$min++;
$sec = $sec - 60;
}
while ($min > 59 && $whilecounter < 1024) {
$whilecounter++;
$hour++;
$min = $min - 60;
if ($min < 10) {
$min = "0$min";
}
if (!$min) {
$min = "00";
}
}
if ($sec < 10) {
$sec = "0$sec";
}
if (!$sec) {
$sec = "00";
}
if ($hour) {
return "$hour:$min:$sec";
} else {
return "$min:$sec";
}
}
###############################################################################
# birthday
###############################################################################
sub birthday_select {
#: Select birthday.
my (
$self,
$name,
$birthday,
$year,
$lang,
$BLK_ref,
) = @_;
my ($date_y,$date_m,$date_d) = &birthday("",$birthday,$year,$BLK_ref);
my $BIRTHDAY = qq~<td><div class="select"><select name="${name}_m">$date_m</select></div></td>
<td><div class="select"><select name="${name}_d">$date_d</select></div></td>
<td><div class="select"><select name="${name}_y">$date_y</select></div></td>
~;
if ($lang =~ /^(de|fr|lu)$/) {
$BIRTHDAY = qq~<td><div class="select"><select name="${name}_d">$date_d</select></div></td>
<td><div class="select"><select name="${name}_m">$date_m</select></div></td>
<td><div class="select"><select name="${name}_y">$date_y</select></div></td>
~;
}
return $BIRTHDAY;
}
sub birthday {
#: Select birthday, subroutine, see birthday_select().
my (
$self,
$birthday,
$year,
$BLK_ref,
) = @_;
my %BLK = %$BLK_ref,
my ($date_y,$date_m,$date_d);
for (my $i = $year-4; $i > 1899; $i--) {
my $sel;
if ($i == substr($birthday,0,4) || (substr($birthday,0,4) < 1900 && $i == $year-18)) {
$sel = "selected";
}
$date_y .= qq~<option $sel value="$i">$i</option>~;
}
for (my $i = 1; $i < 13; $i++) {
my $sel;
if ($i == substr($birthday,4,2)) {
$sel = "selected";
}
my $j = $i;
if ($i < 10) {
$j = "0$i";
}
my $mn = ucfirst &month_name("",$i);
$date_m .= qq~<option $sel value="$j">$BLK{$mn}</option>~;
}
for (my $i = 1; $i < 32; $i++) {
my $sel;
if ($i == substr($birthday,6,2)) {
$sel = "selected";
}
my $j = $i;
if ($i < 10) {
$j = "0$i";
}
$date_d .= qq~<option $sel value="$j">$i</option>~;
}
return ($date_y,$date_m,$date_d);
}
###############################################################################
# schoolyear
###############################################################################
sub schoolyear {
#: Return schoolyear.
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = &get();
my ($year1,$year2) = ($year-1,$year);
if ($mon > 7) {
($year1,$year2) = ($year,$year+1);
}
return "${year1}_${year2}";
}
###############################################################################
# mmm to mm
###############################################################################
sub mmm2mm {
#: Convert month (3-char) to number (2-char).
my $mmm = lc $_[1];
$mmm =~ s~jan~01~;
$mmm =~ s~feb~02~;
$mmm =~ s~mar~03~;
$mmm =~ s~apr~04~;
$mmm =~ s~may~05~;
$mmm =~ s~jun~06~;
$mmm =~ s~jul~07~;
$mmm =~ s~aug~08~;
$mmm =~ s~sep~09~;
$mmm =~ s~oct~10~;
$mmm =~ s~nov~11~;
$mmm =~ s~dec~12~;
return $mmm;
}
###############################################################################
# end of script
###############################################################################
1;
__END__