Как мога да получа началото на месеца във формата на епоха от произволно времево клеймо на епоха в 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 epoch time(unix timestamp) е 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