【问题标题】:Convert YYDDD to YY/MM/DD将 YYDDD 转换为 YY/MM/DD
【发布时间】:2013-08-28 13:33:30
【问题描述】:

我正在寻找一种将 YYDDD 格式的日期转换为 YY/MM/DD 的方法。

即12212 变为 12/07/30。

可以在http://www.longpelaexpertise.com.au/toolsJulian.php 找到一个php 示例,您可以在http://landweb.nascom.nasa.gov/browse/calendar.html 找到一个DDD 日历

无论有没有 perl 模块,我都非常感谢任何指导。

谢谢!

编辑: 我不是在寻找一种方法来转换 php2perl 或类似的东西。我只是在寻找一种使用 perl 将 YYDDD 转换为 YY/MM/DD 的方法。我更喜欢不使用任何额外 perl 模块的方法,但如果这是唯一的方法,那么我将欢迎使用 perl 模块的示例。

【问题讨论】:

  • 你有什么尝试吗?
  • 所以您正在寻找php2perl 工具??
  • 现在日期操作的标准是 DateTime 系列模块。 search.cpan.org/dist/DateTime
  • @Borodin 核心内容并不意味着它特别好、推荐、现代或标准。它只是用来引导 perl 和其他 CPAN 模块的安装(或出于历史原因)。
  • Time::Piece 模块已修复。您现在可以将 Time::Piece 与 1.23 版模块一起使用。

标签: perl


【解决方案1】:

最好的方法是使用Time::Piece 来解析日期并重新格式化,就像这样

Time::Piece->strptime('12212', '%y%j')->strftime('%y/%m/%d')

不幸的是,该模块不接受strptime 格式的%j(一年中的某天)(尽管strftime 格式很好)。

第二好的选项是来自POSIX 模块的strftime。该字符串必须首先拆分为年和日,并且年中的日是从零开始的,因此必须减去一个,但是转换很简单。可能最好打包成一个子程序,像这样

use strict;
use warnings;

use POSIX 'strftime';

sub yj2ymd {
  my ($year, $yday) = $_[0] =~ /(\d\d)(\d\d\d)/;
  strftime('%y/%m/%d', 0, 0, 0, 0, 0, 2000+$year, 0, $yday-1);
}

print yj2ymd('12212');

输出

12/07/30

如果您期望上个世纪的任何日期,您将不得不对这一年做一些更有趣的事情。

【讨论】:

  • 由于某种原因,我得到了11/12/31 作为您的代码 sn-p 的输出,这很不幸。
  • @amon:多么奇怪。你的 POSIX 是最新的吗?我有1.30。这就是从strftime 中删除最后两个参数后得到的值。
  • POSIX->VERSION 表示1.32,perl 是 v18.1。似乎是一个错误:使用较旧的 perl 一切正常。调查。也许我弄乱了一些编译标志。
  • @amon: The docs 暗示strftime 的行为取决于底层系统功能。也许这就是区别:我在 Windows 上,而你显然不在。
  • Time::Piece 和 %j 对我有用。可能取决于版本。
【解决方案2】:

我喜欢Time::Piece 只是因为它是 Perl 自带的,我相信是 5.10 版。您会发现数十个日期/时间模块,每个人都有自己的最爱,但随着 Time::Piece 成为官方发行版的一部分,是时候切换到它了。

要使用 Time::Piece,您需要了解 strptime (STRing Parse TIME) 和 strftime (STRing Format TIME) 两者都使用%x 字母格式来表示时间字符串的某些方面。原因是Time::Piece 使用相同的%x 格式字符来将您的时间字符串转换为时间对象,有时还会将该时间对象 格式化为您的字符串。

来自strftime 的手册页:

%j

以十进制数表示的一年中的日期(范围为 001 到 366)。

还有:

%y

没有世纪的十进制数字形式的年份(范围 00 到 99)。

现在转换您的日期:

use Time::Piece;

my $old_time = "12212";   #YYddd
my $time = Time::Piece->strptime( $old_time, "%y%j" );
my $new_time = $time->ymd("/"); Now in YY/MM/DD format

哎呀

等等——strptime 不能理解 %j。这将给出错误的答案。

我没有对此进行测试,因为我经常使用 Time::Piece,以至于我可以在睡梦中进行。我之前从未在Time::Piece 中使用过%j。 perldoc 没有提到 %j 不起作用,我也没有收到任何错误。这不好。

新策略。我可以将YYddd 字符串解析为年和日。然后,我可以将一年的开始设为01/01/$year。在那之后,我可以把天数加到年里。但是,要正确执行此操作,我需要来自 Time::Seconds 的常量:

use strict;
use warnings;
use feature qw(say);
use Time::Piece;
use Time::Seconds;

my $old_date = "12212";
$old_date =~ /(..)(.*)/;
my $year = $1;
my $days = $2;

my $time = Time::Piece->strptime("01/01/$year", "%m/%d/%y");
$time += ( ( $days - 1 ) * ONE_DAY);  #01/01/$year is day 1 and not 0

say  $time->strftime("%y/%m/%d");

这给出了12/07/30 作为答案。


公告

Time::Piece 模块的所有者修复了模块中的错误。 1.23 版现在可以使用:

use warnings;
use strict;
use autodie;
use feature qw(say);
use Data::Dumper;

use Time::Piece;

my $old_time = "12212";   #YYddd
my $time = Time::Piece->strptime( $old_time, "%y%j" );
my $new_time = $time->ymd("/"); #Now in YY/MM/DD format
say "Version: $Time::Piece::VERSION";
say $new_time;

打印出来:

Version: 1.23
2012/07/30

【讨论】:

  • 等一下——strptime 无法理解%j。这将给出错误的答案。
  • 我假设你没有尝试过这个?首先,strptime 已损坏,不会接受%j,其次,ymd 返回 完整 四位数年份,而需要的是 %y/%m/%d
  • 我怀疑,结果是2012/01/01,这根本不对。
  • @pilcrow 我不知道Time::Piece 不了解%j。 Perldoc 中没有任何内容,它返回一个有效的时间对象。对我来说,这是一个重大错误。考虑到这一点,重新回答了我的答案。见上文。
  • +1 用于解释 strptime/strftime。正如您自己所说,您提供的原始答案不准确,但是,第二次尝试提供了正确答案 - 谢谢!
【解决方案3】:

这里有一个简短而甜蜜的方法来做你想做的事:

#!/usr/bin/perl

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

my $dt = '12212';

my $startYr = 2000 + substr($dt, 0, 2);
my $daysToAdd = substr($dt, 2) - 1;
my ($newYr, $newMo, $newDay) = Add_Delta_Days($startYr, 1, 1, $daysToAdd);

printf("%02d/%02d/%02d\n", $newYr % 100, $newMo, $newDay);

【讨论】:

  • 你需要用斜线分隔的两位数年份,所以printf("%02d/%02d/%02d\n", $newYr % 100, $newMo, $newDay);
  • 我不知道你为什么得到-1。在许多方面,我认为这是最好的解决方案。来自我的 +1
猜你喜欢
  • 2012-01-27
  • 2013-10-25
  • 1970-01-01
  • 1970-01-01
  • 2019-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-14
相关资源
最近更新 更多