のように文字列に日付があります$str1="20120704"
。その日付から1日を減算し、日付の値を文字列としてに格納します$str2
。どうすればいいですか?
5 に答える
これは、数日前に尋ねた別の質問と非常によく似ています。したがって、当然のことながら、ソリューションも非常に似ています。
Time::PieceとTime::Secondsは、バージョン5.10.0以降の標準のPerlディストリビューションの一部です。あなたはそれらを使うべきです。
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
use Time::Seconds;
my $format = '%Y%m%d';
my $str1 = '20120704';
my $dt1 = Time::Piece->strptime($str1, $format);
my $dt2 = $dt1 - ONE_DAY;
my $str2 = $dt2->strftime($format);
say $str2;
Perlは、日付と時刻を簡単に操作できる内部形式で保存します。あなたが持っているのはYYYYMMDD形式の日付です。だから、あなたがする必要があるのは:
- 日付(YYYYMMDD形式)をPerlの日付/時刻ストレージ形式に変換します。
- Perlを使用して、この日付と時刻を操作します。
- 結果を出力する場合は、必要な形式に変換し直す必要があります。
日付(YYYYMMDD形式)をPerlの日付/時刻ストレージ形式に変換します。
これを行うための最良のモジュールは、Perlに付属しているTime::Pieceです。とても簡単です。
my $date = Time::Piece->strptime($str1, '%Y%m%d');
$date
これで日付と時刻になりますが、Perlが理解して操作できる形式で保存されます。これ%Y%m%d
はフォーマットの説明であるため、Perlは年、月、日を見つける場所を知っています。strftimeを見ると、さまざまなフォーマットパラメータを確認できます。あなたの場合:
%Y
-など、世紀とともに年を表し2012
ます。%m
-月をまたはなどの2桁の数字として03
表します12
。%d
-その月の日数が多い場合は、その月の日付をから2桁の数字で01
表します。31
次へ:日付を操作します。
これを処理するTime::Secondsという別のモジュールを使用できます。
Time::Seconds
ONE_DAY
物事を簡単にするような定数の束を定義します:
my $date = $date - ONE_DAY;
最後に:日付を希望の形式に戻します。
繰り返しTime::Piece
ますが、これを行うための気の利いた簡単な方法があります。
$date->ymd("");
$date
これは、年-月-日形式の文字列に変換されます。デフォルトでは、これにより-
各パーツの間に配置されます。ただし、仕切りとして使用する文字を渡すことができます。この場合、何もありません。
すべて一緒に:
use Time::Piece # For manipulating and storing the date
use Time::Seconds # For the nice constants such as ONE_DAY and ONE_WEEK
my $date = Time::Piece->strptime($str1, '%Y%m%d');
my $date = $date - ONE_DAY;
my $str2 = $date->ymd('');
それはとても簡単です。
デイブクロスはあなたに素晴らしい答えを与えました。私は通常、彼に賛成票を投じて、そのままにしておきます。しかし、彼はまた、あなたが数日前に同様の質問をしたと述べました。私にとって、それはあなたがデイブクロスの以前の答えを使用したかもしれないが、あなたはそれを理解していなかったことを意味します。それは良いことではありません。
Time::PieceとTime::Secondsのドキュメントを見てください。strfdateを見て、それを試してみてください。それを学び、理解してください。これらについて質問がある場合は、Stackoverflowで質問してください。Stackoverflowのユーザーは、「これはどのように機能しますか?」などの質問に喜んで答えています。「私のためにこれをしてくれませんか?」ではなく。彼らは前者を説明するのに時間と労力を要しますが、ほとんどの人は後者を無視するか、大雑把な答えを与えます。
これはあなたをより良いプログラマーにするでしょう、それはあなたがあなたの会社でより価値があり、それがより高い賃金につながることを意味します。それはあなたの時間と努力の価値があります。
それを理解してみてください。それで遊んでください。
補遺
古いperlバージョン5.8を使用していて、システム内の既存のモジュールを使用することを考えていました。また、time::pieceがどのように機能するかわからない
これはかなり古いバージョンのPerlですが、Solarisでは一般的です。
この場合、非常に古い方法で行います。
localtimeとgmtimeという2つのPerl関数があります。これらは1970年1月1日からの秒数を取り、それを値の配列に変換します。各値は時間の特定の部分(月、年、日、時間、分など)を表します。
必要なのは逆関数です。値の配列を取り、それを1970年以降の秒数に変換できるものです。Perl3.0以降、Perlの各バージョンに含まれているようなモジュールがあります。Perl 5.xでは、ttはTime::Localと呼ばれていました。timelocal
とと呼ばれる2つの関数を提供しますtimegm
。これらは私たちが必要とする逆関数です。
まず、文字列を別々の年、月、日に分割し、それを1970年1月1日以降の秒数に変換するために、配列に配置する必要がtimegm
あります。timelocal
次に、1日の秒数を減算します。これは60*60*24または86,400です。
最後に、その新しい日付を、YYYYMMDDの順序で日付を表示するために使用できる配列に変換します。
2つの重要な注意事項!
- この関数は、月が1から12ではなく0から11であることを前提としています。これにより、月番号から名前に変換する配列を作成できます。つまり、与える前の月から1を引き、から
gmtime
戻すときに1を足す必要がありますtimegm
。 - 年は1900年からの年数です。つまり、に与える前に1900を減算し
gmtime
、から戻すときに1900を加算する必要がありますtimegm
。
そして今、プログラム:
#! /usr/bin/env perl
use strict;
use warnings;
use Time::Local;
my $date = 20120615; #2012-June-15
$date =~ /(....)(..)(..)/; #Parse the date
my $year = $1;
my $month = $2;
my $day = $3;
$month -= 1; #Month is 0 to 11 and not 1 to 12
$year -= 1900; #Year is number of years since 1900
my $seconds = 0;
my $minutes = 0;
my $hours = 0;
my $perl_date = timegm($seconds, $minutes, $hours, $day, $month, $year);
my $perl_date2 = $perl_date - (60 * 60 *24);
my ($seconds2, $minutes2, $hours2, $day2, $month2, $year2) = gmtime($perl_date2);
$month2 += 1; #Month is returned as 0 - 11. Make 1 - 12
$year2 += 1900; #Year is given as years since 1900. Add 1900 back to it.
printf qq(The date is %04d-%02d-%02d \n), $year2, $month2, $day2;
フォーマットにはモジュールDateTime
と1つのextを使用することをお勧めします。Date::Calc
また、モジュールまたはDate::Parse
+POSIX
関数strftimeを見ることができます。
use strict;
use DateTime;
use DateTime::Format::Strptime;
my $date_str = '20120704';
my $date_obj = DateTime::Format::Strptime->parse_datetime($date_str);
my $date_res = $date_obj->subtract(days => 1)->ymd;
これでいいですか?
use Date::Parse;
use POSIX;
my $s1 = "20120704";
my $t = str2time($s1) - 86400;
my $s2 = strftime "%Y%m%d", localtime $t;
print "$s2\n";
localtime
vsに注意し、それらを気gmtime
にする場合はうるう秒。
これは単純なstrptime
/strftime
往復です。入力を正規化するのでstrftime
、mdayフィールドから1を引くだけです。
use POSIX 'strftime';
use POSIX::strptime 'strptime';
my $fmt = "%Y%m%d";
my @t = strptime "20120704", $fmt;
$t[3] -= 1; # 1 day
my $str2 = strftime $fmt, @t;