开发者

Is there a Perl equivalent of SAS' INTNX function or Javascript's Dateadd function?

开发者 https://www.devze.com 2022-12-14 11:18 出处:网络
I\'m trying to convert Chinese lunar system to Gregorian using Perl, both for fun and for learning purposes. I thought there was some kind of easy mathematical algorithm to do the job but turned out I

I'm trying to convert Chinese lunar system to Gregorian using Perl, both for fun and for learning purposes. I thought there was some kind of easy mathematical algorithm to do the job but turned out I was wrong. Anyway, after a little googling around I came aross some ready SAS code that could do the job. Well, it was not too difficult for me to figure out how to rewrite most of the code in Perl. But there is something like this:

Convert2Gregorian = INTNX ('day', conDate, AddDay-1);

Google tells me that INTNX is a function that can return a date after which a certain date interval has been added. But using the keywords "Perl INTNX" gave me nothing useful. I then found a script written in Javascript, the general approach is about the same except that the Javascript uses Dateadd function, something like:

Return DateAdd(DateInterval.Day, AddDay - 1, conDate) 

I also tried searching using PPM but was unable to find the module I wanted. Can someone kindly give me some pointers?

Thanks in advance :)

Update

Thanks to @psilva and @hobbs :)

Haha, finally I can translate one programming language to another. It's fun :) Just for fun and maybe for later reference: Here's the original SAS code and the Perl code translated by me. Correct me if I'm wrong :)

Note: Data incomplete.

SAS CODE IS AS FOLLOWS:

data DateNtoG (drop = Ngstrings conDate AddMonth AddDay Mrunyue I);
array NGlist{43} $18_TEMPORARY_(
"010110101010170130" /*(1968)*/
"010101101010000217" /*(1969)*/
"100101101101000206" /*(1970)*/
"010010101110150127" /*(1971)*/
);

input tYear tMonth tDay RunYue;

if (tyear >1967 and tyear<2011) then do;
NGstrings = NGlist(tYear - 1967);
conDate = MDY (substr (NGstrings,15,2),(NGstrings, 17,2), tYear);

AddMonth = tMonth;

select (substr(NGstrings, 14, 1));
when ("A" )  Mrunyue=10;
when ("B" )  Mrunyue=11;
when ( "C" ) Mrunyue=12;
otherwise Mrunyue = substr (NGstrings, 14,1);
end;
开发者_如何学Python
if ((RunYue=1) and (tMonth=Mrunyue) ANDMrunyue>0)or ((tMonth Mrunyue) AND Mrunyue>0) then
do;
Addmonth = tMonth+1;
end;

AddDay = tDay;
do i = 1 To AddMonth-1;
AddDay = AddDay + 29 + substr(NGstrings,i,1);
end;

dNtoG = INTNX ('day', conDate, AddDay - 1);
put "Transfereddate:" dNtoGdate9.;
end;

TRANSLATED Perl CODE IS AS FOLLOWS: didn't handle the undefined situations for the moment

(I Changed the original SAS variable names)

#!perl

# A Chinese-Gregorian Calendar System Converter just for Testing

use Date::Calc qw(Add_Delta_Days); 
use integer;
use strict;
use warnings;

$_ = shift @ARGV;

if (length == 8) {
    $_.=0;
}

my ($Lunar_Year,$Lunar_Month,$Lunar_Day,$Leap_Month) = /(\d\d\d\d)(\d\d)(\d\d)(\d)/;


my %Lunar_Year_Patterns = qw/1968 010110101010170130 1969 010101101010000217 1970 100101101101000206 1971 010010101110150127/;

if (substr ($Lunar_Year_Patterns{$Lunar_Year},13,1) =~ /A/) {
         $Leap_Month = 10;
} elsif (substr ($Lunar_Year_Patterns{$Lunar_Year},13,1)=~ /B/){
        $Leap_Month = 11;
} elsif (substr ($Lunar_Year_Patterns{$Lunar_Year},13,1)=~ /C/){
        $Leap_Month = 12;
} else {
$Leap_Month = substr($Lunar_Year_Patterns{$Lunar_Year},13,1);
}

my $First_Lunar_Day_In_Gregorian_Month = substr($Lunar_Year_Patterns{$Lunar_Year},14,2);
my $First_Lunar_Day_In_Gregorian_Day = substr($Lunar_Year_Patterns{$Lunar_Year},16,2);

my $AddMonth;
if ( (($Leap_Month ==1) && ($Lunar_Month == $Leap_Month) && ($Leap_Month > 0)) || (($Lunar_Month > $Leap_Month) && ($Leap_Month>0) ) ){
    $AddMonth = $Lunar_Month +1;
} else {
$AddMonth = $Lunar_Month;
}

my $AddDay;
$AddDay = $Lunar_Day;

for(my $i = 1; $i <= $AddMonth - 1; $i++){
$AddDay = $AddDay +29 + substr($Lunar_Year_Patterns{$Lunar_Year},$i,1);
}


my @Gregorian = Add_Delta_Days($Lunar_Year,$First_Lunar_Day_In_Gregorian_Month,$First_Lunar_Day_In_Gregorian_Day,$AddDay -1);
print @Gregorian;


DateTime is the 800-pound gorilla of date handling. It's quite large, but it's large because it does a lot, and more importantly, it does it right.

With DateTime you would simply construct the DateTime object for the starting date, and then obtain the ending date by adding: $dt->add(days => $add_days).

Also, there's a DateTime::Calendar::Chinese that you can compare your results with, even if you want to reinvent this particular wheel for fun :)


Check out the delta functions in Date::Calc and Date::Calc::Object, and Date::Calc::PP. Specifically, you might want to look at the DateCalc_add_delta_days subroutine in the PP source.

You could also try looking at the source of Calendar::China.

0

精彩评论

暂无评论...
验证码 换一张
取 消