如何使用Perl确定计算机设置的当前时区?

9

我曾以为只需使用$ENV{TZ}就能轻松解决问题,但是TZ环境变量未设置,然而date命令仍然知道我在东部夏令时区,因此必须有其他方法确定时区(除了使用chomp(my $tz = qx/date +%Z/);的方式)。


只是额外的信息,在我的系统上,时区由文件/etc/localtime调节,libc似乎知道如何使用它。 - Kent Fredric
6个回答

15
use POSIX;
print strftime("%Z", localtime()), "\n";

我考虑过%Z,但我记得它在某些系统上无法正常工作。 - Chas. Owens
根据man strftime的说法,%Z是一个标准规范,应该在所有平台上得到支持。 - Igor Krivokon
1
我认为我是从POSIX文档中记住了这个:由于时区名称不标准,“Z”指定符非常不可移植。坚持使用数字指定符是最安全的路线。但我认为对于我的目的来说,这可能足够安全。 - Chas. Owens
2
可能更好的写法是 use POSIX qw(strftime); 这样可以节省约 5 毫秒并减少加载其他常量时名称冲突的风险。 - 700 Software

7
如果您需要比POSIX更加便携的解决方案(尽管可能会慢一些),您可以使用DateTime::TimeZone来实现此功能:
use DateTime::TimeZone;

print DateTime::TimeZone->new( name => 'local' )->name();

6
use POSIX;
localtime();
my ($std, $dst) = POSIX::tzname();

tzname()提供了访问POSIX全局变量tzname的方法,但是在第一次使用之前,您需要调用localtime()来设置它。


2
如果你只需要像+05:30(UTC+5.5/印度时间)这样的东西,你可以使用以下代码。
my @lt = localtime();
my @gt = gmtime();

my $hour_diff = $lt[2] - $gt[2];
my $min_diff  = $lt[1] - $gt[1];

my $total_diff = $hour_diff * 60 + $min_diff;
my $hour = int($total_diff / 60);
my $min = abs($total_diff - $hour * 60);

print sprintf("%+03d:%02d", $hour, $min);

这个答案受到了 Pavel 上面的答案的启发。

1

或许这样更快:

my @lt = localtime(12*60*60);
my @gt = gmtime(12*60*60);
$tz = @lt[2] - @gt[2];
$tz_ = sprintf("%+03d:00", $tz); # for +02:00 format

为了补充你的回答,你可以使用编辑按钮。 - ZygD

-1
使用:返回服务器与UTC的时区偏移量(以小时为单位)。 这基于上面的示例,并且可以处理夏令时。
 my $hour_seconds = 60 * 60;
 my $day_seconds = 24 * $hour_seconds;
 #what is today's time at 00:00
 my $right_now = time();
 my $days = $right_now / $day_seconds;
 my $years = $right_now / ($day_seconds * 365);
 my $days_rounded = sprintf("%d", $days);
 my $today_seconds_at_midnight = $days_rounded  * $day_seconds;
 
 my @lt = localtime($today_seconds_at_midnight + ($day_seconds / 2)); #must use noon today or we will get odd values
 my $tz = $lt[2] - 12; #calc timezome difference, includes DST
 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接