从给定日期查找日期

问题描述 投票:0回答:5
#!/usr/bin/perl

@month = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
@week = ("Sunday", "Monday","Tuesday", "Wednesday","Thursday", "Friday", 
    "Saturday");

print "date:\n";
$date=<STDIN>;
print "mon:\n";
$mon=<STDIN>;
print "year:\n";
$year=<STDIN>;

if ( ($year % 400 == 0) || ($year % 4 == 0) && ($year % 100 != 0) )
{
    $month[1] = 29 ;
    for($i = 0 ; $i < $mon - 1 ; $i++)
    {       
        $s = $s + $month[$i] ;
        $s = $s + ($date + $year + ($year / 4) - 2) ;
        $s = $s % 7 ;
    }
}
print $week[$s+1] ;

我已经尝试学习 perl 几天了,我编写了代码来查找给定日期的日期。实际上我是从 C 代码转换过来的。但它不是真的。输出始终为星期一。我哪里错了?

perl
5个回答
5
投票

正如@Chris Turner 指出的那样,您的代码中没有路径可以处理不是闰年的情况。要解决此问题并实现您既定的目标,只需对您的代码进行一个小改动。

if( ($year % 400 == 0) || ($year % 4 == 0) && ($year % 100 != 0) ) {
   $month[1] = 29 ;
   for($i = 0 ; $i < $mon - 1 ; $i++) {
      ...
   }
}
print $week[$s+1] ;

应该重写并重新缩进为

if( ($year % 400 == 0) || ($year % 4 == 0) && ($year % 100 != 0) ) {
   $month[1] = 29 ; 
}
for($i = 0 ; $i < $mon - 1 ; $i++) {
   ...
}
print $week[$s+1] ;

所以

$month[1]
只更新闰年,但你的
for
循环中的代码总是运行。


有经验的 Perl 程序员也总是建议你用

开始每个脚本
use strict;
use warnings;

因为这些 pragma 促进了良好的编程实践并有助于在开发早期发现许多错误。他们不会帮助解决这个问题,但如果你开始使用它们,他们会帮助解决下一个问题。


2
投票

不要自己做。使用模块。 Time::Piece 近十年来一直是 Perl 发行版的标准部分。

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Time::Piece;

print "date:\n";
chomp(my $date = <STDIN>);
print "mon:\n";
chomp(my $mon = <STDIN>);
print "year:\n";
chomp(my $year = <STDIN>);

my $tp = Time::Piece->strptime("$year-$mon-$date", '%Y-%m-%d');

say $tp->fullday;

我做的其他一些调整:

  • 总是
    use strict
    use warnings
  • my
  • 声明变量
  • 使用
    chomp()
    从输入中删除换行符

更新: 我现在更详细地查看了您的代码。那里只有一个错误。

你的逻辑是这样的:

if (we're in a leap year) {
    Change the @months array to deal with leap years
    Do the maths to calculate the day
}

当它应该是这样的时候:

if (we're in a leap year) {
    Change the @months array to deal with leap years
}
Do the maths to calculate the day

所以,除非您输入的年份是闰年,否则您将跳过所有计算。这意味着 $s 永远不会被赋值。 Perl 将未定义的值视为 0,因此您的最终语句始终打印

$week[0 + 1]
,即星期一。

如果像 Time::Piece 这样的模块不可用,Perl 程序员会像这样编写代码:

#!/usr/bin/perl

# Force us to declare variables.
use strict;
# Get Perl to tell us when we're doing something stupid
use warnings;
# Allow the use of say()
use feature 'say';

# Declare variables with my()
my @month = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
# qw(...) defines a list without all that tedious punctuation
my @week = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday);

print "date:\n";
# Use chomp() to remove newlines from input
chomp(my $date = <STDIN>);
print "mon:\n";
chomp(my $mon = <STDIN>);
print "year:\n";
chomp(my $year = <STDIN>);

# This logic can be cleaned up a lot.
if ( ($year % 400 == 0) || ($year % 4 == 0) && ($year % 100 != 0) ) {
    $month[1] = 29 ;
}

# Initialise $s to avoid warnings later
my $s = 0;
# A foreach look is almost always cleaner than for (;;)
foreach my $i (0 .. $mon - 2) {
    # Haven't checked your calculations (but they seem to work
    # += is  useful shortcut
    $s += $month[$i];
    $s += ($date + $year + ($year / 4) - 2);
    $s %= 7;
}

# say() is like print() but with an extra newline
say $week[$s+1];

2
投票

还要介绍一个最广泛使用的日期和时间模块,这里是DateTime

use warnings;
use strict;
use feature qw(say);

use DateTime;

# ... acquire input ($year, $mon, $date)

my $dt = DateTime->new(year => $year, month => $mon, day => $date);

say $dt->day_name;

这是一个非常大且“重”的模块,具有很多功能。还有其他的。

虽然我支持作为学习的一部分手动执行此操作,但一旦涉及到日期和时间,您将需要使用模块。


1
投票
use Time::Local qw( timegm );

my @dow_names = qw( Sunday Monday Tuesday Wednesday Thursday Friday Saturday );

my $Y = ...;
my $m = ...;
my $d = ...;

my $epoch = timegm(0, 0, 0, $d, $m-1, $Y-1900);
my $dow = ( gmtime($epoch) )[6];
my $dow_name = $dow_names[$dow];

更好的是,

use POSIX       qw( strftime );
use Time::Local qw( timegm );

my $Y = ...;
my $m = ...;
my $d = ...;

my $epoch = timegm(0, 0, 0, $d, $m-1, $Y-1900);
my $dow_name = strftime("%A", gmtime($epoch));

您也可以使用DateTime;它使用起来更简单,但它不像上面使用的模块那么轻。


0
投票

我的解决方案非常简单,指定给定日期的特定纪元时间,然后使用

strftime
检索工作日。

use Time::Local;

#The time was set to be 10:30:30 as default.

$designated_epoch_time = timelocal(30, 30, 10, $given_day, $given_month-1, $given_year); 

$weekday = strftime("%w", localtime($designated_epoch_time));
© www.soinside.com 2019 - 2024. All rights reserved.