В Perl, как я могу разобрать строку даты и вычесть дни из даты, которую она представляет?



У меня есть дата в строке, как в $str1="20120704". Я хочу вычесть 1 день из этой даты и сохранить значение даты в виде строки в $str2. Как я могу это сделать?

650   5  

5 ответов:

Это очень похоже на другой вопрос, который вы задали пару дней назад. Поэтому неудивительно, что решение также очень похоже.

Time:: Piece и Time:: Seconds были частью стандартного дистрибутива Perl начиная с версии 5.10.0. Вы должны использовать их.

#!/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. Итак, что вам нужно сделать:

  1. преобразуйте вашу дату (которая находится в формате YYYYMMDD) в формат хранения даты/времени Perl.
  2. используйте Perl для управления этой датой и временем.
  3. Когда вы хотите вывести результаты, вы должны преобразовать их обратно в нужный формат.

Преобразование даты (которая находится в формате YYYYMMDD) в формат хранения даты и времени Perl.

Лучший модуль для этого - Time::Piece , который поставляется с Perl. Это довольно просто:

my $date = Time::Piece->strptime($str1, '%Y%m%d');

$date теперь будет ваша дата и время, но сохраненные в формате Perl можно понять и манипулировать. %Y%m%d - это описание вашего формата, поэтому Perl знает, где найти год, месяц и день месяца. Вы можете посмотреть на strftime, чтобы увидеть различные параметры формата. В вашем случае:

  • %Y - представляет год с веком, например 2012.
  • %m - представляет месяц в виде двухзначного числа, например 03 или 12.
  • %d - представляет дату месяца в виде двухзначного числа от 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, но она распространена на Солярисе. В данном случае мы сделаем это очень старомодным способом. Есть две функции Perl, называемыеlocaltime иgmtime . Эти возьмите число секунд с 1 января 1970 года и преобразуйте его в массив значений, каждое из которых представляет определенную часть времени (месяц, год, День, часы, минуты и т. д.).). Что вам нужно, так это обратные функции - что-то, что может взять массив значений и преобразовать его в число секунд с 1970 года. Начиная с Perl 3.0, такой модуль был включен в каждую версию Perl. В Perl 5.x, tt называется Time:: Local . Это дает вам два функции называются timelocal и timegm. Это те обратные функции, которые нам нужны. Во-первых, нам нужно разделить вашу строку на отдельные год, месяц и день, поместить их в массив для timegm или timelocal, чтобы превратить в число секунд с 1 января 1970 года. Далее мы вычтем количество секунд в сутках. Это и есть 60 * 60 * 24 или 86 400.

Наконец, мы преобразуем эту новую дату в массив, который вы можете использовать для отображения даты в YYYYMMDD порядок.

Два важных предостережения!
    Функция предполагает, что месяц находится в диапазоне от 0 до 11, а не от 1 до 12. Это позволяет создать массив для преобразования числа месяца в имя. Это означает, что мы должны вычесть 1 из месяца, прежде чем мы дадим его gmtime и добавить один, когда возьмем его обратно из 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 и один 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 против gmtime, и прыжковые секунды, если вы заботитесь о них.

Это просто strptime/strftime туда и обратно. Поскольку strftime нормализует входные данные, достаточно просто вычесть 1 из поля mday.

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;

Comments

    Ничего не найдено.