#!/usr/bin/perl -w use strict; # about: # ----- # author: parv UNDERSCORE AT yahoo DOT com # name: timeconvert.perl # modified: Oct 08 2005 # # currently this program does the below stated conversion, but can be # (easily) extended to do other conversions. # # unix date/time in seconds is convereted to year, month, day, hour, # minute, second. 0s is converted to "1970 01 01 00 00 00" UTC (year month # day hour minute second), same as "date -u -r 0". # # ! ** note ** this alogrithm implemented here seems to have some rounding # ! errors in calculations for seconds. however, there seems to be no problem # ! in the original javascript version ... # ! # ! http://www.fourmilab.ch/documents/calendar/ # ! # ! ... problem seems to be having no javascript equivalent fraction() # ! function; here in perl, fraction is obtained by subtracting from the # ! integer part (given by int()), possibly causing the error. # ! # ! for example, seconds do not come out sequentially for 2147483649 (08) & # ! 2147483650 (10); for 2147483647, seconds came put to be "06" while date # ! command report that to be "07". # # credits: # ------- # this program's date conversion alogrithm is based on an # article about interdate convserions (shown via javascript); # author of the article is john walker, founder of autocad. # article copies are available at many places, two of which 're... # # http://www.fourmilab.ch/documents/calendar/ # http://www.michaelmccafferty.com/mmmdate.htm # # ...the article recommends/referrs to... # # 1. astronomical alogritms, # mjean meeus; 1991; isbn: 0-943396-35-2 # # 2. explanatory supplement to the astronomical alamnac, # p. kenneth seidelmann (ed.); 1992; isbn: 0-935702-68-7 # use constant { Seconds_Per_Minute => 60 , Minutes_Per_Hour => 60 , Hours_Per_Day => 24 , Seconds_Per_Hour => 60 * 60 , Seconds_Per_Day => 60 * 60 * 24 , Avg_Julian_Year => 365.25 , Avg_Gregorian_Year => ( 400 # years * 365 # days + 97 # compensation days? ) / 400 # years # adjust unix epoc in julian day number by 0.5day so that day starts on # midnight instead of noon , Unix_Epoc_Julian => 2440587.5 +0.5 } ; foreach my $epoch (@ARGV) { unless ($epoch =~ m/^\d+$/) { print "\n# $epoch is not a unsigned number, skipping...\n"; next; } # convert given seconds into (fractional) julian days my $d = unix_sec_to_julian_day($epoch); my $d_int = int($d); my $diff = $d - $d_int ; # get date & time... my ($year , $month , $day) = julian_day_to_date($d_int , $diff); my ($hour , $min , $sec) = julian_day_to_time($diff); printf "%11d -> %04d-%02d-%02d %02d:%02d:%02d\n" , $epoch , $year , $month , $day , $hour , $min , $sec; } exit; # convert unix seconds time to fractional julian day sub unix_sec_to_julian_day { my ($sec) = @_; return 0 if not_digit($sec); return Unix_Epoc_Julian + ($sec / Seconds_Per_Day); } # return fractional julian day as list of hour, minute, second sub julian_day_to_time { my ($day_diff) = @_; return ('00') x3 if not_digit($day_diff); # convert difference of julian days to seconds my $sec_diff = $day_diff * Seconds_Per_Day; my ($h , $m , $s); $h = int( $sec_diff / Seconds_Per_Hour ); $m = int( ($sec_diff /Seconds_Per_Minute) %60 ); $s = int( $sec_diff %60 ); return ($h , $m , $s); } # return fractional julian day as list of year, month, day sub julian_day_to_date { my ($days, $diff) = @_; return ('0000', '00', '00') if not_digit($days) || not_digit($diff) ; my ($x, $y, $m, $d); # calculate year, month, day if ($days < 2299161) { $x = $days; } else { $y = int( ($days -1867216.25) / Avg_Gregorian_Year /100 ); $x = $days + $y - int($y /4) +1; } $y = int( ($x +1524 -122.1) / Avg_Julian_Year ); $m = int( ($x +1524 - int($y * Avg_Julian_Year)) /30.6001 ); $d = int( $x +1524 + $diff - int($y * Avg_Julian_Year) - int($m *30.6001) ); $m = ($m < 14) ? ($m -1) : ($m -13); $y = ($m > 2) ? ($y -4716) : ($y -4715); return ($y , $m , $d); } sub not_digit { my ($d) = @_; return 1 if !(defined $d || $d =~ m/\d+/); return 0; }