Как я могу получить начало месяца в форме эпохи из случайной метки времени эпохи в Perl?

Я получаю несколько раз из базы данных и пытаюсь хранить их по месяцам, используя форму эпохи. Таким образом, у меня могло быть несколько случайных моментов, например:

1354120744
1328978360
1297388332

и для каждого я хочу найти значение эпохи, которое представляет 1-е число этого месяца, поэтому для последней временной метки это будет:

1296518400 (используя прекрасную epochconverter.com).

Я знаю, что могу использовать POSIX mktime, чтобы уменьшить временную метку до дней, минут и т. д. и соответственно изменить их и т. д., как это было в ответе на сообщение, которое я сделал некоторое время назад: Как вернуться на месяцы назад в Perl с учетом разных дней в месяце?

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

Я не видел никаких других методов POSIX, которые казались полезными. Любая помощь приветствуется!


person dgBP    schedule 28.11.2012    source источник


Ответы (3)


Моей первой мыслью было бы использовать Time::Local для преобразования результатов localtime обратно в эпоху, с соответствующими значениями, установленными на 0 или 1 по мере необходимости. Обратите внимание, что день недели не входит в число ожидаемых входных значений, поэтому вам не нужно беспокоиться о том, что произойдет, если вы ошибетесь.

$start_of_month_epoch = timelocal(0, 0, 0, 1, $month, $year);

person Dave Sherohman    schedule 28.11.2012
comment
и здесь я наивно думал, что localtime и timelocal это одно и то же... глупый я! Благодарность :) - person dgBP; 28.11.2012
comment
localtime и timelocal противоположны; localtime превращает целое число эпохи в 6 (или 9) разбитых полей, а timelocal превращает эти 6 полей обратно в целое число эпохи. Они отлично подходят для такого рода проблем. - person LeoNerd; 29.11.2012

Я перестал беспокоиться о проблемах с метками времени, так как встретил DateTime:

$ perl -MDateTime -E 'say DateTime->from_epoch(epoch => 1354120744)->truncate(to => "month")->epoch;'
1351728000
person creaktive    schedule 28.11.2012
comment
Неплохой модуль, но часовые пояса жестко закодированы, и он может ошибаться в дневное время. - person PSIAlt; 28.11.2012
comment
DateTime - это путь, но я думаю, что нам нужно уважать разницу в часовых поясах, давая from_epoch аргумент time_zone. - person darch; 28.11.2012
comment
кажется, работает хорошо, но не так просто понять, не глядя на документацию - интересно, что сказал @PSIAlt - person dgBP; 28.11.2012
comment
Как указано в документах DateTime-›from_epoch(), по умолчанию возвращаемый объект будет в часовом поясе UTC. Конечно, вы можете указать DateTime->from_epoch(epoch => 1354120744, time_zone => "local") - person creaktive; 28.11.2012
comment
Время эпохи @darch (временная метка unix) - это UTC, поэтому часовой пояс не имеет ничего общего. creaktive, у меня нет кода, он был на моей предыдущей работе. Но было что-то с математикой даты и времени - person PSIAlt; 28.11.2012

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

mktime(3) игнорирует поля wday, yday и isdst именно по этой причине. Вы можете безопасно настроить mday на 1, а затем снова вызвать POSIX::mktime(), чтобы вернуть его к значению эпохи.

my @t = localtime();
$t[0] = $t[1] = $t[2] = 0; # sec/min/hour
$t[3] = 1;                 # mday
my $epoch_start_of_month = mktime @t;

Или проще

my $epoch = mktime 0, 0, 0, 1, (localtime)[4,5];
person LeoNerd    schedule 29.11.2012