Very nice script. I changed some parts so it is more generic. Now I can convert dates to epoch-seconds and epoch-seconds back to different formatted dates. Nice exersice. I wonder if there is any module out there that can do the same thing.... ?
Here it is:
#! /usr/bin/perl
package TimeFormat ;
use strict ;
use warnings ;
require Exporter ;
our ($VERSION, $ISA, @EXPORT) ;
our @ISA = qw(Exporter);
@EXPORT = qw( sec2date date2sec ) ;
$VERSION = 1.0 ;
our @month_day = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) ;
# This function accepts epoch-seconds and returns a formatted date.
sub sec2date {
my ( $self, $time, $format) = @_ ;
if ( ref ( $self ) !~ /TimeFormat/ ) {
$format = $time ;
$time = $self ;
} else {
$format = $self->{format} if ( ! defined $format ) ;
}
$format = "%Y-%m-%d %H:%M:%S" if ( @_ == 1 && ! defined $format )
+; # no format defined, use default
my $mtime = $time ;
my $year = 1970 ; # start year
my ($month, $day, $julian) ;
my $hour = "00" ;
my $min = "00" ;
my $sec = "00" ;
my $msec = "0" ;
if ( $time =~ /\./ ) { # compute fraction of seconds
($time, $msec) = ($time =~ /(\d+)\.(\d+)/) ;
}
my $lyear = 31622400 ; # 366 days (leap year)
my $nyear = 31536000 ; # 365 days
my $dyear ; # dummy var
my %month_day ;
# calculate year
while ( $time >= 0 ) {
&_checkFebruary($year) ; # fix @month_day array
$dyear = (&_checkLeapYear($year) == 28 ? $nyear : $lyear) ;
if ( $time - $dyear < 0 ) {
last ;
} else {
$time -= $dyear ;
$year ++ ;
}
}
# calculate month/day and julian day
$julian = int $time / 86400 + 1 ; # start = 001 (not 000)
$time -= ($julian - 1) * 86400 ;
$julian = "0" x (3 - length($julian)).$julian ;
($month, $day) = _getMonthDay($year, $julian) ;
# calculate hour
$hour = int $time / 3600 ;
$time -= $hour * 3600 ;
$hour = "0" x (2 - length($hour)).$hour ;
# calculate min
$min = int $time / 60 ;
$time -= $min * 60 ;
$min = "0" x (2 - length($min)).$min ;
# calculate seconds and fraction of seconds
$sec = "0" x (2 - length($time)).$time ;
$msec = "0" x (3 - length($msec)).$msec ;
# format output
($format = $format ) =~ s/\%Y/$year/g ; # xxxx
($format = $format ) =~ s/\%m/$month/g ; # 1-12
($format = $format ) =~ s/\%d/$day/g ; # 01-31
($format = $format ) =~ s/\%j/$julian/g ;# 001-366
($format = $format ) =~ s/\%H/$hour/g ; # 00-23
($format = $format ) =~ s/\%M/$min/g ; # 00-59
($format = $format ) =~ s/\%S/$sec/g ; # 00-59
($format = $format ) =~ s/\%s/$msec/g ; # 000-999
($format = $format ) =~ s/\%E/$mtime/g ; # xxxxxxxxxxx.xxx
return $format ;
}
# Accepted input dates
# 2005-03-28 12:00:00
# 2005-03-28
# 2005-102 12:00:00
# 2005-102
# 2005102 12:00:00
# 2005102
sub date2sec {
my ($self, $time) = @_ ; # object
if ( ref ($self) !~ /TimeFormat/ ) {
$time = $self ;
}
$time = $self->{date} if ! defined $time ;
return 0 if ! defined $time ;
my ( $year,$month, $day, $julian, $hour, $minute, $second ) ;
# split date
if ( $time =~ /\d{4}-?(\d{3})\s{0,}?(\d\d:\d\d:\d\d)?/ ) {
( $year, $julian, $hour, $minute, $second ) = ( $time =~ m/
(\d{4}) # year
(?: # group the day - time portions
-? # optional hyphen
(\d{1,3}) # julian day
(?: # group the time portions
\s+ # one or more whitespace
(\d\d) # hour
:
(\d\d) # minute
:
(\d\d.*) # second + fractions
)? # time is optional
)? # day - time is optional
/xg );
return 0 unless _checkDateFormat( $year, $julian );
($month, $day) = _getMonthDay($year,$julian) ;
} elsif ( $time =~ /\d{4}-\d{2}-\d{2}\s{0,}?(\d\d:\d\d:\d\d)?/
+ ) {
( $year, $month, $day, $hour, $minute, $second ) = ( $time =~ m/
(\d{4}) # year
- #
(\d{2}) # month
- #
(\d{2}) # day
(?: # group the time portions
\s+ # one or more whitespace
(\d\d) # hour
:
(\d\d) # minute
:
(\d\d.*) # second + fractions
)? # time is optional
/xg );
return 0 unless _checkDateFormat( $year,$month,$day );
$julian = _getJulian($year, $month, $day) ;
} else {
return $time =~ /\d+/ || $time =~ /\d+\.\d+/ ? $time : 0 ; # 0 = f
+ailed to parse data
}
# convert data2seconds, should be good until the year 2100
my $depoch = 0 ;
$depoch += (($year - 1970) * 31536000);
$depoch += (int (($year - 1969) / 4)) * 86400; # correct for le
+ap years
$depoch += (($julian - 1) * 86400);
$depoch += ($hour * 3600);
$depoch += ($minute * 60);
$depoch += $second;
return $depoch ;
}
sub setDate {
my $self = shift ;
$self->{date} = shift ;
return 1 ; # OK
}
# predefine the output format (only works when using OOPerl)
sub format {
my $self = shift ;
$self->{format} = shift ;
if ( defined $self->{seconds} ) {
$self->sec2date() ;
}
return 1 ; # OK
}
sub _getJulian {
my ($year, $month, $day) = @_ ;
&_checkFebruary($year) ;
my $julian = 0 ;
my $key ;
for( my $i = 0; $i < $month -1; $i++) {
$key = "0" x(2 - length($i)).$i ;
$julian += $month_day[$key] ;
}
$julian += $day ;
return $julian ;
}
sub _getMonthDay {
my ($year, $julian) = @_ ;
my $month ;
_checkFebruary($year) ;
for(my $i = 0; $i < 12; $i++) {
if ( $month_day[$i] >= $julian ) {
$month = $i + 1 ;
last ;
}
$julian -= $month_day[$i] ;
$month = $i + 1;
}
return ("0" x (2 - length($month)).$month,"0" x (2 - length($julia
+n) ).$julian ) ;
}
# This function check if the given string is a correct date.
sub _checkFebruary {
$month_day[1] = _checkLeapYear(shift) ;
}
sub _checkDateFormat {
my ( $year,$month,$day ) = @_;
&_checkFebruary($year) ;
if ( defined $day ) { # input format is %Y-%m-%d
$month = '0'. $month if length( $month ) == 1;
return $day <= $month_day[ $month - 1 ] ? 1 : 0 ;
} else {
my $jday = $month ; # month represents julian day
return _checkLeapYear($year) == 28 ? $jday <= 365 ? 1 : 0 : $jd
+ay <= 366 ? 1 : 0 ;
}
}
sub _checkLeapYear {
my ( $self, $year ) = @_ ;
$year = $self if ( ! defined $year ) ;
return 29 unless $year % 400;
return 28 unless $year % 100;
return 29 unless $year % 4;
return 28;
}
# constructor
sub new {
my ( $class, $time, $format ) = @_ ;
$time = date2sec($time) if defined $time ; # convert input to epoc
+h-seconds
return bless { seconds => $time, format => $format }, __PACKAGE__
+;
}
__END__
Cheers
Luca
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.